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 if (!preg_match('~\.php$~', $path)) {
70 dependency-injection.Tests.Fixtures.xml.xml_with_wrong_ext
71 # difference in nop statement
72 | framework-bundle.Resources.views.Form.choice_widget_options\.html
73 # difference due to INF
74 | yaml.Tests.InlineTest
81 $codeExtractor = function($file, $code) {
87 $version = $testType === 'PHP5' ? 'Php5' : 'Php7';
88 $fileFilter = function($path) {
89 return preg_match('~\.phpt$~', $path);
91 $codeExtractor = function($file, $code) {
95 | ext.skeleton.tests.00\d
96 # multibyte encoded files
97 | ext.mbstring.tests.zend_multibyte-01
98 | Zend.tests.multibyte.multibyte_encoding_001
99 | Zend.tests.multibyte.multibyte_encoding_004
100 | Zend.tests.multibyte.multibyte_encoding_005
101 # invalid code due to missing WS after opening tag
102 | tests.run-test.bug75042-3
103 # pretty print difference due to INF vs 1e1000
104 | ext.standard.tests.general_functions.bug27678
105 | tests.lang.bug24640
106 | Zend.tests.bug74947
107 # pretty print differences due to negative LNumbers
108 | Zend.tests.neg_num_string
109 | Zend.tests.bug72918
110 # pretty print difference due to nop statements
111 | ext.mbstring.tests.htmlent
112 | ext.standard.tests.file.fread_basic
113 # its too hard to emulate these on old PHP versions
114 | Zend.tests.flexible-heredoc-complex-test[1-4]
115 )\.phpt$~x', $file)) {
119 if (!preg_match('~--FILE--\s*(.*?)\n--[A-Z]+--~s', $code, $matches)) {
122 if (preg_match('~--EXPECT(?:F|REGEX)?--\s*(?:Parse|Fatal) error~', $code)) {
130 showHelp('Test type must be one of: PHP5, PHP7 or Symfony');
133 require_once __DIR__ . '/../vendor/autoload.php';
135 $lexer = new PhpParser\Lexer\Emulative(['usedAttributes' => [
136 'comments', 'startLine', 'endLine', 'startTokenPos', 'endTokenPos',
138 $parserName = 'PhpParser\Parser\\' . $version;
139 /** @var PhpParser\Parser $parser */
140 $parser = new $parserName($lexer);
141 $prettyPrinter = new PhpParser\PrettyPrinter\Standard;
142 $nodeDumper = new PhpParser\NodeDumper;
144 $cloningTraverser = new PhpParser\NodeTraverser;
145 $cloningTraverser->addVisitor(new PhpParser\NodeVisitor\CloningVisitor);
147 $parseFail = $fpppFail = $ppFail = $compareFail = $count = 0;
149 $readTime = $parseTime = $cloneTime = 0;
150 $fpppTime = $ppTime = $reparseTime = $compareTime = 0;
151 $totalStartTime = microtime(true);
153 foreach (new RecursiveIteratorIterator(
154 new RecursiveDirectoryIterator($dir),
155 RecursiveIteratorIterator::LEAVES_ONLY)
157 if (!$fileFilter($file)) {
161 $startTime = microtime(true);
162 $origCode = file_get_contents($file);
163 $readTime += microtime(true) - $startTime;
165 if (null === $origCode = $codeExtractor($file, $origCode)) {
174 echo substr(str_pad('Testing file ' . $count . ': ' . substr($file, strlen($dir)), 79), 0, 79), "\r";
178 $startTime = microtime(true);
179 $origStmts = $parser->parse($origCode);
180 $parseTime += microtime(true) - $startTime;
182 $origTokens = $lexer->getTokens();
184 $startTime = microtime(true);
185 $stmts = $cloningTraverser->traverse($origStmts);
186 $cloneTime += microtime(true) - $startTime;
188 $startTime = microtime(true);
189 $code = $prettyPrinter->printFormatPreserving($stmts, $origStmts, $origTokens);
190 $fpppTime += microtime(true) - $startTime;
192 if ($code !== $origCode) {
193 echo $file, ":\n Result of format-preserving pretty-print differs\n";
195 echo "FPPP output:\n=====\n$code\n=====\n\n";
201 $startTime = microtime(true);
202 $code = "<?php\n" . $prettyPrinter->prettyPrint($stmts);
203 $ppTime += microtime(true) - $startTime;
206 $startTime = microtime(true);
207 $ppStmts = $parser->parse($code);
208 $reparseTime += microtime(true) - $startTime;
210 $startTime = microtime(true);
211 $same = $nodeDumper->dump($stmts) == $nodeDumper->dump($ppStmts);
212 $compareTime += microtime(true) - $startTime;
215 echo $file, ":\n Result of initial parse and parse after pretty print differ\n";
217 echo "Pretty printer output:\n=====\n$code\n=====\n\n";
222 } catch (PhpParser\Error $e) {
223 echo $file, ":\n Parse of pretty print failed with message: {$e->getMessage()}\n";
225 echo "Pretty printer output:\n=====\n$code\n=====\n\n";
230 } catch (PhpParser\Error $e) {
231 echo $file, ":\n Parse failed with message: {$e->getMessage()}\n";
237 if (0 === $parseFail && 0 === $ppFail && 0 === $compareFail) {
239 echo "\n\n", 'All tests passed.', "\n";
242 echo "\n\n", '==========', "\n\n", 'There were: ', "\n";
243 if (0 !== $parseFail) {
244 echo ' ', $parseFail, ' parse failures.', "\n";
247 echo ' ', $ppFail, ' pretty print failures.', "\n";
249 if (0 !== $fpppFail) {
250 echo ' ', $fpppFail, ' FPPP failures.', "\n";
252 if (0 !== $compareFail) {
253 echo ' ', $compareFail, ' compare failures.', "\n";
258 'Tested files: ', $count, "\n",
260 'Reading files took: ', $readTime, "\n",
261 'Parsing took: ', $parseTime, "\n",
262 'Cloning took: ', $cloneTime, "\n",
263 'FPPP took: ', $fpppTime, "\n",
264 'Pretty printing took: ', $ppTime, "\n",
265 'Reparsing took: ', $reparseTime, "\n",
266 'Comparing took: ', $compareTime, "\n",
268 'Total time: ', microtime(true) - $totalStartTime, "\n",
269 'Maximum memory usage: ', memory_get_peak_usage(true), "\n";