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