|
1
|
|
|
<?php |
|
2
|
|
|
/* |
|
3
|
|
|
* This file is part of PHPUnit. |
|
4
|
|
|
* |
|
5
|
|
|
* (c) Sebastian Bergmann <[email protected]> |
|
6
|
|
|
* |
|
7
|
|
|
* For the full copyright and license information, please view the LICENSE |
|
8
|
|
|
* file that was distributed with this source code. |
|
9
|
|
|
*/ |
|
10
|
|
|
|
|
11
|
|
|
namespace PHPUnit\TextUI; |
|
12
|
|
|
|
|
13
|
|
|
use File_Iterator_Facade; |
|
14
|
|
|
use PharIo\Manifest\ApplicationName; |
|
15
|
|
|
use PharIo\Manifest\ManifestLoader; |
|
16
|
|
|
use PharIo\Version\Version as PharIoVersion; |
|
17
|
|
|
use PharIo\Manifest\Exception as ManifestException; |
|
18
|
|
|
use PHPUnit\Framework\Exception; |
|
19
|
|
|
use PHPUnit\Framework\TestSuite; |
|
20
|
|
|
use PHPUnit\Framework\Test; |
|
21
|
|
|
use PHPUnit\Framework\TestListener; |
|
22
|
|
|
use PHPUnit\Runner\PhptTestCase; |
|
23
|
|
|
use PHPUnit\Runner\StandardTestSuiteLoader; |
|
24
|
|
|
use PHPUnit\Runner\Version; |
|
25
|
|
|
use PHPUnit\Runner\TestSuiteLoader; |
|
26
|
|
|
use PHPUnit\Util\Configuration; |
|
27
|
|
|
use PHPUnit\Util\ConfigurationGenerator; |
|
28
|
|
|
use PHPUnit\Util\Fileloader; |
|
29
|
|
|
use PHPUnit\Util\Filesystem; |
|
30
|
|
|
use PHPUnit\Util\Getopt; |
|
31
|
|
|
use PHPUnit\Util\Log\TeamCity; |
|
32
|
|
|
use PHPUnit\Util\TestDox\TextResultPrinter; |
|
33
|
|
|
use PHPUnit\Util\Printer; |
|
34
|
|
|
use ReflectionClass; |
|
35
|
|
|
use Throwable; |
|
36
|
|
|
|
|
37
|
|
|
/** |
|
38
|
|
|
* A TestRunner for the Command Line Interface (CLI) |
|
39
|
|
|
* PHP SAPI Module. |
|
40
|
|
|
*/ |
|
41
|
|
|
class Command |
|
42
|
|
|
{ |
|
43
|
|
|
/** |
|
44
|
|
|
* @var array |
|
45
|
|
|
*/ |
|
46
|
|
|
protected $arguments = [ |
|
47
|
|
|
'listGroups' => false, |
|
48
|
|
|
'listSuites' => false, |
|
49
|
|
|
'loader' => null, |
|
50
|
|
|
'useDefaultConfiguration' => true, |
|
51
|
|
|
'loadedExtensions' => [], |
|
52
|
|
|
'notLoadedExtensions' => [] |
|
53
|
|
|
]; |
|
54
|
|
|
|
|
55
|
|
|
/** |
|
56
|
|
|
* @var array |
|
57
|
|
|
*/ |
|
58
|
|
|
protected $options = []; |
|
59
|
|
|
|
|
60
|
|
|
/** |
|
61
|
|
|
* @var array |
|
62
|
|
|
*/ |
|
63
|
|
|
protected $longOptions = [ |
|
64
|
|
|
'atleast-version=' => null, |
|
65
|
|
|
'bootstrap=' => null, |
|
66
|
|
|
'check-version' => null, |
|
67
|
|
|
'colors==' => null, |
|
68
|
|
|
'columns=' => null, |
|
69
|
|
|
'configuration=' => null, |
|
70
|
|
|
'coverage-clover=' => null, |
|
71
|
|
|
'coverage-crap4j=' => null, |
|
72
|
|
|
'coverage-html=' => null, |
|
73
|
|
|
'coverage-php=' => null, |
|
74
|
|
|
'coverage-text==' => null, |
|
75
|
|
|
'coverage-xml=' => null, |
|
76
|
|
|
'debug' => null, |
|
77
|
|
|
'disallow-test-output' => null, |
|
78
|
|
|
'disallow-resource-usage' => null, |
|
79
|
|
|
'disallow-todo-tests' => null, |
|
80
|
|
|
'enforce-time-limit' => null, |
|
81
|
|
|
'exclude-group=' => null, |
|
82
|
|
|
'filter=' => null, |
|
83
|
|
|
'generate-configuration' => null, |
|
84
|
|
|
'globals-backup' => null, |
|
85
|
|
|
'group=' => null, |
|
86
|
|
|
'help' => null, |
|
87
|
|
|
'include-path=' => null, |
|
88
|
|
|
'list-groups' => null, |
|
89
|
|
|
'list-suites' => null, |
|
90
|
|
|
'loader=' => null, |
|
91
|
|
|
'log-junit=' => null, |
|
92
|
|
|
'log-teamcity=' => null, |
|
93
|
|
|
'no-configuration' => null, |
|
94
|
|
|
'no-coverage' => null, |
|
95
|
|
|
'no-extensions' => null, |
|
96
|
|
|
'printer=' => null, |
|
97
|
|
|
'process-isolation' => null, |
|
98
|
|
|
'repeat=' => null, |
|
99
|
|
|
'dont-report-useless-tests' => null, |
|
100
|
|
|
'reverse-list' => null, |
|
101
|
|
|
'static-backup' => null, |
|
102
|
|
|
'stderr' => null, |
|
103
|
|
|
'stop-on-error' => null, |
|
104
|
|
|
'stop-on-failure' => null, |
|
105
|
|
|
'stop-on-warning' => null, |
|
106
|
|
|
'stop-on-incomplete' => null, |
|
107
|
|
|
'stop-on-risky' => null, |
|
108
|
|
|
'stop-on-skipped' => null, |
|
109
|
|
|
'fail-on-warning' => null, |
|
110
|
|
|
'fail-on-risky' => null, |
|
111
|
|
|
'strict-coverage' => null, |
|
112
|
|
|
'disable-coverage-ignore' => null, |
|
113
|
|
|
'strict-global-state' => null, |
|
114
|
|
|
'teamcity' => null, |
|
115
|
|
|
'testdox' => null, |
|
116
|
|
|
'testdox-group=' => null, |
|
117
|
|
|
'testdox-exclude-group=' => null, |
|
118
|
|
|
'testdox-html=' => null, |
|
119
|
|
|
'testdox-text=' => null, |
|
120
|
|
|
'testdox-xml=' => null, |
|
121
|
|
|
'test-suffix=' => null, |
|
122
|
|
|
'testsuite=' => null, |
|
123
|
|
|
'verbose' => null, |
|
124
|
|
|
'version' => null, |
|
125
|
|
|
'whitelist=' => null |
|
126
|
|
|
]; |
|
127
|
|
|
|
|
128
|
|
|
/** |
|
129
|
|
|
* @var bool |
|
130
|
|
|
*/ |
|
131
|
|
|
private $versionStringPrinted = false; |
|
132
|
|
|
|
|
133
|
|
|
/** |
|
134
|
|
|
* @param bool $exit |
|
135
|
|
|
*/ |
|
136
|
|
|
public static function main($exit = true) |
|
137
|
|
|
{ |
|
138
|
|
|
$command = new static; |
|
139
|
|
|
|
|
140
|
|
|
return $command->run($_SERVER['argv'], $exit); |
|
141
|
|
|
} |
|
142
|
|
|
|
|
143
|
|
|
/** |
|
144
|
|
|
* @param array $argv |
|
145
|
|
|
* @param bool $exit |
|
146
|
|
|
* |
|
147
|
|
|
* @return int |
|
148
|
|
|
*/ |
|
149
|
|
|
public function run(array $argv, $exit = true) |
|
150
|
|
|
{ |
|
151
|
|
|
$this->handleArguments($argv); |
|
152
|
|
|
|
|
153
|
|
|
$runner = $this->createRunner(); |
|
154
|
|
|
|
|
155
|
|
|
if ($this->arguments['test'] instanceof Test) { |
|
156
|
|
|
$suite = $this->arguments['test']; |
|
157
|
|
|
} else { |
|
158
|
|
|
$suite = $runner->getTest( |
|
159
|
|
|
$this->arguments['test'], |
|
160
|
|
|
$this->arguments['testFile'], |
|
161
|
|
|
$this->arguments['testSuffixes'] |
|
162
|
|
|
); |
|
163
|
|
|
} |
|
164
|
|
|
|
|
165
|
|
|
if ($this->arguments['listGroups']) { |
|
166
|
|
|
$this->printVersionString(); |
|
167
|
|
|
|
|
168
|
|
|
print "Available test group(s):\n"; |
|
169
|
|
|
|
|
170
|
|
|
$groups = $suite->getGroups(); |
|
171
|
|
|
\sort($groups); |
|
172
|
|
|
|
|
173
|
|
|
foreach ($groups as $group) { |
|
174
|
|
|
print " - $group\n"; |
|
175
|
|
|
} |
|
176
|
|
|
|
|
177
|
|
|
if ($exit) { |
|
178
|
|
|
exit(TestRunner::SUCCESS_EXIT); |
|
179
|
|
|
} |
|
180
|
|
|
|
|
181
|
|
|
return TestRunner::SUCCESS_EXIT; |
|
182
|
|
|
} |
|
183
|
|
|
|
|
184
|
|
|
if ($this->arguments['listSuites']) { |
|
185
|
|
|
$this->printVersionString(); |
|
186
|
|
|
|
|
187
|
|
|
print "Available test suite(s):\n"; |
|
188
|
|
|
|
|
189
|
|
|
$configuration = Configuration::getInstance( |
|
190
|
|
|
$this->arguments['configuration'] |
|
191
|
|
|
); |
|
192
|
|
|
|
|
193
|
|
|
$suiteNames = $configuration->getTestSuiteNames(); |
|
194
|
|
|
foreach ($suiteNames as $suiteName) { |
|
195
|
|
|
print " - $suiteName\n"; |
|
196
|
|
|
} |
|
197
|
|
|
|
|
198
|
|
|
if ($exit) { |
|
199
|
|
|
exit(TestRunner::SUCCESS_EXIT); |
|
200
|
|
|
} |
|
201
|
|
|
|
|
202
|
|
|
return TestRunner::SUCCESS_EXIT; |
|
203
|
|
|
} |
|
204
|
|
|
|
|
205
|
|
|
unset($this->arguments['test']); |
|
206
|
|
|
unset($this->arguments['testFile']); |
|
207
|
|
|
|
|
208
|
|
|
try { |
|
209
|
|
|
$result = $runner->doRun($suite, $this->arguments, $exit); |
|
210
|
|
|
} catch (Exception $e) { |
|
211
|
|
|
print $e->getMessage() . "\n"; |
|
212
|
|
|
} |
|
213
|
|
|
|
|
214
|
|
|
$return = TestRunner::FAILURE_EXIT; |
|
215
|
|
|
|
|
216
|
|
|
if (isset($result) && $result->wasSuccessful()) { |
|
217
|
|
|
$return = TestRunner::SUCCESS_EXIT; |
|
218
|
|
|
} elseif (!isset($result) || $result->errorCount() > 0) { |
|
219
|
|
|
$return = TestRunner::EXCEPTION_EXIT; |
|
220
|
|
|
} |
|
221
|
|
|
|
|
222
|
|
|
if ($exit) { |
|
223
|
|
|
exit($return); |
|
224
|
|
|
} |
|
225
|
|
|
|
|
226
|
|
|
return $return; |
|
227
|
|
|
} |
|
228
|
|
|
|
|
229
|
|
|
/** |
|
230
|
|
|
* Create a TestRunner, override in subclasses. |
|
231
|
|
|
* |
|
232
|
|
|
* @return TestRunner |
|
233
|
|
|
*/ |
|
234
|
|
|
protected function createRunner() |
|
235
|
|
|
{ |
|
236
|
|
|
return new TestRunner($this->arguments['loader']); |
|
237
|
|
|
} |
|
238
|
|
|
|
|
239
|
|
|
/** |
|
240
|
|
|
* Handles the command-line arguments. |
|
241
|
|
|
* |
|
242
|
|
|
* A child class of PHPUnit_TextUI_Command can hook into the argument |
|
243
|
|
|
* parsing by adding the switch(es) to the $longOptions array and point to a |
|
244
|
|
|
* callback method that handles the switch(es) in the child class like this |
|
245
|
|
|
* |
|
246
|
|
|
* <code> |
|
247
|
|
|
* <?php |
|
248
|
|
|
* class MyCommand extends PHPUnit_TextUI_Command |
|
249
|
|
|
* { |
|
250
|
|
|
* public function __construct() |
|
251
|
|
|
* { |
|
252
|
|
|
* // my-switch won't accept a value, it's an on/off |
|
253
|
|
|
* $this->longOptions['my-switch'] = 'myHandler'; |
|
254
|
|
|
* // my-secondswitch will accept a value - note the equals sign |
|
255
|
|
|
* $this->longOptions['my-secondswitch='] = 'myOtherHandler'; |
|
256
|
|
|
* } |
|
257
|
|
|
* |
|
258
|
|
|
* // --my-switch -> myHandler() |
|
259
|
|
|
* protected function myHandler() |
|
260
|
|
|
* { |
|
261
|
|
|
* } |
|
262
|
|
|
* |
|
263
|
|
|
* // --my-secondswitch foo -> myOtherHandler('foo') |
|
264
|
|
|
* protected function myOtherHandler ($value) |
|
265
|
|
|
* { |
|
266
|
|
|
* } |
|
267
|
|
|
* |
|
268
|
|
|
* // You will also need this - the static keyword in the |
|
269
|
|
|
* // PHPUnit_TextUI_Command will mean that it'll be |
|
270
|
|
|
* // PHPUnit_TextUI_Command that gets instantiated, |
|
271
|
|
|
* // not MyCommand |
|
272
|
|
|
* public static function main($exit = true) |
|
273
|
|
|
* { |
|
274
|
|
|
* $command = new static; |
|
275
|
|
|
* |
|
276
|
|
|
* return $command->run($_SERVER['argv'], $exit); |
|
277
|
|
|
* } |
|
278
|
|
|
* |
|
279
|
|
|
* } |
|
280
|
|
|
* </code> |
|
281
|
|
|
* |
|
282
|
|
|
* @param array $argv |
|
283
|
|
|
*/ |
|
284
|
|
|
protected function handleArguments(array $argv) |
|
285
|
|
|
{ |
|
286
|
|
|
try { |
|
287
|
|
|
$this->options = Getopt::getopt( |
|
288
|
|
|
$argv, |
|
289
|
|
|
'd:c:hv', |
|
290
|
|
|
\array_keys($this->longOptions) |
|
291
|
|
|
); |
|
292
|
|
|
} catch (Exception $t) { |
|
293
|
|
|
$this->showError($t->getMessage()); |
|
294
|
|
|
} |
|
295
|
|
|
|
|
296
|
|
|
foreach ($this->options[0] as $option) { |
|
297
|
|
|
switch ($option[0]) { |
|
298
|
|
|
case '--colors': |
|
299
|
|
|
$this->arguments['colors'] = $option[1] ?: ResultPrinter::COLOR_AUTO; |
|
300
|
|
|
break; |
|
301
|
|
|
|
|
302
|
|
|
case '--bootstrap': |
|
303
|
|
|
$this->arguments['bootstrap'] = $option[1]; |
|
304
|
|
|
break; |
|
305
|
|
|
|
|
306
|
|
|
case '--columns': |
|
307
|
|
|
if (\is_numeric($option[1])) { |
|
308
|
|
|
$this->arguments['columns'] = (int) $option[1]; |
|
309
|
|
|
} elseif ($option[1] == 'max') { |
|
310
|
|
|
$this->arguments['columns'] = 'max'; |
|
311
|
|
|
} |
|
312
|
|
|
break; |
|
313
|
|
|
|
|
314
|
|
|
case 'c': |
|
315
|
|
|
case '--configuration': |
|
316
|
|
|
$this->arguments['configuration'] = $option[1]; |
|
317
|
|
|
break; |
|
318
|
|
|
|
|
319
|
|
|
case '--coverage-clover': |
|
320
|
|
|
$this->arguments['coverageClover'] = $option[1]; |
|
321
|
|
|
break; |
|
322
|
|
|
|
|
323
|
|
|
case '--coverage-crap4j': |
|
324
|
|
|
$this->arguments['coverageCrap4J'] = $option[1]; |
|
325
|
|
|
break; |
|
326
|
|
|
|
|
327
|
|
|
case '--coverage-html': |
|
328
|
|
|
$this->arguments['coverageHtml'] = $option[1]; |
|
329
|
|
|
break; |
|
330
|
|
|
|
|
331
|
|
|
case '--coverage-php': |
|
332
|
|
|
$this->arguments['coveragePHP'] = $option[1]; |
|
333
|
|
|
break; |
|
334
|
|
|
|
|
335
|
|
|
case '--coverage-text': |
|
336
|
|
|
if ($option[1] === null) { |
|
337
|
|
|
$option[1] = 'php://stdout'; |
|
338
|
|
|
} |
|
339
|
|
|
|
|
340
|
|
|
$this->arguments['coverageText'] = $option[1]; |
|
341
|
|
|
$this->arguments['coverageTextShowUncoveredFiles'] = false; |
|
342
|
|
|
$this->arguments['coverageTextShowOnlySummary'] = false; |
|
343
|
|
|
break; |
|
344
|
|
|
|
|
345
|
|
|
case '--coverage-xml': |
|
346
|
|
|
$this->arguments['coverageXml'] = $option[1]; |
|
347
|
|
|
break; |
|
348
|
|
|
|
|
349
|
|
|
case 'd': |
|
350
|
|
|
$ini = \explode('=', $option[1]); |
|
351
|
|
|
|
|
352
|
|
|
if (isset($ini[0])) { |
|
353
|
|
|
if (isset($ini[1])) { |
|
354
|
|
|
\ini_set($ini[0], $ini[1]); |
|
355
|
|
|
} else { |
|
356
|
|
|
\ini_set($ini[0], true); |
|
357
|
|
|
} |
|
358
|
|
|
} |
|
359
|
|
|
break; |
|
360
|
|
|
|
|
361
|
|
|
case '--debug': |
|
362
|
|
|
$this->arguments['debug'] = true; |
|
363
|
|
|
break; |
|
364
|
|
|
|
|
365
|
|
|
case 'h': |
|
366
|
|
|
case '--help': |
|
367
|
|
|
$this->showHelp(); |
|
368
|
|
|
exit(TestRunner::SUCCESS_EXIT); |
|
369
|
|
|
break; |
|
|
|
|
|
|
370
|
|
|
|
|
371
|
|
|
case '--filter': |
|
372
|
|
|
$this->arguments['filter'] = $option[1]; |
|
373
|
|
|
break; |
|
374
|
|
|
|
|
375
|
|
|
case '--testsuite': |
|
376
|
|
|
$this->arguments['testsuite'] = $option[1]; |
|
377
|
|
|
break; |
|
378
|
|
|
|
|
379
|
|
|
case '--generate-configuration': |
|
380
|
|
|
$this->printVersionString(); |
|
381
|
|
|
|
|
382
|
|
|
\printf( |
|
383
|
|
|
"Generating phpunit.xml in %s\n\n", |
|
384
|
|
|
\getcwd() |
|
385
|
|
|
); |
|
386
|
|
|
|
|
387
|
|
|
print 'Bootstrap script (relative to path shown above; default: vendor/autoload.php): '; |
|
388
|
|
|
$bootstrapScript = \trim(\fgets(STDIN)); |
|
389
|
|
|
|
|
390
|
|
|
print 'Tests directory (relative to path shown above; default: tests): '; |
|
391
|
|
|
$testsDirectory = \trim(\fgets(STDIN)); |
|
392
|
|
|
|
|
393
|
|
|
print 'Source directory (relative to path shown above; default: src): '; |
|
394
|
|
|
$src = \trim(\fgets(STDIN)); |
|
395
|
|
|
|
|
396
|
|
|
if ($bootstrapScript == '') { |
|
397
|
|
|
$bootstrapScript = 'vendor/autoload.php'; |
|
398
|
|
|
} |
|
399
|
|
|
|
|
400
|
|
|
if ($testsDirectory == '') { |
|
401
|
|
|
$testsDirectory = 'tests'; |
|
402
|
|
|
} |
|
403
|
|
|
|
|
404
|
|
|
if ($src == '') { |
|
405
|
|
|
$src = 'src'; |
|
406
|
|
|
} |
|
407
|
|
|
|
|
408
|
|
|
$generator = new ConfigurationGenerator; |
|
409
|
|
|
|
|
410
|
|
|
\file_put_contents( |
|
411
|
|
|
'phpunit.xml', |
|
412
|
|
|
$generator->generateDefaultConfiguration( |
|
413
|
|
|
Version::series(), |
|
414
|
|
|
$bootstrapScript, |
|
415
|
|
|
$testsDirectory, |
|
416
|
|
|
$src |
|
417
|
|
|
) |
|
418
|
|
|
); |
|
419
|
|
|
|
|
420
|
|
|
\printf( |
|
421
|
|
|
"\nGenerated phpunit.xml in %s\n", |
|
422
|
|
|
\getcwd() |
|
423
|
|
|
); |
|
424
|
|
|
|
|
425
|
|
|
exit(TestRunner::SUCCESS_EXIT); |
|
426
|
|
|
break; |
|
|
|
|
|
|
427
|
|
|
|
|
428
|
|
|
case '--group': |
|
429
|
|
|
$this->arguments['groups'] = \explode(',', $option[1]); |
|
430
|
|
|
break; |
|
431
|
|
|
|
|
432
|
|
|
case '--exclude-group': |
|
433
|
|
|
$this->arguments['excludeGroups'] = \explode( |
|
434
|
|
|
',', |
|
435
|
|
|
$option[1] |
|
436
|
|
|
); |
|
437
|
|
|
break; |
|
438
|
|
|
|
|
439
|
|
|
case '--test-suffix': |
|
440
|
|
|
$this->arguments['testSuffixes'] = \explode( |
|
441
|
|
|
',', |
|
442
|
|
|
$option[1] |
|
443
|
|
|
); |
|
444
|
|
|
break; |
|
445
|
|
|
|
|
446
|
|
|
case '--include-path': |
|
447
|
|
|
$includePath = $option[1]; |
|
448
|
|
|
break; |
|
449
|
|
|
|
|
450
|
|
|
case '--list-groups': |
|
451
|
|
|
$this->arguments['listGroups'] = true; |
|
452
|
|
|
break; |
|
453
|
|
|
|
|
454
|
|
|
case '--list-suites': |
|
455
|
|
|
$this->arguments['listSuites'] = true; |
|
456
|
|
|
break; |
|
457
|
|
|
|
|
458
|
|
|
case '--printer': |
|
459
|
|
|
$this->arguments['printer'] = $option[1]; |
|
460
|
|
|
break; |
|
461
|
|
|
|
|
462
|
|
|
case '--loader': |
|
463
|
|
|
$this->arguments['loader'] = $option[1]; |
|
464
|
|
|
break; |
|
465
|
|
|
|
|
466
|
|
|
case '--log-junit': |
|
467
|
|
|
$this->arguments['junitLogfile'] = $option[1]; |
|
468
|
|
|
break; |
|
469
|
|
|
|
|
470
|
|
|
case '--log-teamcity': |
|
471
|
|
|
$this->arguments['teamcityLogfile'] = $option[1]; |
|
472
|
|
|
break; |
|
473
|
|
|
|
|
474
|
|
|
case '--process-isolation': |
|
475
|
|
|
$this->arguments['processIsolation'] = true; |
|
476
|
|
|
break; |
|
477
|
|
|
|
|
478
|
|
|
case '--repeat': |
|
479
|
|
|
$this->arguments['repeat'] = (int) $option[1]; |
|
480
|
|
|
break; |
|
481
|
|
|
|
|
482
|
|
|
case '--stderr': |
|
483
|
|
|
$this->arguments['stderr'] = true; |
|
484
|
|
|
break; |
|
485
|
|
|
|
|
486
|
|
|
case '--stop-on-error': |
|
487
|
|
|
$this->arguments['stopOnError'] = true; |
|
488
|
|
|
break; |
|
489
|
|
|
|
|
490
|
|
|
case '--stop-on-failure': |
|
491
|
|
|
$this->arguments['stopOnFailure'] = true; |
|
492
|
|
|
break; |
|
493
|
|
|
|
|
494
|
|
|
case '--stop-on-warning': |
|
495
|
|
|
$this->arguments['stopOnWarning'] = true; |
|
496
|
|
|
break; |
|
497
|
|
|
|
|
498
|
|
|
case '--stop-on-incomplete': |
|
499
|
|
|
$this->arguments['stopOnIncomplete'] = true; |
|
500
|
|
|
break; |
|
501
|
|
|
|
|
502
|
|
|
case '--stop-on-risky': |
|
503
|
|
|
$this->arguments['stopOnRisky'] = true; |
|
504
|
|
|
break; |
|
505
|
|
|
|
|
506
|
|
|
case '--stop-on-skipped': |
|
507
|
|
|
$this->arguments['stopOnSkipped'] = true; |
|
508
|
|
|
break; |
|
509
|
|
|
|
|
510
|
|
|
case '--fail-on-warning': |
|
511
|
|
|
$this->arguments['failOnWarning'] = true; |
|
512
|
|
|
break; |
|
513
|
|
|
|
|
514
|
|
|
case '--fail-on-risky': |
|
515
|
|
|
$this->arguments['failOnRisky'] = true; |
|
516
|
|
|
break; |
|
517
|
|
|
|
|
518
|
|
|
case '--teamcity': |
|
519
|
|
|
$this->arguments['printer'] = TeamCity::class; |
|
520
|
|
|
break; |
|
521
|
|
|
|
|
522
|
|
|
case '--testdox': |
|
523
|
|
|
$this->arguments['printer'] = TextResultPrinter::class; |
|
524
|
|
|
break; |
|
525
|
|
|
|
|
526
|
|
|
case '--testdox-group': |
|
527
|
|
|
$this->arguments['testdoxGroups'] = \explode( |
|
528
|
|
|
',', |
|
529
|
|
|
$option[1] |
|
530
|
|
|
); |
|
531
|
|
|
break; |
|
532
|
|
|
|
|
533
|
|
|
case '--testdox-exclude-group': |
|
534
|
|
|
$this->arguments['testdoxExcludeGroups'] = \explode( |
|
535
|
|
|
',', |
|
536
|
|
|
$option[1] |
|
537
|
|
|
); |
|
538
|
|
|
break; |
|
539
|
|
|
|
|
540
|
|
|
case '--testdox-html': |
|
541
|
|
|
$this->arguments['testdoxHTMLFile'] = $option[1]; |
|
542
|
|
|
break; |
|
543
|
|
|
|
|
544
|
|
|
case '--testdox-text': |
|
545
|
|
|
$this->arguments['testdoxTextFile'] = $option[1]; |
|
546
|
|
|
break; |
|
547
|
|
|
|
|
548
|
|
|
case '--testdox-xml': |
|
549
|
|
|
$this->arguments['testdoxXMLFile'] = $option[1]; |
|
550
|
|
|
break; |
|
551
|
|
|
|
|
552
|
|
|
case '--no-configuration': |
|
553
|
|
|
$this->arguments['useDefaultConfiguration'] = false; |
|
554
|
|
|
break; |
|
555
|
|
|
|
|
556
|
|
|
case '--no-extensions': |
|
557
|
|
|
$this->arguments['noExtensions'] = true; |
|
558
|
|
|
break; |
|
559
|
|
|
|
|
560
|
|
|
case '--no-coverage': |
|
561
|
|
|
$this->arguments['noCoverage'] = true; |
|
562
|
|
|
break; |
|
563
|
|
|
|
|
564
|
|
|
case '--globals-backup': |
|
565
|
|
|
$this->arguments['backupGlobals'] = true; |
|
566
|
|
|
break; |
|
567
|
|
|
|
|
568
|
|
|
case '--static-backup': |
|
569
|
|
|
$this->arguments['backupStaticAttributes'] = true; |
|
570
|
|
|
break; |
|
571
|
|
|
|
|
572
|
|
|
case 'v': |
|
573
|
|
|
case '--verbose': |
|
574
|
|
|
$this->arguments['verbose'] = true; |
|
575
|
|
|
break; |
|
576
|
|
|
|
|
577
|
|
|
case '--atleast-version': |
|
578
|
|
|
if (\version_compare(Version::id(), $option[1], '>=')) { |
|
579
|
|
|
exit(TestRunner::SUCCESS_EXIT); |
|
580
|
|
|
} |
|
581
|
|
|
|
|
582
|
|
|
exit(TestRunner::FAILURE_EXIT); |
|
583
|
|
|
break; |
|
|
|
|
|
|
584
|
|
|
|
|
585
|
|
|
case '--version': |
|
586
|
|
|
$this->printVersionString(); |
|
587
|
|
|
exit(TestRunner::SUCCESS_EXIT); |
|
588
|
|
|
break; |
|
|
|
|
|
|
589
|
|
|
|
|
590
|
|
|
case '--dont-report-useless-tests': |
|
591
|
|
|
$this->arguments['reportUselessTests'] = false; |
|
592
|
|
|
break; |
|
593
|
|
|
|
|
594
|
|
|
case '--strict-coverage': |
|
595
|
|
|
$this->arguments['strictCoverage'] = true; |
|
596
|
|
|
break; |
|
597
|
|
|
|
|
598
|
|
|
case '--disable-coverage-ignore': |
|
599
|
|
|
$this->arguments['disableCodeCoverageIgnore'] = true; |
|
600
|
|
|
break; |
|
601
|
|
|
|
|
602
|
|
|
case '--strict-global-state': |
|
603
|
|
|
$this->arguments['beStrictAboutChangesToGlobalState'] = true; |
|
604
|
|
|
break; |
|
605
|
|
|
|
|
606
|
|
|
case '--disallow-test-output': |
|
607
|
|
|
$this->arguments['disallowTestOutput'] = true; |
|
608
|
|
|
break; |
|
609
|
|
|
|
|
610
|
|
|
case '--disallow-resource-usage': |
|
611
|
|
|
$this->arguments['beStrictAboutResourceUsageDuringSmallTests'] = true; |
|
612
|
|
|
break; |
|
613
|
|
|
|
|
614
|
|
|
case '--enforce-time-limit': |
|
615
|
|
|
$this->arguments['enforceTimeLimit'] = true; |
|
616
|
|
|
break; |
|
617
|
|
|
|
|
618
|
|
|
case '--disallow-todo-tests': |
|
619
|
|
|
$this->arguments['disallowTodoAnnotatedTests'] = true; |
|
620
|
|
|
break; |
|
621
|
|
|
|
|
622
|
|
|
case '--reverse-list': |
|
623
|
|
|
$this->arguments['reverseList'] = true; |
|
624
|
|
|
break; |
|
625
|
|
|
|
|
626
|
|
|
case '--check-version': |
|
627
|
|
|
$this->handleVersionCheck(); |
|
628
|
|
|
break; |
|
629
|
|
|
|
|
630
|
|
|
case '--whitelist': |
|
631
|
|
|
$this->arguments['whitelist'] = $option[1]; |
|
632
|
|
|
break; |
|
633
|
|
|
|
|
634
|
|
|
default: |
|
635
|
|
|
$optionName = \str_replace('--', '', $option[0]); |
|
636
|
|
|
|
|
637
|
|
|
$handler = null; |
|
638
|
|
|
if (isset($this->longOptions[$optionName])) { |
|
639
|
|
|
$handler = $this->longOptions[$optionName]; |
|
640
|
|
|
} elseif (isset($this->longOptions[$optionName . '='])) { |
|
641
|
|
|
$handler = $this->longOptions[$optionName . '=']; |
|
642
|
|
|
} |
|
643
|
|
|
|
|
644
|
|
|
if (isset($handler) && \is_callable([$this, $handler])) { |
|
645
|
|
|
$this->$handler($option[1]); |
|
646
|
|
|
} |
|
647
|
|
|
} |
|
648
|
|
|
} |
|
649
|
|
|
|
|
650
|
|
|
$this->handleCustomTestSuite(); |
|
651
|
|
|
|
|
652
|
|
|
if (!isset($this->arguments['test'])) { |
|
653
|
|
|
if (isset($this->options[1][0])) { |
|
654
|
|
|
$this->arguments['test'] = $this->options[1][0]; |
|
655
|
|
|
} |
|
656
|
|
|
|
|
657
|
|
|
if (isset($this->options[1][1])) { |
|
658
|
|
|
$this->arguments['testFile'] = \realpath($this->options[1][1]); |
|
659
|
|
|
} else { |
|
660
|
|
|
$this->arguments['testFile'] = ''; |
|
661
|
|
|
} |
|
662
|
|
|
|
|
663
|
|
|
if (isset($this->arguments['test']) && |
|
664
|
|
|
\is_file($this->arguments['test']) && |
|
665
|
|
|
\substr($this->arguments['test'], -5, 5) != '.phpt') { |
|
666
|
|
|
$this->arguments['testFile'] = \realpath($this->arguments['test']); |
|
667
|
|
|
$this->arguments['test'] = \substr($this->arguments['test'], 0, \strrpos($this->arguments['test'], '.')); |
|
668
|
|
|
} |
|
669
|
|
|
} |
|
670
|
|
|
|
|
671
|
|
|
if (!isset($this->arguments['testSuffixes'])) { |
|
672
|
|
|
$this->arguments['testSuffixes'] = ['Test.php', '.phpt']; |
|
673
|
|
|
} |
|
674
|
|
|
|
|
675
|
|
|
if (isset($includePath)) { |
|
676
|
|
|
\ini_set( |
|
677
|
|
|
'include_path', |
|
678
|
|
|
$includePath . PATH_SEPARATOR . \ini_get('include_path') |
|
679
|
|
|
); |
|
680
|
|
|
} |
|
681
|
|
|
|
|
682
|
|
|
if ($this->arguments['loader'] !== null) { |
|
683
|
|
|
$this->arguments['loader'] = $this->handleLoader($this->arguments['loader']); |
|
684
|
|
|
} |
|
685
|
|
|
|
|
686
|
|
|
if (isset($this->arguments['configuration']) && |
|
687
|
|
|
\is_dir($this->arguments['configuration'])) { |
|
688
|
|
|
$configurationFile = $this->arguments['configuration'] . '/phpunit.xml'; |
|
689
|
|
|
|
|
690
|
|
|
if (\file_exists($configurationFile)) { |
|
691
|
|
|
$this->arguments['configuration'] = \realpath( |
|
692
|
|
|
$configurationFile |
|
693
|
|
|
); |
|
694
|
|
|
} elseif (\file_exists($configurationFile . '.dist')) { |
|
695
|
|
|
$this->arguments['configuration'] = \realpath( |
|
696
|
|
|
$configurationFile . '.dist' |
|
697
|
|
|
); |
|
698
|
|
|
} |
|
699
|
|
|
} elseif (!isset($this->arguments['configuration']) && |
|
700
|
|
|
$this->arguments['useDefaultConfiguration']) { |
|
701
|
|
|
if (\file_exists('phpunit.xml')) { |
|
702
|
|
|
$this->arguments['configuration'] = \realpath('phpunit.xml'); |
|
703
|
|
|
} elseif (\file_exists('phpunit.xml.dist')) { |
|
704
|
|
|
$this->arguments['configuration'] = \realpath( |
|
705
|
|
|
'phpunit.xml.dist' |
|
706
|
|
|
); |
|
707
|
|
|
} |
|
708
|
|
|
} |
|
709
|
|
|
|
|
710
|
|
|
if (isset($this->arguments['configuration'])) { |
|
711
|
|
|
try { |
|
712
|
|
|
$configuration = Configuration::getInstance( |
|
713
|
|
|
$this->arguments['configuration'] |
|
714
|
|
|
); |
|
715
|
|
|
} catch (Throwable $t) { |
|
716
|
|
|
print $t->getMessage() . "\n"; |
|
717
|
|
|
exit(TestRunner::FAILURE_EXIT); |
|
718
|
|
|
} |
|
719
|
|
|
|
|
720
|
|
|
$phpunitConfiguration = $configuration->getPHPUnitConfiguration(); |
|
721
|
|
|
|
|
722
|
|
|
$configuration->handlePHPConfiguration(); |
|
723
|
|
|
|
|
724
|
|
|
/* |
|
725
|
|
|
* Issue #1216 |
|
726
|
|
|
*/ |
|
727
|
|
|
if (isset($this->arguments['bootstrap'])) { |
|
728
|
|
|
$this->handleBootstrap($this->arguments['bootstrap']); |
|
729
|
|
|
} elseif (isset($phpunitConfiguration['bootstrap'])) { |
|
730
|
|
|
$this->handleBootstrap($phpunitConfiguration['bootstrap']); |
|
731
|
|
|
} |
|
732
|
|
|
|
|
733
|
|
|
/* |
|
734
|
|
|
* Issue #657 |
|
735
|
|
|
*/ |
|
736
|
|
|
if (isset($phpunitConfiguration['stderr']) && !isset($this->arguments['stderr'])) { |
|
737
|
|
|
$this->arguments['stderr'] = $phpunitConfiguration['stderr']; |
|
738
|
|
|
} |
|
739
|
|
|
|
|
740
|
|
|
if (isset($phpunitConfiguration['extensionsDirectory']) && !isset($this->arguments['noExtensions']) && \extension_loaded('phar')) { |
|
741
|
|
|
$this->handleExtensions($phpunitConfiguration['extensionsDirectory']); |
|
742
|
|
|
} |
|
743
|
|
|
|
|
744
|
|
|
if (isset($phpunitConfiguration['columns']) && !isset($this->arguments['columns'])) { |
|
745
|
|
|
$this->arguments['columns'] = $phpunitConfiguration['columns']; |
|
746
|
|
|
} |
|
747
|
|
|
|
|
748
|
|
|
if (!isset($this->arguments['printer']) && isset($phpunitConfiguration['printerClass'])) { |
|
749
|
|
|
if (isset($phpunitConfiguration['printerFile'])) { |
|
750
|
|
|
$file = $phpunitConfiguration['printerFile']; |
|
751
|
|
|
} else { |
|
752
|
|
|
$file = ''; |
|
753
|
|
|
} |
|
754
|
|
|
|
|
755
|
|
|
$this->arguments['printer'] = $this->handlePrinter( |
|
756
|
|
|
$phpunitConfiguration['printerClass'], |
|
757
|
|
|
$file |
|
758
|
|
|
); |
|
759
|
|
|
} |
|
760
|
|
|
|
|
761
|
|
|
if (isset($phpunitConfiguration['testSuiteLoaderClass'])) { |
|
762
|
|
|
if (isset($phpunitConfiguration['testSuiteLoaderFile'])) { |
|
763
|
|
|
$file = $phpunitConfiguration['testSuiteLoaderFile']; |
|
764
|
|
|
} else { |
|
765
|
|
|
$file = ''; |
|
766
|
|
|
} |
|
767
|
|
|
|
|
768
|
|
|
$this->arguments['loader'] = $this->handleLoader( |
|
769
|
|
|
$phpunitConfiguration['testSuiteLoaderClass'], |
|
770
|
|
|
$file |
|
771
|
|
|
); |
|
772
|
|
|
} |
|
773
|
|
|
|
|
774
|
|
|
if (!isset($this->arguments['testsuite']) && isset($phpunitConfiguration['defaultTestSuite'])) { |
|
775
|
|
|
$this->arguments['testsuite'] = $phpunitConfiguration['defaultTestSuite']; |
|
776
|
|
|
} |
|
777
|
|
|
|
|
778
|
|
|
if (!isset($this->arguments['test'])) { |
|
779
|
|
|
$testSuite = $configuration->getTestSuiteConfiguration($this->arguments['testsuite'] ?? null); |
|
780
|
|
|
|
|
781
|
|
|
if ($testSuite !== null) { |
|
782
|
|
|
$this->arguments['test'] = $testSuite; |
|
783
|
|
|
} |
|
784
|
|
|
} |
|
785
|
|
|
} elseif (isset($this->arguments['bootstrap'])) { |
|
786
|
|
|
$this->handleBootstrap($this->arguments['bootstrap']); |
|
787
|
|
|
} |
|
788
|
|
|
|
|
789
|
|
|
if (isset($this->arguments['printer']) && |
|
790
|
|
|
\is_string($this->arguments['printer'])) { |
|
791
|
|
|
$this->arguments['printer'] = $this->handlePrinter($this->arguments['printer']); |
|
792
|
|
|
} |
|
793
|
|
|
|
|
794
|
|
|
if (isset($this->arguments['test']) && \is_string($this->arguments['test']) && \substr($this->arguments['test'], -5, 5) == '.phpt') { |
|
795
|
|
|
$test = new PhptTestCase($this->arguments['test']); |
|
796
|
|
|
|
|
797
|
|
|
$this->arguments['test'] = new TestSuite; |
|
798
|
|
|
$this->arguments['test']->addTest($test); |
|
799
|
|
|
} |
|
800
|
|
|
|
|
801
|
|
|
if (!isset($this->arguments['test'])) { |
|
802
|
|
|
$this->showHelp(); |
|
803
|
|
|
exit(TestRunner::EXCEPTION_EXIT); |
|
804
|
|
|
} |
|
805
|
|
|
} |
|
806
|
|
|
|
|
807
|
|
|
/** |
|
808
|
|
|
* Handles the loading of the PHPUnit_Runner_TestSuiteLoader implementation. |
|
809
|
|
|
* |
|
810
|
|
|
* @param string $loaderClass |
|
811
|
|
|
* @param string $loaderFile |
|
812
|
|
|
* |
|
813
|
|
|
* @return TestSuiteLoader |
|
814
|
|
|
*/ |
|
815
|
|
|
protected function handleLoader($loaderClass, $loaderFile = '') |
|
816
|
|
|
{ |
|
817
|
|
|
if (!\class_exists($loaderClass, false)) { |
|
818
|
|
|
if ($loaderFile == '') { |
|
819
|
|
|
$loaderFile = Filesystem::classNameToFilename( |
|
820
|
|
|
$loaderClass |
|
821
|
|
|
); |
|
822
|
|
|
} |
|
823
|
|
|
|
|
824
|
|
|
$loaderFile = \stream_resolve_include_path($loaderFile); |
|
825
|
|
|
|
|
826
|
|
|
if ($loaderFile) { |
|
827
|
|
|
require $loaderFile; |
|
828
|
|
|
} |
|
829
|
|
|
} |
|
830
|
|
|
|
|
831
|
|
|
if (\class_exists($loaderClass, false)) { |
|
832
|
|
|
$class = new ReflectionClass($loaderClass); |
|
833
|
|
|
|
|
834
|
|
|
if ($class->implementsInterface(TestSuiteLoader::class) && |
|
835
|
|
|
$class->isInstantiable()) { |
|
836
|
|
|
return $class->newInstance(); |
|
837
|
|
|
} |
|
838
|
|
|
} |
|
839
|
|
|
|
|
840
|
|
|
if ($loaderClass == StandardTestSuiteLoader::class) { |
|
841
|
|
|
return; |
|
842
|
|
|
} |
|
843
|
|
|
|
|
844
|
|
|
$this->showError( |
|
845
|
|
|
\sprintf( |
|
846
|
|
|
'Could not use "%s" as loader.', |
|
847
|
|
|
$loaderClass |
|
848
|
|
|
) |
|
849
|
|
|
); |
|
850
|
|
|
} |
|
851
|
|
|
|
|
852
|
|
|
/** |
|
853
|
|
|
* Handles the loading of the PHPUnit_Util_Printer implementation. |
|
854
|
|
|
* |
|
855
|
|
|
* @param string $printerClass |
|
856
|
|
|
* @param string $printerFile |
|
857
|
|
|
* |
|
858
|
|
|
* @return Printer|string |
|
859
|
|
|
*/ |
|
860
|
|
|
protected function handlePrinter($printerClass, $printerFile = '') |
|
861
|
|
|
{ |
|
862
|
|
|
if (!\class_exists($printerClass, false)) { |
|
863
|
|
|
if ($printerFile == '') { |
|
864
|
|
|
$printerFile = Filesystem::classNameToFilename( |
|
865
|
|
|
$printerClass |
|
866
|
|
|
); |
|
867
|
|
|
} |
|
868
|
|
|
|
|
869
|
|
|
$printerFile = \stream_resolve_include_path($printerFile); |
|
870
|
|
|
|
|
871
|
|
|
if ($printerFile) { |
|
872
|
|
|
require $printerFile; |
|
873
|
|
|
} |
|
874
|
|
|
} |
|
875
|
|
|
|
|
876
|
|
|
if (\class_exists($printerClass)) { |
|
877
|
|
|
$class = new ReflectionClass($printerClass); |
|
878
|
|
|
|
|
879
|
|
|
if ($class->implementsInterface(TestListener::class) && |
|
880
|
|
|
$class->isSubclassOf(Printer::class) && |
|
881
|
|
|
$class->isInstantiable()) { |
|
882
|
|
|
if ($class->isSubclassOf(ResultPrinter::class)) { |
|
883
|
|
|
return $printerClass; |
|
884
|
|
|
} |
|
885
|
|
|
|
|
886
|
|
|
$outputStream = isset($this->arguments['stderr']) ? 'php://stderr' : null; |
|
887
|
|
|
|
|
888
|
|
|
return $class->newInstance($outputStream); |
|
889
|
|
|
} |
|
890
|
|
|
} |
|
891
|
|
|
|
|
892
|
|
|
$this->showError( |
|
893
|
|
|
\sprintf( |
|
894
|
|
|
'Could not use "%s" as printer.', |
|
895
|
|
|
$printerClass |
|
896
|
|
|
) |
|
897
|
|
|
); |
|
898
|
|
|
} |
|
899
|
|
|
|
|
900
|
|
|
/** |
|
901
|
|
|
* Loads a bootstrap file. |
|
902
|
|
|
* |
|
903
|
|
|
* @param string $filename |
|
904
|
|
|
*/ |
|
905
|
|
|
protected function handleBootstrap($filename) |
|
906
|
|
|
{ |
|
907
|
|
|
try { |
|
908
|
|
|
Fileloader::checkAndLoad($filename); |
|
909
|
|
|
} catch (Exception $e) { |
|
910
|
|
|
$this->showError($e->getMessage()); |
|
911
|
|
|
} |
|
912
|
|
|
} |
|
913
|
|
|
|
|
914
|
|
|
protected function handleVersionCheck() |
|
915
|
|
|
{ |
|
916
|
|
|
$this->printVersionString(); |
|
917
|
|
|
|
|
918
|
|
|
$latestVersion = \file_get_contents('https://phar.phpunit.de/latest-version-of/phpunit'); |
|
919
|
|
|
$isOutdated = \version_compare($latestVersion, Version::id(), '>'); |
|
920
|
|
|
|
|
921
|
|
|
if ($isOutdated) { |
|
922
|
|
|
\printf( |
|
923
|
|
|
"You are not using the latest version of PHPUnit.\n" . |
|
924
|
|
|
"The latest version is PHPUnit %s.\n", |
|
925
|
|
|
$latestVersion |
|
926
|
|
|
); |
|
927
|
|
|
} else { |
|
928
|
|
|
print "You are using the latest version of PHPUnit.\n"; |
|
929
|
|
|
} |
|
930
|
|
|
|
|
931
|
|
|
exit(TestRunner::SUCCESS_EXIT); |
|
932
|
|
|
} |
|
933
|
|
|
|
|
934
|
|
|
/** |
|
935
|
|
|
* Show the help message. |
|
936
|
|
|
*/ |
|
937
|
|
|
protected function showHelp() |
|
938
|
|
|
{ |
|
939
|
|
|
$this->printVersionString(); |
|
940
|
|
|
|
|
941
|
|
|
print <<<EOT |
|
942
|
|
|
Usage: phpunit [options] UnitTest [UnitTest.php] |
|
943
|
|
|
phpunit [options] <directory> |
|
944
|
|
|
|
|
945
|
|
|
Code Coverage Options: |
|
946
|
|
|
|
|
947
|
|
|
--coverage-clover <file> Generate code coverage report in Clover XML format. |
|
948
|
|
|
--coverage-crap4j <file> Generate code coverage report in Crap4J XML format. |
|
949
|
|
|
--coverage-html <dir> Generate code coverage report in HTML format. |
|
950
|
|
|
--coverage-php <file> Export PHP_CodeCoverage object to file. |
|
951
|
|
|
--coverage-text=<file> Generate code coverage report in text format. |
|
952
|
|
|
Default: Standard output. |
|
953
|
|
|
--coverage-xml <dir> Generate code coverage report in PHPUnit XML format. |
|
954
|
|
|
--whitelist <dir> Whitelist <dir> for code coverage analysis. |
|
955
|
|
|
--disable-coverage-ignore Disable annotations for ignoring code coverage. |
|
956
|
|
|
|
|
957
|
|
|
Logging Options: |
|
958
|
|
|
|
|
959
|
|
|
--log-junit <file> Log test execution in JUnit XML format to file. |
|
960
|
|
|
--log-teamcity <file> Log test execution in TeamCity format to file. |
|
961
|
|
|
--testdox-html <file> Write agile documentation in HTML format to file. |
|
962
|
|
|
--testdox-text <file> Write agile documentation in Text format to file. |
|
963
|
|
|
--testdox-xml <file> Write agile documentation in XML format to file. |
|
964
|
|
|
--reverse-list Print defects in reverse order |
|
965
|
|
|
|
|
966
|
|
|
Test Selection Options: |
|
967
|
|
|
|
|
968
|
|
|
--filter <pattern> Filter which tests to run. |
|
969
|
|
|
--testsuite <name,...> Filter which testsuite to run. |
|
970
|
|
|
--group ... Only runs tests from the specified group(s). |
|
971
|
|
|
--exclude-group ... Exclude tests from the specified group(s). |
|
972
|
|
|
--list-groups List available test groups. |
|
973
|
|
|
--list-suites List available test suites. |
|
974
|
|
|
--test-suffix ... Only search for test in files with specified |
|
975
|
|
|
suffix(es). Default: Test.php,.phpt |
|
976
|
|
|
|
|
977
|
|
|
Test Execution Options: |
|
978
|
|
|
|
|
979
|
|
|
--dont-report-useless-tests Do not report tests that do not test anything. |
|
980
|
|
|
--strict-coverage Be strict about @covers annotation usage. |
|
981
|
|
|
--strict-global-state Be strict about changes to global state |
|
982
|
|
|
--disallow-test-output Be strict about output during tests. |
|
983
|
|
|
--disallow-resource-usage Be strict about resource usage during small tests. |
|
984
|
|
|
--enforce-time-limit Enforce time limit based on test size. |
|
985
|
|
|
--disallow-todo-tests Disallow @todo-annotated tests. |
|
986
|
|
|
|
|
987
|
|
|
--process-isolation Run each test in a separate PHP process. |
|
988
|
|
|
--globals-backup Backup and restore \$GLOBALS for each test. |
|
989
|
|
|
--static-backup Backup and restore static attributes for each test. |
|
990
|
|
|
|
|
991
|
|
|
--colors=<flag> Use colors in output ("never", "auto" or "always"). |
|
992
|
|
|
--columns <n> Number of columns to use for progress output. |
|
993
|
|
|
--columns max Use maximum number of columns for progress output. |
|
994
|
|
|
--stderr Write to STDERR instead of STDOUT. |
|
995
|
|
|
--stop-on-error Stop execution upon first error. |
|
996
|
|
|
--stop-on-failure Stop execution upon first error or failure. |
|
997
|
|
|
--stop-on-warning Stop execution upon first warning. |
|
998
|
|
|
--stop-on-risky Stop execution upon first risky test. |
|
999
|
|
|
--stop-on-skipped Stop execution upon first skipped test. |
|
1000
|
|
|
--stop-on-incomplete Stop execution upon first incomplete test. |
|
1001
|
|
|
--fail-on-warning Treat tests with warnings as failures. |
|
1002
|
|
|
--fail-on-risky Treat risky tests as failures. |
|
1003
|
|
|
-v|--verbose Output more verbose information. |
|
1004
|
|
|
--debug Display debugging information. |
|
1005
|
|
|
|
|
1006
|
|
|
--loader <loader> TestSuiteLoader implementation to use. |
|
1007
|
|
|
--repeat <times> Runs the test(s) repeatedly. |
|
1008
|
|
|
--teamcity Report test execution progress in TeamCity format. |
|
1009
|
|
|
--testdox Report test execution progress in TestDox format. |
|
1010
|
|
|
--testdox-group Only include tests from the specified group(s). |
|
1011
|
|
|
--testdox-exclude-group Exclude tests from the specified group(s). |
|
1012
|
|
|
--printer <printer> TestListener implementation to use. |
|
1013
|
|
|
|
|
1014
|
|
|
Configuration Options: |
|
1015
|
|
|
|
|
1016
|
|
|
--bootstrap <file> A "bootstrap" PHP file that is run before the tests. |
|
1017
|
|
|
-c|--configuration <file> Read configuration from XML file. |
|
1018
|
|
|
--no-configuration Ignore default configuration file (phpunit.xml). |
|
1019
|
|
|
--no-coverage Ignore code coverage configuration. |
|
1020
|
|
|
--no-extensions Do not load PHPUnit extensions. |
|
1021
|
|
|
--include-path <path(s)> Prepend PHP's include_path with given path(s). |
|
1022
|
|
|
-d key[=value] Sets a php.ini value. |
|
1023
|
|
|
--generate-configuration Generate configuration file with suggested settings. |
|
1024
|
|
|
|
|
1025
|
|
|
Miscellaneous Options: |
|
1026
|
|
|
|
|
1027
|
|
|
-h|--help Prints this usage information. |
|
1028
|
|
|
--version Prints the version and exits. |
|
1029
|
|
|
--atleast-version <min> Checks that version is greater than min and exits. |
|
1030
|
|
|
--check-version Check whether PHPUnit is the latest version. |
|
1031
|
|
|
|
|
1032
|
|
|
EOT; |
|
1033
|
|
|
} |
|
1034
|
|
|
|
|
1035
|
|
|
/** |
|
1036
|
|
|
* Custom callback for test suite discovery. |
|
1037
|
|
|
*/ |
|
1038
|
|
|
protected function handleCustomTestSuite() |
|
1039
|
|
|
{ |
|
1040
|
|
|
} |
|
1041
|
|
|
|
|
1042
|
|
|
private function printVersionString() |
|
1043
|
|
|
{ |
|
1044
|
|
|
if ($this->versionStringPrinted) { |
|
1045
|
|
|
return; |
|
1046
|
|
|
} |
|
1047
|
|
|
|
|
1048
|
|
|
print Version::getVersionString() . "\n\n"; |
|
1049
|
|
|
|
|
1050
|
|
|
$this->versionStringPrinted = true; |
|
1051
|
|
|
} |
|
1052
|
|
|
|
|
1053
|
|
|
/** |
|
1054
|
|
|
* @param string $message |
|
1055
|
|
|
*/ |
|
1056
|
|
|
private function showError($message) |
|
1057
|
|
|
{ |
|
1058
|
|
|
$this->printVersionString(); |
|
1059
|
|
|
|
|
1060
|
|
|
print $message . "\n"; |
|
1061
|
|
|
|
|
1062
|
|
|
exit(TestRunner::FAILURE_EXIT); |
|
1063
|
|
|
} |
|
1064
|
|
|
|
|
1065
|
|
|
/** |
|
1066
|
|
|
* @param string $directory |
|
1067
|
|
|
*/ |
|
1068
|
|
|
private function handleExtensions($directory) |
|
1069
|
|
|
{ |
|
1070
|
|
|
$facade = new File_Iterator_Facade; |
|
1071
|
|
|
|
|
1072
|
|
|
foreach ($facade->getFilesAsArray($directory, '.phar') as $file) { |
|
1073
|
|
|
if (!\file_exists('phar://' . $file . '/manifest.xml')) { |
|
1074
|
|
|
$this->arguments['notLoadedExtensions'][] = $file . ' is not an extension for PHPUnit'; |
|
1075
|
|
|
|
|
1076
|
|
|
continue; |
|
1077
|
|
|
} |
|
1078
|
|
|
|
|
1079
|
|
|
try { |
|
1080
|
|
|
$applicationName = new ApplicationName('phpunit/phpunit'); |
|
1081
|
|
|
$version = new PharIoVersion(Version::series()); |
|
1082
|
|
|
$manifest = ManifestLoader::fromFile('phar://' . $file . '/manifest.xml'); |
|
1083
|
|
|
|
|
1084
|
|
|
if (!$manifest->isExtensionFor($applicationName)) { |
|
1085
|
|
|
$this->arguments['notLoadedExtensions'][] = $file . ' is not an extension for PHPUnit'; |
|
1086
|
|
|
|
|
1087
|
|
|
continue; |
|
1088
|
|
|
} |
|
1089
|
|
|
|
|
1090
|
|
|
if (!$manifest->isExtensionFor($applicationName, $version)) { |
|
1091
|
|
|
$this->arguments['notLoadedExtensions'][] = $file . ' is not compatible with this version of PHPUnit'; |
|
1092
|
|
|
|
|
1093
|
|
|
continue; |
|
1094
|
|
|
} |
|
1095
|
|
|
} catch (ManifestException $e) { |
|
1096
|
|
|
$this->arguments['notLoadedExtensions'][] = $file . ': ' . $e->getMessage(); |
|
1097
|
|
|
|
|
1098
|
|
|
continue; |
|
1099
|
|
|
} |
|
1100
|
|
|
|
|
1101
|
|
|
require $file; |
|
1102
|
|
|
|
|
1103
|
|
|
$this->arguments['loadedExtensions'][] = $manifest->getName() . ' ' . $manifest->getVersion()->getVersionString(); |
|
1104
|
|
|
} |
|
1105
|
|
|
} |
|
1106
|
|
|
} |
|
1107
|
|
|
|
This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.
Unreachable code is most often the result of
return,dieorexitstatements that have been added for debug purposes.In the above example, the last
return falsewill never be executed, because a return statement has already been met in every possible execution path.