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