ComplianceTest.php 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. <?php
  2. namespace JmesPath\Tests;
  3. use JmesPath\AstRuntime;
  4. use JmesPath\CompilerRuntime;
  5. use JmesPath\SyntaxErrorException;
  6. use PHPUnit\Framework\TestCase;
  7. class ComplianceTest extends TestCase
  8. {
  9. private static $path;
  10. public static function setUpBeforeClass()
  11. {
  12. self::$path = __DIR__ . '/../../compiled';
  13. array_map('unlink', glob(self::$path . '/jmespath_*.php'));
  14. }
  15. public static function tearDownAfterClass()
  16. {
  17. array_map('unlink', glob(self::$path . '/jmespath_*.php'));
  18. }
  19. /**
  20. * @dataProvider complianceProvider
  21. */
  22. public function testPassesCompliance(
  23. $data,
  24. $expression,
  25. $result,
  26. $error,
  27. $file,
  28. $suite,
  29. $case,
  30. $compiled,
  31. $asAssoc
  32. ) {
  33. $evalResult = null;
  34. $failed = false;
  35. $failureMsg = '';
  36. $failure = '';
  37. $compiledStr = '';
  38. try {
  39. if ($compiled) {
  40. $compiledStr = \JmesPath\Env::COMPILE_DIR . '=on ';
  41. $runtime = new CompilerRuntime(self::$path);
  42. } else {
  43. $runtime = new AstRuntime();
  44. }
  45. $evalResult = $runtime($expression, $data);
  46. } catch (\Exception $e) {
  47. $failed = $e instanceof SyntaxErrorException ? 'syntax' : 'runtime';
  48. $failureMsg = sprintf(
  49. '%s (%s line %d)',
  50. $e->getMessage(),
  51. $e->getFile(),
  52. $e->getLine()
  53. );
  54. }
  55. $file = __DIR__ . '/compliance/' . $file . '.json';
  56. $failure .= "\n{$compiledStr}php bin/jp.php --file {$file} --suite {$suite} --case {$case}\n\n"
  57. . "Result: " . $this->prettyJson($evalResult) . "\n\n"
  58. . "Expected: " . $this->prettyJson($result) . "\n\n";
  59. $failure .= 'Associative? ' . var_export($asAssoc, true) . "\n\n";
  60. if (!$error && $failed) {
  61. $this->fail("Should not have failed\n{$failure}=> {$failed} {$failureMsg}");
  62. } elseif ($error && !$failed) {
  63. $this->fail("Should have failed\n{$failure}");
  64. }
  65. $this->assertEquals(
  66. $this->convertAssoc($result),
  67. $this->convertAssoc($evalResult),
  68. $failure
  69. );
  70. }
  71. public function complianceProvider()
  72. {
  73. $cases = [];
  74. $files = array_map(function ($f) {
  75. return basename($f, '.json');
  76. }, glob(__DIR__ . '/compliance/*.json'));
  77. foreach ($files as $name) {
  78. $contents = file_get_contents(__DIR__ . "/compliance/{$name}.json");
  79. foreach ([true, false] as $asAssoc) {
  80. $json = json_decode($contents, true);
  81. $jsonObj = json_decode($contents);
  82. foreach ($json as $suiteNumber => $suite) {
  83. $given = $asAssoc ? $suite['given'] : $jsonObj[$suiteNumber]->given;
  84. foreach ($suite['cases'] as $caseNumber => $case) {
  85. $caseData = [
  86. $given,
  87. $case['expression'],
  88. isset($case['result']) ? $case['result'] : null,
  89. isset($case['error']) ? $case['error'] : false,
  90. $name,
  91. $suiteNumber,
  92. $caseNumber,
  93. false,
  94. $asAssoc
  95. ];
  96. $cases[] = $caseData;
  97. $caseData[7] = true;
  98. $cases[] = $caseData;
  99. }
  100. }
  101. }
  102. }
  103. return $cases;
  104. }
  105. private function convertAssoc($data)
  106. {
  107. if ($data instanceof \stdClass) {
  108. return $this->convertAssoc((array) $data);
  109. } elseif (is_array($data)) {
  110. return array_map([$this, 'convertAssoc'], $data);
  111. } else {
  112. return $data;
  113. }
  114. }
  115. private function prettyJson($json)
  116. {
  117. if (defined('JSON_PRETTY_PRINT')) {
  118. return json_encode($json, JSON_PRETTY_PRINT);
  119. }
  120. return json_encode($json);
  121. }
  122. }