Viewing file: TestGenerator.php (6.31 KB) -rw-r--r-- Select action/file-type: (+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
<?php
declare(strict_types=1);
namespace PhpMyAdmin\SqlParser\Tools;
use Exception; use PhpMyAdmin\SqlParser\Context; use PhpMyAdmin\SqlParser\Lexer; use PhpMyAdmin\SqlParser\Parser; use function file_exists; use function file_get_contents; use function file_put_contents; use function in_array; use function is_dir; use function mkdir; use function print_r; use function scandir; use function serialize; use function sprintf; use function strpos; use function substr;
/** * Used for test generation. */ class TestGenerator { /** * Generates a test's data. * * @param string $query the query to be analyzed * @param string $type test's type (may be `lexer` or `parser`) * * @return array */ public static function generate($query, $type = 'parser') { /** * Lexer used for tokenizing the query. * * @var Lexer */ $lexer = new Lexer($query);
/** * Parsed used for analyzing the query. * A new instance of parser is generated only if the test requires. * * @var Parser */ $parser = $type === 'parser' ? new Parser($lexer->list) : null;
/** * Lexer's errors. * * @var array */ $lexerErrors = [];
/** * Parser's errors. * * @var array */ $parserErrors = [];
// Both the lexer and the parser construct exception for errors. // Usually, exceptions contain a full stack trace and other details that // are not required. // The code below extracts only the relevant information.
// Extracting lexer's errors. if (! empty($lexer->errors)) { foreach ($lexer->errors as $err) { $lexerErrors[] = [ $err->getMessage(), $err->ch, $err->pos, $err->getCode(), ]; }
$lexer->errors = []; }
// Extracting parser's errors. if (! empty($parser->errors)) { foreach ($parser->errors as $err) { $parserErrors[] = [ $err->getMessage(), $err->token, $err->getCode(), ]; }
$parser->errors = []; }
return [ 'query' => $query, 'lexer' => $lexer, 'parser' => $parser, 'errors' => [ 'lexer' => $lexerErrors, 'parser' => $parserErrors, ], ]; }
/** * Builds a test. * * Reads the input file, generates the data and writes it back. * * @param string $type the type of this test * @param string $input the input file * @param string $output the output file * @param string $debug the debug file * @param bool $ansi activate quotes ANSI mode */ public static function build($type, $input, $output, $debug = null, $ansi = false) { // Support query types: `lexer` / `parser`. if (! in_array($type, ['lexer', 'parser'])) { throw new Exception('Unknown test type (expected `lexer` or `parser`).'); }
/** * The query that is used to generate the test. * * @var string */ $query = file_get_contents($input);
// There is no point in generating a test without a query. if (empty($query)) { throw new Exception('No input query specified.'); }
if ($ansi === true) { // set ANSI_QUOTES for ansi tests Context::setMode('ANSI_QUOTES'); }
$test = static::generate($query, $type);
// unset mode, reset to default every time, to be sure Context::setMode();
// Writing test's data. file_put_contents($output, serialize($test));
// Dumping test's data in human readable format too (if required). if (! empty($debug)) { file_put_contents($debug, print_r($test, true)); } }
/** * Generates recursively all tests preserving the directory structure. * * @param string $input the input directory * @param string $output the output directory * @param mixed|null $debug */ public static function buildAll($input, $output, $debug = null) { $files = scandir($input);
foreach ($files as $file) { // Skipping current and parent directories. if (($file === '.') || ($file === '..')) { continue; }
// Appending the filename to directories. $inputFile = $input . '/' . $file; $outputFile = $output . '/' . $file; $debugFile = $debug !== null ? $debug . '/' . $file : null;
if (is_dir($inputFile)) { // Creating required directories to maintain the structure. // Ignoring errors if the folder structure exists already. if (! is_dir($outputFile)) { mkdir($outputFile); }
if (($debug !== null) && (! is_dir($debugFile))) { mkdir($debugFile); }
// Generating tests recursively. static::buildAll($inputFile, $outputFile, $debugFile); } elseif (substr($inputFile, -3) === '.in') { // Generating file names by replacing `.in` with `.out` and // `.debug`. $outputFile = substr($outputFile, 0, -3) . '.out'; if ($debug !== null) { $debugFile = substr($debugFile, 0, -3) . '.debug'; }
// Building the test. if (! file_exists($outputFile)) { sprintf("Building test for %s...\n", $inputFile); static::build( strpos($inputFile, 'lex') !== false ? 'lexer' : 'parser', $inputFile, $outputFile, $debugFile, strpos($inputFile, 'ansi') !== false ); } else { sprintf("Test for %s already built!\n", $inputFile); } } } } }
|