3 error_reporting(E_ALL | E_STRICT);
4 ini_set('short_open_tag', false);
6 if ('cli' !== php_sapi_name()) {
7 die('This script is designed for running on the command line.');
10 function showHelp($error) {
13 This script has to be called with the following signature:
15 php run.php [--no-progress] testType pathToTestFiles
17 The test type must be one of: PHP5, PHP7 or Symfony.
19 The following options are available:
21 --no-progress Disables showing which file is currently tested.
30 // remove script name from argv
33 foreach ($argv as $arg) {
34 if ('-' === $arg[0]) {
41 if (count($arguments) !== 2) {
42 showHelp('Too little arguments passed!');
47 foreach ($options as $option) {
48 if ($option === '--no-progress') {
49 $showProgress = false;
50 } elseif ($option === '--verbose') {
53 showHelp('Invalid option passed!');
57 $testType = $arguments[0];
63 $fileFilter = function($path) {
64 return preg_match('~\.php(?:\.cache)?$~', $path) && false === strpos($path, 'skeleton');
66 $codeExtractor = function($file, $code) {
72 $version = $testType === 'PHP5' ? 'Php5' : 'Php7';
73 $fileFilter = function($path) {
74 return preg_match('~\.phpt$~', $path);
76 $codeExtractor = function($file, $code) {
80 | ext.skeleton.tests.001
81 # multibyte encoded files
82 | ext.mbstring.tests.zend_multibyte-01
83 | Zend.tests.multibyte.multibyte_encoding_001
84 | Zend.tests.multibyte.multibyte_encoding_004
85 | Zend.tests.multibyte.multibyte_encoding_005
86 # pretty print difference due to INF vs 1e1000
87 | ext.standard.tests.general_functions.bug27678
89 # pretty print differences due to negative LNumbers
90 | Zend.tests.neg_num_string
92 # pretty print difference due to nop statements
93 | ext.mbstring.tests.htmlent
94 | ext.standard.tests.file.fread_basic
95 )\.phpt$~x', $file)) {
99 if (!preg_match('~--FILE--\s*(.*?)--[A-Z]+--~s', $code, $matches)) {
102 if (preg_match('~--EXPECT(?:F|REGEX)?--\s*(?:Parse|Fatal) error~', $code)) {
110 showHelp('Test type must be one of: PHP5, PHP7 or Symfony');
113 require_once __DIR__ . '/../vendor/autoload.php';
115 $lexer = new PhpParser\Lexer\Emulative(['usedAttributes' => [
116 'comments', 'startLine', 'endLine', 'startTokenPos', 'endTokenPos',
118 $parserName = 'PhpParser\Parser\\' . $version;
119 /** @var PhpParser\Parser $parser */
120 $parser = new $parserName($lexer);
121 $prettyPrinter = new PhpParser\PrettyPrinter\Standard;
122 $nodeDumper = new PhpParser\NodeDumper;
124 $cloningTraverser = new PhpParser\NodeTraverser;
125 $cloningTraverser->addVisitor(new PhpParser\NodeVisitor\CloningVisitor);
127 $parseFail = $fpppFail = $ppFail = $compareFail = $count = 0;
129 $readTime = $parseTime = $cloneTime = 0;
130 $fpppTime = $ppTime = $reparseTime = $compareTime = 0;
131 $totalStartTime = microtime(true);
133 foreach (new RecursiveIteratorIterator(
134 new RecursiveDirectoryIterator($dir),
135 RecursiveIteratorIterator::LEAVES_ONLY)
137 if (!$fileFilter($file)) {
141 $startTime = microtime(true);
142 $origCode = file_get_contents($file);
143 $readTime += microtime(true) - $startTime;
145 if (null === $origCode = $codeExtractor($file, $origCode)) {
154 echo substr(str_pad('Testing file ' . $count . ': ' . substr($file, strlen($dir)), 79), 0, 79), "\r";
158 $startTime = microtime(true);
159 $origStmts = $parser->parse($origCode);
160 $parseTime += microtime(true) - $startTime;
162 $origTokens = $lexer->getTokens();
164 $startTime = microtime(true);
165 $stmts = $cloningTraverser->traverse($origStmts);
166 $cloneTime += microtime(true) - $startTime;
168 $startTime = microtime(true);
169 $code = $prettyPrinter->printFormatPreserving($stmts, $origStmts, $origTokens);
170 $fpppTime += microtime(true) - $startTime;
172 if ($code !== $origCode) {
173 echo $file, ":\n Result of format-preserving pretty-print differs\n";
175 echo "FPPP output:\n=====\n$code\n=====\n\n";
181 $startTime = microtime(true);
182 $code = "<?php\n" . $prettyPrinter->prettyPrint($stmts);
183 $ppTime += microtime(true) - $startTime;
186 $startTime = microtime(true);
187 $ppStmts = $parser->parse($code);
188 $reparseTime += microtime(true) - $startTime;
190 $startTime = microtime(true);
191 $same = $nodeDumper->dump($stmts) == $nodeDumper->dump($ppStmts);
192 $compareTime += microtime(true) - $startTime;
195 echo $file, ":\n Result of initial parse and parse after pretty print differ\n";
197 echo "Pretty printer output:\n=====\n$code\n=====\n\n";
202 } catch (PhpParser\Error $e) {
203 echo $file, ":\n Parse of pretty print failed with message: {$e->getMessage()}\n";
205 echo "Pretty printer output:\n=====\n$code\n=====\n\n";
210 } catch (PhpParser\Error $e) {
211 echo $file, ":\n Parse failed with message: {$e->getMessage()}\n";
217 if (0 === $parseFail && 0 === $ppFail && 0 === $compareFail) {
219 echo "\n\n", 'All tests passed.', "\n";
222 echo "\n\n", '==========', "\n\n", 'There were: ', "\n";
223 if (0 !== $parseFail) {
224 echo ' ', $parseFail, ' parse failures.', "\n";
227 echo ' ', $ppFail, ' pretty print failures.', "\n";
229 if (0 !== $fpppFail) {
230 echo ' ', $fpppFail, ' FPPP failures.', "\n";
232 if (0 !== $compareFail) {
233 echo ' ', $compareFail, ' compare failures.', "\n";
238 'Tested files: ', $count, "\n",
240 'Reading files took: ', $readTime, "\n",
241 'Parsing took: ', $parseTime, "\n",
242 'Cloning took: ', $cloneTime, "\n",
243 'FPPP took: ', $fpppTime, "\n",
244 'Pretty printing took: ', $ppTime, "\n",
245 'Reparsing took: ', $reparseTime, "\n",
246 'Comparing took: ', $compareTime, "\n",
248 'Total time: ', microtime(true) - $totalStartTime, "\n",
249 'Maximum memory usage: ', memory_get_peak_usage(true), "\n";