Chris@0
|
1 <?php
|
Chris@0
|
2
|
Chris@0
|
3 error_reporting(E_ALL | E_STRICT);
|
Chris@0
|
4 ini_set('short_open_tag', false);
|
Chris@0
|
5
|
Chris@0
|
6 if ('cli' !== php_sapi_name()) {
|
Chris@0
|
7 die('This script is designed for running on the command line.');
|
Chris@0
|
8 }
|
Chris@0
|
9
|
Chris@0
|
10 function showHelp($error) {
|
Chris@0
|
11 die($error . "\n\n" .
|
Chris@0
|
12 <<<OUTPUT
|
Chris@0
|
13 This script has to be called with the following signature:
|
Chris@0
|
14
|
Chris@0
|
15 php run.php [--no-progress] testType pathToTestFiles
|
Chris@0
|
16
|
Chris@0
|
17 The test type must be one of: PHP5, PHP7 or Symfony.
|
Chris@0
|
18
|
Chris@0
|
19 The following options are available:
|
Chris@0
|
20
|
Chris@0
|
21 --no-progress Disables showing which file is currently tested.
|
Chris@0
|
22
|
Chris@0
|
23 OUTPUT
|
Chris@0
|
24 );
|
Chris@0
|
25 }
|
Chris@0
|
26
|
Chris@0
|
27 $options = array();
|
Chris@0
|
28 $arguments = array();
|
Chris@0
|
29
|
Chris@0
|
30 // remove script name from argv
|
Chris@0
|
31 array_shift($argv);
|
Chris@0
|
32
|
Chris@0
|
33 foreach ($argv as $arg) {
|
Chris@0
|
34 if ('-' === $arg[0]) {
|
Chris@0
|
35 $options[] = $arg;
|
Chris@0
|
36 } else {
|
Chris@0
|
37 $arguments[] = $arg;
|
Chris@0
|
38 }
|
Chris@0
|
39 }
|
Chris@0
|
40
|
Chris@0
|
41 if (count($arguments) !== 2) {
|
Chris@0
|
42 showHelp('Too little arguments passed!');
|
Chris@0
|
43 }
|
Chris@0
|
44
|
Chris@0
|
45 $showProgress = true;
|
Chris@0
|
46 $verbose = false;
|
Chris@0
|
47 foreach ($options as $option) {
|
Chris@0
|
48 if ($option === '--no-progress') {
|
Chris@0
|
49 $showProgress = false;
|
Chris@0
|
50 } elseif ($option === '--verbose') {
|
Chris@0
|
51 $verbose = true;
|
Chris@0
|
52 } else {
|
Chris@0
|
53 showHelp('Invalid option passed!');
|
Chris@0
|
54 }
|
Chris@0
|
55 }
|
Chris@0
|
56
|
Chris@0
|
57 $testType = $arguments[0];
|
Chris@0
|
58 $dir = $arguments[1];
|
Chris@0
|
59
|
Chris@0
|
60 switch ($testType) {
|
Chris@0
|
61 case 'Symfony':
|
Chris@17
|
62 $version = 'Php7';
|
Chris@0
|
63 $fileFilter = function($path) {
|
Chris@17
|
64 if (!preg_match('~\.php$~', $path)) {
|
Chris@17
|
65 return false;
|
Chris@17
|
66 }
|
Chris@17
|
67
|
Chris@17
|
68 if (preg_match('~(?:
|
Chris@17
|
69 # invalid php code
|
Chris@17
|
70 dependency-injection.Tests.Fixtures.xml.xml_with_wrong_ext
|
Chris@17
|
71 # difference in nop statement
|
Chris@17
|
72 | framework-bundle.Resources.views.Form.choice_widget_options\.html
|
Chris@17
|
73 # difference due to INF
|
Chris@17
|
74 | yaml.Tests.InlineTest
|
Chris@17
|
75 )\.php$~x', $path)) {
|
Chris@17
|
76 return false;
|
Chris@17
|
77 }
|
Chris@17
|
78
|
Chris@17
|
79 return true;
|
Chris@0
|
80 };
|
Chris@0
|
81 $codeExtractor = function($file, $code) {
|
Chris@0
|
82 return $code;
|
Chris@0
|
83 };
|
Chris@0
|
84 break;
|
Chris@0
|
85 case 'PHP5':
|
Chris@0
|
86 case 'PHP7':
|
Chris@0
|
87 $version = $testType === 'PHP5' ? 'Php5' : 'Php7';
|
Chris@0
|
88 $fileFilter = function($path) {
|
Chris@0
|
89 return preg_match('~\.phpt$~', $path);
|
Chris@0
|
90 };
|
Chris@0
|
91 $codeExtractor = function($file, $code) {
|
Chris@0
|
92 if (preg_match('~(?:
|
Chris@0
|
93 # skeleton files
|
Chris@0
|
94 ext.gmp.tests.001
|
Chris@17
|
95 | ext.skeleton.tests.00\d
|
Chris@0
|
96 # multibyte encoded files
|
Chris@0
|
97 | ext.mbstring.tests.zend_multibyte-01
|
Chris@0
|
98 | Zend.tests.multibyte.multibyte_encoding_001
|
Chris@0
|
99 | Zend.tests.multibyte.multibyte_encoding_004
|
Chris@0
|
100 | Zend.tests.multibyte.multibyte_encoding_005
|
Chris@17
|
101 # invalid code due to missing WS after opening tag
|
Chris@17
|
102 | tests.run-test.bug75042-3
|
Chris@0
|
103 # pretty print difference due to INF vs 1e1000
|
Chris@0
|
104 | ext.standard.tests.general_functions.bug27678
|
Chris@0
|
105 | tests.lang.bug24640
|
Chris@17
|
106 | Zend.tests.bug74947
|
Chris@0
|
107 # pretty print differences due to negative LNumbers
|
Chris@0
|
108 | Zend.tests.neg_num_string
|
Chris@0
|
109 | Zend.tests.bug72918
|
Chris@0
|
110 # pretty print difference due to nop statements
|
Chris@0
|
111 | ext.mbstring.tests.htmlent
|
Chris@0
|
112 | ext.standard.tests.file.fread_basic
|
Chris@17
|
113 # its too hard to emulate these on old PHP versions
|
Chris@17
|
114 | Zend.tests.flexible-heredoc-complex-test[1-4]
|
Chris@0
|
115 )\.phpt$~x', $file)) {
|
Chris@0
|
116 return null;
|
Chris@0
|
117 }
|
Chris@0
|
118
|
Chris@17
|
119 if (!preg_match('~--FILE--\s*(.*?)\n--[A-Z]+--~s', $code, $matches)) {
|
Chris@0
|
120 return null;
|
Chris@0
|
121 }
|
Chris@0
|
122 if (preg_match('~--EXPECT(?:F|REGEX)?--\s*(?:Parse|Fatal) error~', $code)) {
|
Chris@0
|
123 return null;
|
Chris@0
|
124 }
|
Chris@0
|
125
|
Chris@0
|
126 return $matches[1];
|
Chris@0
|
127 };
|
Chris@0
|
128 break;
|
Chris@0
|
129 default:
|
Chris@0
|
130 showHelp('Test type must be one of: PHP5, PHP7 or Symfony');
|
Chris@0
|
131 }
|
Chris@0
|
132
|
Chris@13
|
133 require_once __DIR__ . '/../vendor/autoload.php';
|
Chris@0
|
134
|
Chris@13
|
135 $lexer = new PhpParser\Lexer\Emulative(['usedAttributes' => [
|
Chris@13
|
136 'comments', 'startLine', 'endLine', 'startTokenPos', 'endTokenPos',
|
Chris@13
|
137 ]]);
|
Chris@13
|
138 $parserName = 'PhpParser\Parser\\' . $version;
|
Chris@13
|
139 /** @var PhpParser\Parser $parser */
|
Chris@13
|
140 $parser = new $parserName($lexer);
|
Chris@0
|
141 $prettyPrinter = new PhpParser\PrettyPrinter\Standard;
|
Chris@13
|
142 $nodeDumper = new PhpParser\NodeDumper;
|
Chris@0
|
143
|
Chris@13
|
144 $cloningTraverser = new PhpParser\NodeTraverser;
|
Chris@13
|
145 $cloningTraverser->addVisitor(new PhpParser\NodeVisitor\CloningVisitor);
|
Chris@0
|
146
|
Chris@13
|
147 $parseFail = $fpppFail = $ppFail = $compareFail = $count = 0;
|
Chris@13
|
148
|
Chris@13
|
149 $readTime = $parseTime = $cloneTime = 0;
|
Chris@13
|
150 $fpppTime = $ppTime = $reparseTime = $compareTime = 0;
|
Chris@0
|
151 $totalStartTime = microtime(true);
|
Chris@0
|
152
|
Chris@0
|
153 foreach (new RecursiveIteratorIterator(
|
Chris@0
|
154 new RecursiveDirectoryIterator($dir),
|
Chris@0
|
155 RecursiveIteratorIterator::LEAVES_ONLY)
|
Chris@0
|
156 as $file) {
|
Chris@0
|
157 if (!$fileFilter($file)) {
|
Chris@0
|
158 continue;
|
Chris@0
|
159 }
|
Chris@0
|
160
|
Chris@0
|
161 $startTime = microtime(true);
|
Chris@13
|
162 $origCode = file_get_contents($file);
|
Chris@0
|
163 $readTime += microtime(true) - $startTime;
|
Chris@0
|
164
|
Chris@13
|
165 if (null === $origCode = $codeExtractor($file, $origCode)) {
|
Chris@0
|
166 continue;
|
Chris@0
|
167 }
|
Chris@0
|
168
|
Chris@0
|
169 set_time_limit(10);
|
Chris@0
|
170
|
Chris@0
|
171 ++$count;
|
Chris@0
|
172
|
Chris@0
|
173 if ($showProgress) {
|
Chris@0
|
174 echo substr(str_pad('Testing file ' . $count . ': ' . substr($file, strlen($dir)), 79), 0, 79), "\r";
|
Chris@0
|
175 }
|
Chris@0
|
176
|
Chris@0
|
177 try {
|
Chris@0
|
178 $startTime = microtime(true);
|
Chris@13
|
179 $origStmts = $parser->parse($origCode);
|
Chris@0
|
180 $parseTime += microtime(true) - $startTime;
|
Chris@0
|
181
|
Chris@13
|
182 $origTokens = $lexer->getTokens();
|
Chris@13
|
183
|
Chris@0
|
184 $startTime = microtime(true);
|
Chris@13
|
185 $stmts = $cloningTraverser->traverse($origStmts);
|
Chris@13
|
186 $cloneTime += microtime(true) - $startTime;
|
Chris@13
|
187
|
Chris@13
|
188 $startTime = microtime(true);
|
Chris@13
|
189 $code = $prettyPrinter->printFormatPreserving($stmts, $origStmts, $origTokens);
|
Chris@13
|
190 $fpppTime += microtime(true) - $startTime;
|
Chris@13
|
191
|
Chris@13
|
192 if ($code !== $origCode) {
|
Chris@13
|
193 echo $file, ":\n Result of format-preserving pretty-print differs\n";
|
Chris@13
|
194 if ($verbose) {
|
Chris@13
|
195 echo "FPPP output:\n=====\n$code\n=====\n\n";
|
Chris@13
|
196 }
|
Chris@13
|
197
|
Chris@13
|
198 ++$fpppFail;
|
Chris@13
|
199 }
|
Chris@13
|
200
|
Chris@13
|
201 $startTime = microtime(true);
|
Chris@13
|
202 $code = "<?php\n" . $prettyPrinter->prettyPrint($stmts);
|
Chris@0
|
203 $ppTime += microtime(true) - $startTime;
|
Chris@0
|
204
|
Chris@0
|
205 try {
|
Chris@0
|
206 $startTime = microtime(true);
|
Chris@0
|
207 $ppStmts = $parser->parse($code);
|
Chris@0
|
208 $reparseTime += microtime(true) - $startTime;
|
Chris@0
|
209
|
Chris@0
|
210 $startTime = microtime(true);
|
Chris@0
|
211 $same = $nodeDumper->dump($stmts) == $nodeDumper->dump($ppStmts);
|
Chris@0
|
212 $compareTime += microtime(true) - $startTime;
|
Chris@0
|
213
|
Chris@0
|
214 if (!$same) {
|
Chris@0
|
215 echo $file, ":\n Result of initial parse and parse after pretty print differ\n";
|
Chris@0
|
216 if ($verbose) {
|
Chris@0
|
217 echo "Pretty printer output:\n=====\n$code\n=====\n\n";
|
Chris@0
|
218 }
|
Chris@0
|
219
|
Chris@0
|
220 ++$compareFail;
|
Chris@0
|
221 }
|
Chris@0
|
222 } catch (PhpParser\Error $e) {
|
Chris@0
|
223 echo $file, ":\n Parse of pretty print failed with message: {$e->getMessage()}\n";
|
Chris@0
|
224 if ($verbose) {
|
Chris@0
|
225 echo "Pretty printer output:\n=====\n$code\n=====\n\n";
|
Chris@0
|
226 }
|
Chris@0
|
227
|
Chris@0
|
228 ++$ppFail;
|
Chris@0
|
229 }
|
Chris@0
|
230 } catch (PhpParser\Error $e) {
|
Chris@0
|
231 echo $file, ":\n Parse failed with message: {$e->getMessage()}\n";
|
Chris@0
|
232
|
Chris@0
|
233 ++$parseFail;
|
Chris@0
|
234 }
|
Chris@0
|
235 }
|
Chris@0
|
236
|
Chris@0
|
237 if (0 === $parseFail && 0 === $ppFail && 0 === $compareFail) {
|
Chris@0
|
238 $exit = 0;
|
Chris@0
|
239 echo "\n\n", 'All tests passed.', "\n";
|
Chris@0
|
240 } else {
|
Chris@0
|
241 $exit = 1;
|
Chris@0
|
242 echo "\n\n", '==========', "\n\n", 'There were: ', "\n";
|
Chris@0
|
243 if (0 !== $parseFail) {
|
Chris@0
|
244 echo ' ', $parseFail, ' parse failures.', "\n";
|
Chris@0
|
245 }
|
Chris@0
|
246 if (0 !== $ppFail) {
|
Chris@0
|
247 echo ' ', $ppFail, ' pretty print failures.', "\n";
|
Chris@0
|
248 }
|
Chris@13
|
249 if (0 !== $fpppFail) {
|
Chris@13
|
250 echo ' ', $fpppFail, ' FPPP failures.', "\n";
|
Chris@13
|
251 }
|
Chris@0
|
252 if (0 !== $compareFail) {
|
Chris@0
|
253 echo ' ', $compareFail, ' compare failures.', "\n";
|
Chris@0
|
254 }
|
Chris@0
|
255 }
|
Chris@0
|
256
|
Chris@0
|
257 echo "\n",
|
Chris@0
|
258 'Tested files: ', $count, "\n",
|
Chris@0
|
259 "\n",
|
Chris@0
|
260 'Reading files took: ', $readTime, "\n",
|
Chris@0
|
261 'Parsing took: ', $parseTime, "\n",
|
Chris@13
|
262 'Cloning took: ', $cloneTime, "\n",
|
Chris@13
|
263 'FPPP took: ', $fpppTime, "\n",
|
Chris@0
|
264 'Pretty printing took: ', $ppTime, "\n",
|
Chris@0
|
265 'Reparsing took: ', $reparseTime, "\n",
|
Chris@0
|
266 'Comparing took: ', $compareTime, "\n",
|
Chris@0
|
267 "\n",
|
Chris@0
|
268 'Total time: ', microtime(true) - $totalStartTime, "\n",
|
Chris@0
|
269 'Maximum memory usage: ', memory_get_peak_usage(true), "\n";
|
Chris@0
|
270
|
Chris@0
|
271 exit($exit);
|