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
11use SebastianBergmann\CodeCoverage\CodeCoverage;
12use SebastianBergmann\CodeCoverage\Exception as CodeCoverageException;
13use SebastianBergmann\CodeCoverage\Filter as CodeCoverageFilter;
14use SebastianBergmann\CodeCoverage\Report\Clover as CloverReport;
15use SebastianBergmann\CodeCoverage\Report\Crap4j as Crap4jReport;
16use SebastianBergmann\CodeCoverage\Report\Html\Facade as HtmlReport;
17use SebastianBergmann\CodeCoverage\Report\PHP as PhpReport;
18use SebastianBergmann\CodeCoverage\Report\Text as TextReport;
19use SebastianBergmann\CodeCoverage\Report\Xml\Facade as XmlReport;
20use SebastianBergmann\Environment\Runtime;
21
22/**
23 * A TestRunner for the Command Line Interface (CLI)
24 * PHP SAPI Module.
25 */
26class PHPUnit_TextUI_TestRunner extends PHPUnit_Runner_BaseTestRunner
27{
28    const SUCCESS_EXIT   = 0;
29    const FAILURE_EXIT   = 1;
30    const EXCEPTION_EXIT = 2;
31
32    /**
33     * @var CodeCoverageFilter
34     */
35    protected $codeCoverageFilter;
36
37    /**
38     * @var PHPUnit_Runner_TestSuiteLoader
39     */
40    protected $loader = null;
41
42    /**
43     * @var PHPUnit_TextUI_ResultPrinter
44     */
45    protected $printer = null;
46
47    /**
48     * @var bool
49     */
50    protected static $versionStringPrinted = false;
51
52    /**
53     * @var Runtime
54     */
55    private $runtime;
56
57    /**
58     * @var bool
59     */
60    private $messagePrinted = false;
61
62    /**
63     * @param PHPUnit_Runner_TestSuiteLoader $loader
64     * @param CodeCoverageFilter             $filter
65     */
66    public function __construct(PHPUnit_Runner_TestSuiteLoader $loader = null, CodeCoverageFilter $filter = null)
67    {
68        if ($filter === null) {
69            $filter = new CodeCoverageFilter;
70        }
71
72        $this->codeCoverageFilter = $filter;
73        $this->loader             = $loader;
74        $this->runtime            = new Runtime;
75    }
76
77    /**
78     * @param PHPUnit_Framework_Test|ReflectionClass $test
79     * @param array                                  $arguments
80     *
81     * @return PHPUnit_Framework_TestResult
82     *
83     * @throws PHPUnit_Framework_Exception
84     */
85    public static function run($test, array $arguments = [])
86    {
87        if ($test instanceof ReflectionClass) {
88            $test = new PHPUnit_Framework_TestSuite($test);
89        }
90
91        if ($test instanceof PHPUnit_Framework_Test) {
92            $aTestRunner = new self;
93
94            return $aTestRunner->doRun(
95                $test,
96                $arguments
97            );
98        } else {
99            throw new PHPUnit_Framework_Exception(
100                'No test case or test suite found.'
101            );
102        }
103    }
104
105    /**
106     * @return PHPUnit_Framework_TestResult
107     */
108    protected function createTestResult()
109    {
110        return new PHPUnit_Framework_TestResult;
111    }
112
113    /**
114     * @param PHPUnit_Framework_TestSuite $suite
115     * @param array                       $arguments
116     */
117    private function processSuiteFilters(PHPUnit_Framework_TestSuite $suite, array $arguments)
118    {
119        if (!$arguments['filter'] &&
120            empty($arguments['groups']) &&
121            empty($arguments['excludeGroups'])) {
122            return;
123        }
124
125        $filterFactory = new PHPUnit_Runner_Filter_Factory();
126
127        if (!empty($arguments['excludeGroups'])) {
128            $filterFactory->addFilter(
129                new ReflectionClass('PHPUnit_Runner_Filter_Group_Exclude'),
130                $arguments['excludeGroups']
131            );
132        }
133
134        if (!empty($arguments['groups'])) {
135            $filterFactory->addFilter(
136                new ReflectionClass('PHPUnit_Runner_Filter_Group_Include'),
137                $arguments['groups']
138            );
139        }
140
141        if ($arguments['filter']) {
142            $filterFactory->addFilter(
143                new ReflectionClass('PHPUnit_Runner_Filter_Test'),
144                $arguments['filter']
145            );
146        }
147        $suite->injectFilter($filterFactory);
148    }
149
150    /**
151     * @param PHPUnit_Framework_Test $suite
152     * @param array                  $arguments
153     * @param bool                   $exit
154     *
155     * @return PHPUnit_Framework_TestResult
156     */
157    public function doRun(PHPUnit_Framework_Test $suite, array $arguments = [], $exit = true)
158    {
159        if (isset($arguments['configuration'])) {
160            $GLOBALS['__PHPUNIT_CONFIGURATION_FILE'] = $arguments['configuration'];
161        }
162
163        $this->handleConfiguration($arguments);
164
165        $this->processSuiteFilters($suite, $arguments);
166
167        if (isset($arguments['bootstrap'])) {
168            $GLOBALS['__PHPUNIT_BOOTSTRAP'] = $arguments['bootstrap'];
169        }
170
171        if ($arguments['backupGlobals'] === false) {
172            $suite->setBackupGlobals(false);
173        }
174
175        if ($arguments['backupStaticAttributes'] === true) {
176            $suite->setBackupStaticAttributes(true);
177        }
178
179        if ($arguments['beStrictAboutChangesToGlobalState'] === true) {
180            $suite->setBeStrictAboutChangesToGlobalState(true);
181        }
182
183        if (is_int($arguments['repeat'])) {
184            $test = new PHPUnit_Extensions_RepeatedTest(
185                $suite,
186                $arguments['repeat'],
187                $arguments['processIsolation']
188            );
189
190            $suite = new PHPUnit_Framework_TestSuite();
191            $suite->addTest($test);
192        }
193
194        $result = $this->createTestResult();
195
196        if (!$arguments['convertErrorsToExceptions']) {
197            $result->convertErrorsToExceptions(false);
198        }
199
200        if (!$arguments['convertNoticesToExceptions']) {
201            PHPUnit_Framework_Error_Notice::$enabled = false;
202        }
203
204        if (!$arguments['convertWarningsToExceptions']) {
205            PHPUnit_Framework_Error_Warning::$enabled = false;
206        }
207
208        if ($arguments['stopOnError']) {
209            $result->stopOnError(true);
210        }
211
212        if ($arguments['stopOnFailure']) {
213            $result->stopOnFailure(true);
214        }
215
216        if ($arguments['stopOnWarning']) {
217            $result->stopOnWarning(true);
218        }
219
220        if ($arguments['stopOnIncomplete']) {
221            $result->stopOnIncomplete(true);
222        }
223
224        if ($arguments['stopOnRisky']) {
225            $result->stopOnRisky(true);
226        }
227
228        if ($arguments['stopOnSkipped']) {
229            $result->stopOnSkipped(true);
230        }
231
232        if ($arguments['registerMockObjectsFromTestArgumentsRecursively']) {
233            $result->setRegisterMockObjectsFromTestArgumentsRecursively(true);
234        }
235
236        if ($this->printer === null) {
237            if (isset($arguments['printer']) &&
238                $arguments['printer'] instanceof PHPUnit_Util_Printer) {
239                $this->printer = $arguments['printer'];
240            } else {
241                $printerClass = 'PHPUnit_TextUI_ResultPrinter';
242
243                if (isset($arguments['printer']) &&
244                    is_string($arguments['printer']) &&
245                    class_exists($arguments['printer'], false)) {
246                    $class = new ReflectionClass($arguments['printer']);
247
248                    if ($class->isSubclassOf('PHPUnit_TextUI_ResultPrinter')) {
249                        $printerClass = $arguments['printer'];
250                    }
251                }
252
253                $this->printer = new $printerClass(
254                    (isset($arguments['stderr']) && $arguments['stderr'] === true) ? 'php://stderr' : null,
255                    $arguments['verbose'],
256                    $arguments['colors'],
257                    $arguments['debug'],
258                    $arguments['columns'],
259                    $arguments['reverseList']
260                );
261            }
262        }
263
264        if (!$this->printer instanceof PHPUnit_Util_Log_TAP) {
265            $this->printer->write(
266                PHPUnit_Runner_Version::getVersionString() . "\n"
267            );
268
269            self::$versionStringPrinted = true;
270
271            if ($arguments['verbose']) {
272                $runtime = $this->runtime->getNameWithVersion();
273
274                if ($this->runtime->hasXdebug()) {
275                    $runtime .= sprintf(
276                        ' with Xdebug %s',
277                        phpversion('xdebug')
278                    );
279                }
280
281                $this->writeMessage('Runtime', $runtime);
282
283                if (isset($arguments['configuration'])) {
284                    $this->writeMessage(
285                        'Configuration',
286                        $arguments['configuration']->getFilename()
287                    );
288                }
289
290                foreach ($arguments['loadedExtensions'] as $extension) {
291                    $this->writeMessage(
292                        'Extension',
293                        $extension
294                    );
295                }
296
297                foreach ($arguments['notLoadedExtensions'] as $extension) {
298                    $this->writeMessage(
299                        'Extension',
300                        $extension
301                    );
302                }
303            }
304
305            if (isset($arguments['deprecatedCheckForUnintentionallyCoveredCodeSettingUsed'])) {
306                $this->writeMessage('Warning', 'Deprecated configuration setting "checkForUnintentionallyCoveredCode" used');
307            }
308
309            if (isset($arguments['tapLogfile'])) {
310                $this->writeMessage('Warning', 'Deprecated TAP test listener used');
311            }
312
313            if (isset($arguments['jsonLogfile'])) {
314                $this->writeMessage('Warning', 'Deprecated JSON test listener used');
315            }
316        }
317
318        foreach ($arguments['listeners'] as $listener) {
319            $result->addListener($listener);
320        }
321
322        $result->addListener($this->printer);
323
324        if (isset($arguments['testdoxHTMLFile'])) {
325            $result->addListener(
326                new PHPUnit_Util_TestDox_ResultPrinter_HTML(
327                    $arguments['testdoxHTMLFile'],
328                    $arguments['testdoxGroups'],
329                    $arguments['testdoxExcludeGroups']
330                )
331            );
332        }
333
334        if (isset($arguments['testdoxTextFile'])) {
335            $result->addListener(
336                new PHPUnit_Util_TestDox_ResultPrinter_Text(
337                    $arguments['testdoxTextFile'],
338                    $arguments['testdoxGroups'],
339                    $arguments['testdoxExcludeGroups']
340                )
341            );
342        }
343
344        if (isset($arguments['testdoxXMLFile'])) {
345            $result->addListener(
346                new PHPUnit_Util_TestDox_ResultPrinter_XML(
347                    $arguments['testdoxXMLFile']
348                )
349            );
350        }
351
352        $codeCoverageReports = 0;
353
354        if (isset($arguments['coverageClover'])) {
355            $codeCoverageReports++;
356        }
357
358        if (isset($arguments['coverageCrap4J'])) {
359            $codeCoverageReports++;
360        }
361
362        if (isset($arguments['coverageHtml'])) {
363            $codeCoverageReports++;
364        }
365
366        if (isset($arguments['coveragePHP'])) {
367            $codeCoverageReports++;
368        }
369
370        if (isset($arguments['coverageText'])) {
371            $codeCoverageReports++;
372        }
373
374        if (isset($arguments['coverageXml'])) {
375            $codeCoverageReports++;
376        }
377
378        if (isset($arguments['noCoverage'])) {
379            $codeCoverageReports = 0;
380        }
381
382        if ($codeCoverageReports > 0 && !$this->runtime->canCollectCodeCoverage()) {
383            $this->writeMessage('Error', 'No code coverage driver is available');
384
385            $codeCoverageReports = 0;
386        }
387
388        if (!$this->printer instanceof PHPUnit_Util_Log_TAP) {
389            $this->printer->write("\n");
390        }
391
392        if ($codeCoverageReports > 0) {
393            $codeCoverage = new CodeCoverage(
394                null,
395                $this->codeCoverageFilter
396            );
397
398            $codeCoverage->setUnintentionallyCoveredSubclassesWhitelist(
399                [SebastianBergmann\Comparator\Comparator::class]
400            );
401
402            $codeCoverage->setCheckForUnintentionallyCoveredCode(
403                $arguments['strictCoverage']
404            );
405
406            $codeCoverage->setCheckForMissingCoversAnnotation(
407                $arguments['strictCoverage']
408            );
409
410            if (isset($arguments['forceCoversAnnotation'])) {
411                $codeCoverage->setForceCoversAnnotation(
412                    $arguments['forceCoversAnnotation']
413                );
414            }
415
416            if (isset($arguments['disableCodeCoverageIgnore'])) {
417                $codeCoverage->setDisableIgnoredLines(true);
418            }
419
420            if (isset($arguments['whitelist'])) {
421                $this->codeCoverageFilter->addDirectoryToWhitelist($arguments['whitelist']);
422            }
423
424            if (isset($arguments['configuration'])) {
425                $filterConfiguration = $arguments['configuration']->getFilterConfiguration();
426
427                $codeCoverage->setAddUncoveredFilesFromWhitelist(
428                    $filterConfiguration['whitelist']['addUncoveredFilesFromWhitelist']
429                );
430
431                $codeCoverage->setProcessUncoveredFilesFromWhitelist(
432                    $filterConfiguration['whitelist']['processUncoveredFilesFromWhitelist']
433                );
434
435                foreach ($filterConfiguration['whitelist']['include']['directory'] as $dir) {
436                    $this->codeCoverageFilter->addDirectoryToWhitelist(
437                        $dir['path'],
438                        $dir['suffix'],
439                        $dir['prefix']
440                    );
441                }
442
443                foreach ($filterConfiguration['whitelist']['include']['file'] as $file) {
444                    $this->codeCoverageFilter->addFileToWhitelist($file);
445                }
446
447                foreach ($filterConfiguration['whitelist']['exclude']['directory'] as $dir) {
448                    $this->codeCoverageFilter->removeDirectoryFromWhitelist(
449                        $dir['path'],
450                        $dir['suffix'],
451                        $dir['prefix']
452                    );
453                }
454
455                foreach ($filterConfiguration['whitelist']['exclude']['file'] as $file) {
456                    $this->codeCoverageFilter->removeFileFromWhitelist($file);
457                }
458            }
459
460            if (!$this->codeCoverageFilter->hasWhitelist()) {
461                $this->writeMessage('Error', 'No whitelist configured, no code coverage will be generated');
462
463                $codeCoverageReports = 0;
464
465                unset($codeCoverage);
466            }
467        }
468
469        if (isset($codeCoverage)) {
470            $result->setCodeCoverage($codeCoverage);
471
472            if ($codeCoverageReports > 1 && isset($arguments['cacheTokens'])) {
473                $codeCoverage->setCacheTokens($arguments['cacheTokens']);
474            }
475        }
476
477        if (isset($arguments['jsonLogfile'])) {
478            $result->addListener(
479                new PHPUnit_Util_Log_JSON($arguments['jsonLogfile'])
480            );
481        }
482
483        if (isset($arguments['tapLogfile'])) {
484            $result->addListener(
485                new PHPUnit_Util_Log_TAP($arguments['tapLogfile'])
486            );
487        }
488
489        if (isset($arguments['teamcityLogfile'])) {
490            $result->addListener(
491                new PHPUnit_Util_Log_TeamCity($arguments['teamcityLogfile'])
492            );
493        }
494
495        if (isset($arguments['junitLogfile'])) {
496            $result->addListener(
497                new PHPUnit_Util_Log_JUnit(
498                    $arguments['junitLogfile'],
499                    $arguments['logIncompleteSkipped']
500                )
501            );
502        }
503
504        $result->beStrictAboutTestsThatDoNotTestAnything($arguments['reportUselessTests']);
505        $result->beStrictAboutOutputDuringTests($arguments['disallowTestOutput']);
506        $result->beStrictAboutTodoAnnotatedTests($arguments['disallowTodoAnnotatedTests']);
507        $result->beStrictAboutResourceUsageDuringSmallTests($arguments['beStrictAboutResourceUsageDuringSmallTests']);
508        $result->enforceTimeLimit($arguments['enforceTimeLimit']);
509        $result->setTimeoutForSmallTests($arguments['timeoutForSmallTests']);
510        $result->setTimeoutForMediumTests($arguments['timeoutForMediumTests']);
511        $result->setTimeoutForLargeTests($arguments['timeoutForLargeTests']);
512
513        if ($suite instanceof PHPUnit_Framework_TestSuite) {
514            $suite->setRunTestInSeparateProcess($arguments['processIsolation']);
515        }
516
517        $suite->run($result);
518
519        unset($suite);
520        $result->flushListeners();
521
522        if ($this->printer instanceof PHPUnit_TextUI_ResultPrinter) {
523            $this->printer->printResult($result);
524        }
525
526        if (isset($codeCoverage)) {
527            if (isset($arguments['coverageClover'])) {
528                $this->printer->write(
529                    "\nGenerating code coverage report in Clover XML format ..."
530                );
531
532                try {
533                    $writer = new CloverReport();
534                    $writer->process($codeCoverage, $arguments['coverageClover']);
535
536                    $this->printer->write(" done\n");
537                    unset($writer);
538                } catch (CodeCoverageException $e) {
539                    $this->printer->write(
540                        " failed\n" . $e->getMessage() . "\n"
541                    );
542                }
543            }
544
545            if (isset($arguments['coverageCrap4J'])) {
546                $this->printer->write(
547                    "\nGenerating Crap4J report XML file ..."
548                );
549
550                try {
551                    $writer = new Crap4jReport($arguments['crap4jThreshold']);
552                    $writer->process($codeCoverage, $arguments['coverageCrap4J']);
553
554                    $this->printer->write(" done\n");
555                    unset($writer);
556                } catch (CodeCoverageException $e) {
557                    $this->printer->write(
558                        " failed\n" . $e->getMessage() . "\n"
559                    );
560                }
561            }
562
563            if (isset($arguments['coverageHtml'])) {
564                $this->printer->write(
565                    "\nGenerating code coverage report in HTML format ..."
566                );
567
568                try {
569                    $writer = new HtmlReport(
570                        $arguments['reportLowUpperBound'],
571                        $arguments['reportHighLowerBound'],
572                        sprintf(
573                            ' and <a href="https://phpunit.de/">PHPUnit %s</a>',
574                            PHPUnit_Runner_Version::id()
575                        )
576                    );
577
578                    $writer->process($codeCoverage, $arguments['coverageHtml']);
579
580                    $this->printer->write(" done\n");
581                    unset($writer);
582                } catch (CodeCoverageException $e) {
583                    $this->printer->write(
584                        " failed\n" . $e->getMessage() . "\n"
585                    );
586                }
587            }
588
589            if (isset($arguments['coveragePHP'])) {
590                $this->printer->write(
591                    "\nGenerating code coverage report in PHP format ..."
592                );
593
594                try {
595                    $writer = new PhpReport();
596                    $writer->process($codeCoverage, $arguments['coveragePHP']);
597
598                    $this->printer->write(" done\n");
599                    unset($writer);
600                } catch (CodeCoverageException $e) {
601                    $this->printer->write(
602                        " failed\n" . $e->getMessage() . "\n"
603                    );
604                }
605            }
606
607            if (isset($arguments['coverageText'])) {
608                if ($arguments['coverageText'] == 'php://stdout') {
609                    $outputStream = $this->printer;
610                    $colors       = $arguments['colors'] && $arguments['colors'] != PHPUnit_TextUI_ResultPrinter::COLOR_NEVER;
611                } else {
612                    $outputStream = new PHPUnit_Util_Printer($arguments['coverageText']);
613                    $colors       = false;
614                }
615
616                $processor = new TextReport(
617                    $arguments['reportLowUpperBound'],
618                    $arguments['reportHighLowerBound'],
619                    $arguments['coverageTextShowUncoveredFiles'],
620                    $arguments['coverageTextShowOnlySummary']
621                );
622
623                $outputStream->write(
624                    $processor->process($codeCoverage, $colors)
625                );
626            }
627
628            if (isset($arguments['coverageXml'])) {
629                $this->printer->write(
630                    "\nGenerating code coverage report in PHPUnit XML format ..."
631                );
632
633                try {
634                    $writer = new XmlReport;
635                    $writer->process($codeCoverage, $arguments['coverageXml']);
636
637                    $this->printer->write(" done\n");
638                    unset($writer);
639                } catch (CodeCoverageException $e) {
640                    $this->printer->write(
641                        " failed\n" . $e->getMessage() . "\n"
642                    );
643                }
644            }
645        }
646
647        if ($exit) {
648            if ($result->wasSuccessful(false)) {
649                if ($arguments['failOnRisky'] && !$result->allHarmless()) {
650                    exit(self::FAILURE_EXIT);
651                }
652
653                if ($arguments['failOnWarning'] && $result->warningCount() > 0) {
654                    exit(self::FAILURE_EXIT);
655                }
656
657                exit(self::SUCCESS_EXIT);
658            }
659
660            if ($result->errorCount() > 0) {
661                exit(self::EXCEPTION_EXIT);
662            }
663
664            if ($result->failureCount() > 0) {
665                exit(self::FAILURE_EXIT);
666            }
667        }
668
669        return $result;
670    }
671
672    /**
673     * @param PHPUnit_TextUI_ResultPrinter $resultPrinter
674     */
675    public function setPrinter(PHPUnit_TextUI_ResultPrinter $resultPrinter)
676    {
677        $this->printer = $resultPrinter;
678    }
679
680    /**
681     * Override to define how to handle a failed loading of
682     * a test suite.
683     *
684     * @param string $message
685     */
686    protected function runFailed($message)
687    {
688        $this->write($message . PHP_EOL);
689        exit(self::FAILURE_EXIT);
690    }
691
692    /**
693     * @param string $buffer
694     */
695    protected function write($buffer)
696    {
697        if (PHP_SAPI != 'cli' && PHP_SAPI != 'phpdbg') {
698            $buffer = htmlspecialchars($buffer);
699        }
700
701        if ($this->printer !== null) {
702            $this->printer->write($buffer);
703        } else {
704            print $buffer;
705        }
706    }
707
708    /**
709     * Returns the loader to be used.
710     *
711     * @return PHPUnit_Runner_TestSuiteLoader
712     */
713    public function getLoader()
714    {
715        if ($this->loader === null) {
716            $this->loader = new PHPUnit_Runner_StandardTestSuiteLoader;
717        }
718
719        return $this->loader;
720    }
721
722    /**
723     * @param array $arguments
724     */
725    protected function handleConfiguration(array &$arguments)
726    {
727        if (isset($arguments['configuration']) &&
728            !$arguments['configuration'] instanceof PHPUnit_Util_Configuration) {
729            $arguments['configuration'] = PHPUnit_Util_Configuration::getInstance(
730                $arguments['configuration']
731            );
732        }
733
734        $arguments['debug']     = isset($arguments['debug'])     ? $arguments['debug']     : false;
735        $arguments['filter']    = isset($arguments['filter'])    ? $arguments['filter']    : false;
736        $arguments['listeners'] = isset($arguments['listeners']) ? $arguments['listeners'] : [];
737
738        if (isset($arguments['configuration'])) {
739            $arguments['configuration']->handlePHPConfiguration();
740
741            $phpunitConfiguration = $arguments['configuration']->getPHPUnitConfiguration();
742
743            if (isset($phpunitConfiguration['deprecatedCheckForUnintentionallyCoveredCodeSettingUsed'])) {
744                $arguments['deprecatedCheckForUnintentionallyCoveredCodeSettingUsed'] = true;
745            }
746
747            if (isset($phpunitConfiguration['backupGlobals']) &&
748                !isset($arguments['backupGlobals'])) {
749                $arguments['backupGlobals'] = $phpunitConfiguration['backupGlobals'];
750            }
751
752            if (isset($phpunitConfiguration['backupStaticAttributes']) &&
753                !isset($arguments['backupStaticAttributes'])) {
754                $arguments['backupStaticAttributes'] = $phpunitConfiguration['backupStaticAttributes'];
755            }
756
757            if (isset($phpunitConfiguration['beStrictAboutChangesToGlobalState']) &&
758                !isset($arguments['beStrictAboutChangesToGlobalState'])) {
759                $arguments['beStrictAboutChangesToGlobalState'] = $phpunitConfiguration['beStrictAboutChangesToGlobalState'];
760            }
761
762            if (isset($phpunitConfiguration['bootstrap']) &&
763                !isset($arguments['bootstrap'])) {
764                $arguments['bootstrap'] = $phpunitConfiguration['bootstrap'];
765            }
766
767            if (isset($phpunitConfiguration['cacheTokens']) &&
768                !isset($arguments['cacheTokens'])) {
769                $arguments['cacheTokens'] = $phpunitConfiguration['cacheTokens'];
770            }
771
772            if (isset($phpunitConfiguration['colors']) &&
773                !isset($arguments['colors'])) {
774                $arguments['colors'] = $phpunitConfiguration['colors'];
775            }
776
777            if (isset($phpunitConfiguration['convertErrorsToExceptions']) &&
778                !isset($arguments['convertErrorsToExceptions'])) {
779                $arguments['convertErrorsToExceptions'] = $phpunitConfiguration['convertErrorsToExceptions'];
780            }
781
782            if (isset($phpunitConfiguration['convertNoticesToExceptions']) &&
783                !isset($arguments['convertNoticesToExceptions'])) {
784                $arguments['convertNoticesToExceptions'] = $phpunitConfiguration['convertNoticesToExceptions'];
785            }
786
787            if (isset($phpunitConfiguration['convertWarningsToExceptions']) &&
788                !isset($arguments['convertWarningsToExceptions'])) {
789                $arguments['convertWarningsToExceptions'] = $phpunitConfiguration['convertWarningsToExceptions'];
790            }
791
792            if (isset($phpunitConfiguration['processIsolation']) &&
793                !isset($arguments['processIsolation'])) {
794                $arguments['processIsolation'] = $phpunitConfiguration['processIsolation'];
795            }
796
797            if (isset($phpunitConfiguration['stopOnError']) &&
798                !isset($arguments['stopOnError'])) {
799                $arguments['stopOnError'] = $phpunitConfiguration['stopOnError'];
800            }
801
802            if (isset($phpunitConfiguration['stopOnFailure']) &&
803                !isset($arguments['stopOnFailure'])) {
804                $arguments['stopOnFailure'] = $phpunitConfiguration['stopOnFailure'];
805            }
806
807            if (isset($phpunitConfiguration['stopOnWarning']) &&
808                !isset($arguments['stopOnWarning'])) {
809                $arguments['stopOnWarning'] = $phpunitConfiguration['stopOnWarning'];
810            }
811
812            if (isset($phpunitConfiguration['stopOnIncomplete']) &&
813                !isset($arguments['stopOnIncomplete'])) {
814                $arguments['stopOnIncomplete'] = $phpunitConfiguration['stopOnIncomplete'];
815            }
816
817            if (isset($phpunitConfiguration['stopOnRisky']) &&
818                !isset($arguments['stopOnRisky'])) {
819                $arguments['stopOnRisky'] = $phpunitConfiguration['stopOnRisky'];
820            }
821
822            if (isset($phpunitConfiguration['stopOnSkipped']) &&
823                !isset($arguments['stopOnSkipped'])) {
824                $arguments['stopOnSkipped'] = $phpunitConfiguration['stopOnSkipped'];
825            }
826
827            if (isset($phpunitConfiguration['failOnWarning']) &&
828                !isset($arguments['failOnWarning'])) {
829                $arguments['failOnWarning'] = $phpunitConfiguration['failOnWarning'];
830            }
831
832            if (isset($phpunitConfiguration['failOnRisky']) &&
833                !isset($arguments['failOnRisky'])) {
834                $arguments['failOnRisky'] = $phpunitConfiguration['failOnRisky'];
835            }
836
837            if (isset($phpunitConfiguration['timeoutForSmallTests']) &&
838                !isset($arguments['timeoutForSmallTests'])) {
839                $arguments['timeoutForSmallTests'] = $phpunitConfiguration['timeoutForSmallTests'];
840            }
841
842            if (isset($phpunitConfiguration['timeoutForMediumTests']) &&
843                !isset($arguments['timeoutForMediumTests'])) {
844                $arguments['timeoutForMediumTests'] = $phpunitConfiguration['timeoutForMediumTests'];
845            }
846
847            if (isset($phpunitConfiguration['timeoutForLargeTests']) &&
848                !isset($arguments['timeoutForLargeTests'])) {
849                $arguments['timeoutForLargeTests'] = $phpunitConfiguration['timeoutForLargeTests'];
850            }
851
852            if (isset($phpunitConfiguration['reportUselessTests']) &&
853                !isset($arguments['reportUselessTests'])) {
854                $arguments['reportUselessTests'] = $phpunitConfiguration['reportUselessTests'];
855            }
856
857            if (isset($phpunitConfiguration['strictCoverage']) &&
858                !isset($arguments['strictCoverage'])) {
859                $arguments['strictCoverage'] = $phpunitConfiguration['strictCoverage'];
860            }
861
862            if (isset($phpunitConfiguration['disallowTestOutput']) &&
863                !isset($arguments['disallowTestOutput'])) {
864                $arguments['disallowTestOutput'] = $phpunitConfiguration['disallowTestOutput'];
865            }
866
867            if (isset($phpunitConfiguration['enforceTimeLimit']) &&
868                !isset($arguments['enforceTimeLimit'])) {
869                $arguments['enforceTimeLimit'] = $phpunitConfiguration['enforceTimeLimit'];
870            }
871
872            if (isset($phpunitConfiguration['disallowTodoAnnotatedTests']) &&
873                !isset($arguments['disallowTodoAnnotatedTests'])) {
874                $arguments['disallowTodoAnnotatedTests'] = $phpunitConfiguration['disallowTodoAnnotatedTests'];
875            }
876
877            if (isset($phpunitConfiguration['beStrictAboutResourceUsageDuringSmallTests']) &&
878                !isset($arguments['beStrictAboutResourceUsageDuringSmallTests'])) {
879                $arguments['beStrictAboutResourceUsageDuringSmallTests'] = $phpunitConfiguration['beStrictAboutResourceUsageDuringSmallTests'];
880            }
881
882            if (isset($phpunitConfiguration['verbose']) &&
883                !isset($arguments['verbose'])) {
884                $arguments['verbose'] = $phpunitConfiguration['verbose'];
885            }
886
887            if (isset($phpunitConfiguration['reverseDefectList']) &&
888                !isset($arguments['reverseList'])) {
889                $arguments['reverseList'] = $phpunitConfiguration['reverseDefectList'];
890            }
891
892            if (isset($phpunitConfiguration['forceCoversAnnotation']) &&
893                !isset($arguments['forceCoversAnnotation'])) {
894                $arguments['forceCoversAnnotation'] = $phpunitConfiguration['forceCoversAnnotation'];
895            }
896
897            if (isset($phpunitConfiguration['disableCodeCoverageIgnore']) &&
898                !isset($arguments['disableCodeCoverageIgnore'])) {
899                $arguments['disableCodeCoverageIgnore'] = $phpunitConfiguration['disableCodeCoverageIgnore'];
900            }
901
902            if (isset($phpunitConfiguration['registerMockObjectsFromTestArgumentsRecursively']) &&
903                !isset($arguments['registerMockObjectsFromTestArgumentsRecursively'])) {
904                $arguments['registerMockObjectsFromTestArgumentsRecursively'] = $phpunitConfiguration['registerMockObjectsFromTestArgumentsRecursively'];
905            }
906
907            $groupCliArgs = [];
908
909            if (!empty($arguments['groups'])) {
910                $groupCliArgs = $arguments['groups'];
911            }
912
913            $groupConfiguration = $arguments['configuration']->getGroupConfiguration();
914
915            if (!empty($groupConfiguration['include']) &&
916                !isset($arguments['groups'])) {
917                $arguments['groups'] = $groupConfiguration['include'];
918            }
919
920            if (!empty($groupConfiguration['exclude']) &&
921                !isset($arguments['excludeGroups'])) {
922                $arguments['excludeGroups'] = array_diff($groupConfiguration['exclude'], $groupCliArgs);
923            }
924
925            foreach ($arguments['configuration']->getListenerConfiguration() as $listener) {
926                if (!class_exists($listener['class'], false) &&
927                    $listener['file'] !== '') {
928                    require_once $listener['file'];
929                }
930
931                if (!class_exists($listener['class'])) {
932                    throw new PHPUnit_Framework_Exception(
933                        sprintf(
934                            'Class "%s" does not exist',
935                            $listener['class']
936                        )
937                    );
938                }
939
940                $listenerClass = new ReflectionClass($listener['class']);
941
942                if (!$listenerClass->implementsInterface(PHPUnit_Framework_TestListener::class)) {
943                    throw new PHPUnit_Framework_Exception(
944                        sprintf(
945                            'Class "%s" does not implement the PHPUnit_Framework_TestListener interface',
946                            $listener['class']
947                        )
948                    );
949                }
950
951                if (count($listener['arguments']) == 0) {
952                    $listener = new $listener['class'];
953                } else {
954                    $listener = $listenerClass->newInstanceArgs(
955                        $listener['arguments']
956                    );
957                }
958
959                $arguments['listeners'][] = $listener;
960            }
961
962            $loggingConfiguration = $arguments['configuration']->getLoggingConfiguration();
963
964            if (isset($loggingConfiguration['coverage-clover']) &&
965                !isset($arguments['coverageClover'])) {
966                $arguments['coverageClover'] = $loggingConfiguration['coverage-clover'];
967            }
968
969            if (isset($loggingConfiguration['coverage-crap4j']) &&
970                !isset($arguments['coverageCrap4J'])) {
971                $arguments['coverageCrap4J'] = $loggingConfiguration['coverage-crap4j'];
972
973                if (isset($loggingConfiguration['crap4jThreshold']) &&
974                    !isset($arguments['crap4jThreshold'])) {
975                    $arguments['crap4jThreshold'] = $loggingConfiguration['crap4jThreshold'];
976                }
977            }
978
979            if (isset($loggingConfiguration['coverage-html']) &&
980                !isset($arguments['coverageHtml'])) {
981                if (isset($loggingConfiguration['lowUpperBound']) &&
982                    !isset($arguments['reportLowUpperBound'])) {
983                    $arguments['reportLowUpperBound'] = $loggingConfiguration['lowUpperBound'];
984                }
985
986                if (isset($loggingConfiguration['highLowerBound']) &&
987                    !isset($arguments['reportHighLowerBound'])) {
988                    $arguments['reportHighLowerBound'] = $loggingConfiguration['highLowerBound'];
989                }
990
991                $arguments['coverageHtml'] = $loggingConfiguration['coverage-html'];
992            }
993
994            if (isset($loggingConfiguration['coverage-php']) &&
995                !isset($arguments['coveragePHP'])) {
996                $arguments['coveragePHP'] = $loggingConfiguration['coverage-php'];
997            }
998
999            if (isset($loggingConfiguration['coverage-text']) &&
1000                !isset($arguments['coverageText'])) {
1001                $arguments['coverageText'] = $loggingConfiguration['coverage-text'];
1002                if (isset($loggingConfiguration['coverageTextShowUncoveredFiles'])) {
1003                    $arguments['coverageTextShowUncoveredFiles'] = $loggingConfiguration['coverageTextShowUncoveredFiles'];
1004                } else {
1005                    $arguments['coverageTextShowUncoveredFiles'] = false;
1006                }
1007                if (isset($loggingConfiguration['coverageTextShowOnlySummary'])) {
1008                    $arguments['coverageTextShowOnlySummary'] = $loggingConfiguration['coverageTextShowOnlySummary'];
1009                } else {
1010                    $arguments['coverageTextShowOnlySummary'] = false;
1011                }
1012            }
1013
1014            if (isset($loggingConfiguration['coverage-xml']) &&
1015                !isset($arguments['coverageXml'])) {
1016                $arguments['coverageXml'] = $loggingConfiguration['coverage-xml'];
1017            }
1018
1019            if (isset($loggingConfiguration['json']) &&
1020                !isset($arguments['jsonLogfile'])) {
1021                $arguments['jsonLogfile'] = $loggingConfiguration['json'];
1022            }
1023
1024            if (isset($loggingConfiguration['plain'])) {
1025                $arguments['listeners'][] = new PHPUnit_TextUI_ResultPrinter(
1026                    $loggingConfiguration['plain'],
1027                    true
1028                );
1029            }
1030
1031            if (isset($loggingConfiguration['tap']) &&
1032                !isset($arguments['tapLogfile'])) {
1033                $arguments['tapLogfile'] = $loggingConfiguration['tap'];
1034            }
1035
1036            if (isset($loggingConfiguration['teamcity']) &&
1037                !isset($arguments['teamcityLogfile'])) {
1038                $arguments['teamcityLogfile'] = $loggingConfiguration['teamcity'];
1039            }
1040
1041            if (isset($loggingConfiguration['junit']) &&
1042                !isset($arguments['junitLogfile'])) {
1043                $arguments['junitLogfile'] = $loggingConfiguration['junit'];
1044
1045                if (isset($loggingConfiguration['logIncompleteSkipped']) &&
1046                    !isset($arguments['logIncompleteSkipped'])) {
1047                    $arguments['logIncompleteSkipped'] = $loggingConfiguration['logIncompleteSkipped'];
1048                }
1049            }
1050
1051            if (isset($loggingConfiguration['testdox-html']) &&
1052                !isset($arguments['testdoxHTMLFile'])) {
1053                $arguments['testdoxHTMLFile'] = $loggingConfiguration['testdox-html'];
1054            }
1055
1056            if (isset($loggingConfiguration['testdox-text']) &&
1057                !isset($arguments['testdoxTextFile'])) {
1058                $arguments['testdoxTextFile'] = $loggingConfiguration['testdox-text'];
1059            }
1060
1061            if (isset($loggingConfiguration['testdox-xml']) &&
1062                !isset($arguments['testdoxXMLFile'])) {
1063                $arguments['testdoxXMLFile'] = $loggingConfiguration['testdox-xml'];
1064            }
1065
1066            $testdoxGroupConfiguration = $arguments['configuration']->getTestdoxGroupConfiguration();
1067
1068            if (isset($testdoxGroupConfiguration['include']) &&
1069                !isset($arguments['testdoxGroups'])) {
1070                $arguments['testdoxGroups'] = $testdoxGroupConfiguration['include'];
1071            }
1072
1073            if (isset($testdoxGroupConfiguration['exclude']) &&
1074                !isset($arguments['testdoxExcludeGroups'])) {
1075                $arguments['testdoxExcludeGroups'] = $testdoxGroupConfiguration['exclude'];
1076            }
1077        }
1078
1079        $arguments['addUncoveredFilesFromWhitelist']                  = isset($arguments['addUncoveredFilesFromWhitelist'])                  ? $arguments['addUncoveredFilesFromWhitelist']                  : true;
1080        $arguments['processUncoveredFilesFromWhitelist']              = isset($arguments['processUncoveredFilesFromWhitelist'])              ? $arguments['processUncoveredFilesFromWhitelist']              : false;
1081        $arguments['backupGlobals']                                   = isset($arguments['backupGlobals'])                                   ? $arguments['backupGlobals']                                   : null;
1082        $arguments['backupStaticAttributes']                          = isset($arguments['backupStaticAttributes'])                          ? $arguments['backupStaticAttributes']                          : null;
1083        $arguments['beStrictAboutChangesToGlobalState']               = isset($arguments['beStrictAboutChangesToGlobalState'])               ? $arguments['beStrictAboutChangesToGlobalState']               : null;
1084        $arguments['cacheTokens']                                     = isset($arguments['cacheTokens'])                                     ? $arguments['cacheTokens']                                     : false;
1085        $arguments['columns']                                         = isset($arguments['columns'])                                         ? $arguments['columns']                                         : 80;
1086        $arguments['colors']                                          = isset($arguments['colors'])                                          ? $arguments['colors']                                          : PHPUnit_TextUI_ResultPrinter::COLOR_DEFAULT;
1087        $arguments['convertErrorsToExceptions']                       = isset($arguments['convertErrorsToExceptions'])                       ? $arguments['convertErrorsToExceptions']                       : true;
1088        $arguments['convertNoticesToExceptions']                      = isset($arguments['convertNoticesToExceptions'])                      ? $arguments['convertNoticesToExceptions']                      : true;
1089        $arguments['convertWarningsToExceptions']                     = isset($arguments['convertWarningsToExceptions'])                     ? $arguments['convertWarningsToExceptions']                     : true;
1090        $arguments['excludeGroups']                                   = isset($arguments['excludeGroups'])                                   ? $arguments['excludeGroups']                                   : [];
1091        $arguments['groups']                                          = isset($arguments['groups'])                                          ? $arguments['groups']                                          : [];
1092        $arguments['logIncompleteSkipped']                            = isset($arguments['logIncompleteSkipped'])                            ? $arguments['logIncompleteSkipped']                            : false;
1093        $arguments['processIsolation']                                = isset($arguments['processIsolation'])                                ? $arguments['processIsolation']                                : false;
1094        $arguments['repeat']                                          = isset($arguments['repeat'])                                          ? $arguments['repeat']                                          : false;
1095        $arguments['reportHighLowerBound']                            = isset($arguments['reportHighLowerBound'])                            ? $arguments['reportHighLowerBound']                            : 90;
1096        $arguments['reportLowUpperBound']                             = isset($arguments['reportLowUpperBound'])                             ? $arguments['reportLowUpperBound']                             : 50;
1097        $arguments['crap4jThreshold']                                 = isset($arguments['crap4jThreshold'])                                 ? $arguments['crap4jThreshold']                                 : 30;
1098        $arguments['stopOnError']                                     = isset($arguments['stopOnError'])                                     ? $arguments['stopOnError']                                     : false;
1099        $arguments['stopOnFailure']                                   = isset($arguments['stopOnFailure'])                                   ? $arguments['stopOnFailure']                                   : false;
1100        $arguments['stopOnWarning']                                   = isset($arguments['stopOnWarning'])                                   ? $arguments['stopOnWarning']                                   : false;
1101        $arguments['stopOnIncomplete']                                = isset($arguments['stopOnIncomplete'])                                ? $arguments['stopOnIncomplete']                                : false;
1102        $arguments['stopOnRisky']                                     = isset($arguments['stopOnRisky'])                                     ? $arguments['stopOnRisky']                                     : false;
1103        $arguments['stopOnSkipped']                                   = isset($arguments['stopOnSkipped'])                                   ? $arguments['stopOnSkipped']                                   : false;
1104        $arguments['failOnWarning']                                   = isset($arguments['failOnWarning'])                                   ? $arguments['failOnWarning']                                   : false;
1105        $arguments['failOnRisky']                                     = isset($arguments['failOnRisky'])                                     ? $arguments['failOnRisky']                                     : false;
1106        $arguments['timeoutForSmallTests']                            = isset($arguments['timeoutForSmallTests'])                            ? $arguments['timeoutForSmallTests']                            : 1;
1107        $arguments['timeoutForMediumTests']                           = isset($arguments['timeoutForMediumTests'])                           ? $arguments['timeoutForMediumTests']                           : 10;
1108        $arguments['timeoutForLargeTests']                            = isset($arguments['timeoutForLargeTests'])                            ? $arguments['timeoutForLargeTests']                            : 60;
1109        $arguments['reportUselessTests']                              = isset($arguments['reportUselessTests'])                              ? $arguments['reportUselessTests']                              : false;
1110        $arguments['strictCoverage']                                  = isset($arguments['strictCoverage'])                                  ? $arguments['strictCoverage']                                  : false;
1111        $arguments['disallowTestOutput']                              = isset($arguments['disallowTestOutput'])                              ? $arguments['disallowTestOutput']                              : false;
1112        $arguments['enforceTimeLimit']                                = isset($arguments['enforceTimeLimit'])                                ? $arguments['enforceTimeLimit']                                : false;
1113        $arguments['disallowTodoAnnotatedTests']                      = isset($arguments['disallowTodoAnnotatedTests'])                      ? $arguments['disallowTodoAnnotatedTests']                      : false;
1114        $arguments['beStrictAboutResourceUsageDuringSmallTests']      = isset($arguments['beStrictAboutResourceUsageDuringSmallTests'])      ? $arguments['beStrictAboutResourceUsageDuringSmallTests']      : false;
1115        $arguments['reverseList']                                     = isset($arguments['reverseList'])                                     ? $arguments['reverseList']                                     : false;
1116        $arguments['registerMockObjectsFromTestArgumentsRecursively'] = isset($arguments['registerMockObjectsFromTestArgumentsRecursively']) ? $arguments['registerMockObjectsFromTestArgumentsRecursively'] : false;
1117        $arguments['verbose']                                         = isset($arguments['verbose'])                                         ? $arguments['verbose']                                         : false;
1118        $arguments['testdoxExcludeGroups']                            = isset($arguments['testdoxExcludeGroups'])                            ? $arguments['testdoxExcludeGroups']                            : [];
1119        $arguments['testdoxGroups']                                   = isset($arguments['testdoxGroups'])                                   ? $arguments['testdoxGroups']                                   : [];
1120    }
1121
1122    /**
1123     * @param string $type
1124     * @param string $message
1125     */
1126    private function writeMessage($type, $message)
1127    {
1128        if (!$this->messagePrinted) {
1129            $this->write("\n");
1130        }
1131
1132        $this->write(
1133            sprintf(
1134                "%-15s%s\n",
1135                $type . ':',
1136                $message
1137            )
1138        );
1139
1140        $this->messagePrinted = true;
1141    }
1142}
1143