/wp-content/plugins/versionpress/vendor/udan11/sql-parser/tools/TestGenerator.php

https://gitlab.com/vanafroo/landingpage · PHP · 223 lines · 101 code · 28 blank · 94 comment · 19 complexity · 384df23430841edc768f1db3c3e30212 MD5 · raw file

  1. <?php
  2. namespace SqlParser\Tools;
  3. require_once '../vendor/autoload.php';
  4. use SqlParser\Lexer;
  5. use SqlParser\Parser;
  6. /**
  7. * Used for test generation.
  8. *
  9. * @category Tests
  10. * @package SqlParser
  11. * @subpackage Tools
  12. * @author Dan Ungureanu <udan1107@gmail.com>
  13. * @license http://opensource.org/licenses/GPL-2.0 GNU Public License
  14. */
  15. class TestGenerator
  16. {
  17. /**
  18. * Generates a test's data.
  19. *
  20. * @param string $query The query to be analyzed.
  21. * @param string $type Test's type (may be `lexer` or `parser`).
  22. *
  23. * @return array
  24. */
  25. public static function generate($query, $type = 'parser')
  26. {
  27. /**
  28. * Lexer used for tokenizing the query.
  29. *
  30. * @var Lexer $lexer
  31. */
  32. $lexer = new Lexer($query);
  33. /**
  34. * Parsed used for analyzing the query.
  35. * A new instance of parser is generated only if the test requires.
  36. *
  37. * @var Parser $parser
  38. */
  39. $parser = ($type === 'parser') ? new Parser($lexer->list) : null;
  40. /**
  41. * Lexer's errors.
  42. *
  43. * @var array $lexerErrors
  44. */
  45. $lexerErrors = array();
  46. /**
  47. * Parser's errors.
  48. *
  49. * @var array $parserErrors
  50. */
  51. $parserErrors = array();
  52. // Both the lexer and the parser construct exception for errors.
  53. // Usually, exceptions contain a full stack trace and other details that
  54. // are not required.
  55. // The code below extracts only the relevant information.
  56. // Extracting lexer's errors.
  57. if (!empty($lexer->errors)) {
  58. foreach ($lexer->errors as $err) {
  59. $lexerErrors[] = array($err->getMessage(), $err->ch, $err->pos, $err->getCode());
  60. }
  61. $lexer->errors = array();
  62. }
  63. // Extracting parser's errors.
  64. if (!empty($parser->errors)) {
  65. foreach ($parser->errors as $err) {
  66. $parserErrors[] = array($err->getMessage(), $err->token, $err->getCode());
  67. }
  68. $parser->errors = array();
  69. }
  70. return array(
  71. 'query' => $query,
  72. 'lexer' => $lexer,
  73. 'parser' => $parser,
  74. 'errors' => array(
  75. 'lexer' => $lexerErrors,
  76. 'parser' => $parserErrors
  77. ),
  78. );
  79. }
  80. /**
  81. * Builds a test.
  82. *
  83. * Reads the input file, generates the data and writes it back.
  84. *
  85. * @param string $type The type of this test.
  86. * @param string $input The input file.
  87. * @param string $output The output file.
  88. * @param string $debug The debug file.
  89. *
  90. * @return void
  91. */
  92. public static function build($type, $input, $output, $debug = null)
  93. {
  94. // Support query types: `lexer` / `parser`.
  95. if (!in_array($type, array('lexer', 'parser'))) {
  96. throw new \Exception('Unknown test type (expected `lexer` or `parser`).');
  97. }
  98. /**
  99. * The query that is used to generate the test.
  100. *
  101. * @var string $query
  102. */
  103. $query = file_get_contents($input);
  104. // There is no point in generating a test without a query.
  105. if (empty($query)) {
  106. throw new \Exception('No input query specified.');
  107. }
  108. $test = static::generate($query, $type);
  109. // Writing test's data.
  110. file_put_contents($output, serialize($test));
  111. // Dumping test's data in human readable format too (if required).
  112. if (!empty($debug)) {
  113. file_put_contents($debug, print_r($test, true));
  114. }
  115. }
  116. /**
  117. * Generates recursively all tests preserving the directory structure.
  118. *
  119. * @param string $input The input directory.
  120. * @param string $output The output directory.
  121. *
  122. * @return void
  123. */
  124. public static function buildAll($input, $output, $debug = null)
  125. {
  126. $files = scandir($input);
  127. foreach ($files as $file) {
  128. // Skipping current and parent directories.
  129. if (($file === '.') || ($file === '..')) {
  130. continue;
  131. }
  132. // Appending the filename to directories.
  133. $inputFile = $input . '/' . $file;
  134. $outputFile = $output . '/' . $file;
  135. $debugFile = ($debug !== null) ? $debug . '/' . $file : null;
  136. if (is_dir($inputFile)) {
  137. // Creating required directories to maintain the structure.
  138. // Ignoring errors if the folder structure exists already.
  139. if (!is_dir($outputFile)) {
  140. mkdir($outputFile);
  141. }
  142. if (($debug !== null) && (!is_dir($debugFile))) {
  143. mkdir($debugFile);
  144. }
  145. // Generating tests recursively.
  146. static::buildAll($inputFile, $outputFile, $debugFile);
  147. } elseif (substr($inputFile, -3) === '.in') {
  148. // Generating file names by replacing `.in` with `.out` and
  149. // `.debug`.
  150. $outputFile = substr($outputFile, 0, -3) . '.out';
  151. if ($debug !== null) {
  152. $debugFile = substr($debugFile, 0, -3) . '.debug';
  153. }
  154. // Building the test.
  155. if (!file_exists($outputFile)) {
  156. print("Building test for {$inputFile}...\n");
  157. static::build(
  158. strpos($inputFile, 'lex') !== false ? 'lexer' : 'parser',
  159. $inputFile,
  160. $outputFile,
  161. $debugFile
  162. );
  163. } else {
  164. print("Test for {$inputFile} already built!\n");
  165. }
  166. }
  167. }
  168. }
  169. }
  170. // Test generator.
  171. //
  172. // Example of usage:
  173. //
  174. // php TestGenerator.php ../tests/data ../tests/data
  175. //
  176. // Input data must be in the `../tests/data` folder.
  177. // The output will be generated in the same `../tests/data` folder.
  178. //
  179. if (count($argv) >= 3) {
  180. // Extracting directories' name from command line and trimming unnecessary
  181. // slashes at the end.
  182. $input = rtrim($argv[1], '/');
  183. $output = rtrim($argv[2], '/');
  184. $debug = empty($argv[3]) ? null : rtrim($argv[3], '/');
  185. // Checking if all directories are valid.
  186. if (!is_dir($input)) {
  187. throw new \Exception('The input directory does not exist.');
  188. } elseif (!is_dir($output)) {
  189. throw new \Exception('The output directory does not exist.');
  190. } elseif (($debug !== null) && (!is_dir($debug))) {
  191. throw new \Exception('The debug directory does not exist.');
  192. }
  193. // Finally, building the tests.
  194. TestGenerator::buildAll($input, $output, $debug);
  195. }