Subversion-Projekte lars-tiefland.laravel_shop

Revision

Revision 621 | Details | Vergleich mit vorheriger | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
148 lars 1
<?php declare(strict_types=1);
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
namespace PHPUnit\TextUI;
11
 
12
use const PHP_EOL;
13
use const PHP_SAPI;
14
use const PHP_VERSION;
15
use function array_diff;
16
use function array_map;
17
use function array_merge;
18
use function assert;
19
use function class_exists;
20
use function count;
21
use function dirname;
22
use function file_put_contents;
23
use function htmlspecialchars;
24
use function is_array;
25
use function is_int;
26
use function is_string;
27
use function mt_srand;
28
use function range;
29
use function realpath;
150 lars 30
use function sort;
148 lars 31
use function sprintf;
32
use function time;
33
use PHPUnit\Framework\Exception;
34
use PHPUnit\Framework\TestResult;
35
use PHPUnit\Framework\TestSuite;
36
use PHPUnit\Runner\AfterLastTestHook;
37
use PHPUnit\Runner\BaseTestRunner;
38
use PHPUnit\Runner\BeforeFirstTestHook;
39
use PHPUnit\Runner\DefaultTestResultCache;
40
use PHPUnit\Runner\Extension\ExtensionHandler;
41
use PHPUnit\Runner\Filter\ExcludeGroupFilterIterator;
42
use PHPUnit\Runner\Filter\Factory;
43
use PHPUnit\Runner\Filter\IncludeGroupFilterIterator;
44
use PHPUnit\Runner\Filter\NameFilterIterator;
45
use PHPUnit\Runner\Hook;
46
use PHPUnit\Runner\NullTestResultCache;
47
use PHPUnit\Runner\ResultCacheExtension;
48
use PHPUnit\Runner\StandardTestSuiteLoader;
49
use PHPUnit\Runner\TestHook;
50
use PHPUnit\Runner\TestListenerAdapter;
51
use PHPUnit\Runner\TestSuiteLoader;
52
use PHPUnit\Runner\TestSuiteSorter;
53
use PHPUnit\Runner\Version;
54
use PHPUnit\TextUI\XmlConfiguration\CodeCoverage\FilterMapper;
55
use PHPUnit\TextUI\XmlConfiguration\Configuration;
56
use PHPUnit\TextUI\XmlConfiguration\Loader;
57
use PHPUnit\TextUI\XmlConfiguration\PhpHandler;
58
use PHPUnit\Util\Filesystem;
59
use PHPUnit\Util\Log\JUnit;
60
use PHPUnit\Util\Log\TeamCity;
61
use PHPUnit\Util\Printer;
62
use PHPUnit\Util\TestDox\CliTestDoxPrinter;
63
use PHPUnit\Util\TestDox\HtmlResultPrinter;
64
use PHPUnit\Util\TestDox\TextResultPrinter;
65
use PHPUnit\Util\TestDox\XmlResultPrinter;
66
use PHPUnit\Util\XdebugFilterScriptGenerator;
67
use PHPUnit\Util\Xml\SchemaDetector;
68
use ReflectionClass;
69
use ReflectionException;
70
use SebastianBergmann\CodeCoverage\CodeCoverage;
71
use SebastianBergmann\CodeCoverage\Driver\Selector;
72
use SebastianBergmann\CodeCoverage\Exception as CodeCoverageException;
73
use SebastianBergmann\CodeCoverage\Filter as CodeCoverageFilter;
74
use SebastianBergmann\CodeCoverage\Report\Clover as CloverReport;
75
use SebastianBergmann\CodeCoverage\Report\Cobertura as CoberturaReport;
76
use SebastianBergmann\CodeCoverage\Report\Crap4j as Crap4jReport;
77
use SebastianBergmann\CodeCoverage\Report\Html\Facade as HtmlReport;
78
use SebastianBergmann\CodeCoverage\Report\PHP as PhpReport;
79
use SebastianBergmann\CodeCoverage\Report\Text as TextReport;
80
use SebastianBergmann\CodeCoverage\Report\Xml\Facade as XmlReport;
81
use SebastianBergmann\Comparator\Comparator;
82
use SebastianBergmann\Environment\Runtime;
83
use SebastianBergmann\Invoker\Invoker;
84
use SebastianBergmann\Timer\Timer;
85
 
86
/**
87
 * @internal This class is not covered by the backward compatibility promise for PHPUnit
88
 */
89
final class TestRunner extends BaseTestRunner
90
{
991 lars 91
    public const SUCCESS_EXIT   = 0;
92
    public const FAILURE_EXIT   = 1;
148 lars 93
    public const EXCEPTION_EXIT = 2;
94
 
95
    /**
96
     * @var CodeCoverageFilter
97
     */
98
    private $codeCoverageFilter;
99
 
100
    /**
101
     * @var TestSuiteLoader
102
     */
103
    private $loader;
104
 
105
    /**
106
     * @var ResultPrinter
107
     */
108
    private $printer;
109
 
110
    /**
111
     * @var bool
112
     */
113
    private $messagePrinted = false;
114
 
115
    /**
116
     * @var Hook[]
117
     */
118
    private $extensions = [];
119
 
120
    /**
121
     * @var Timer
122
     */
123
    private $timer;
124
 
125
    public function __construct(TestSuiteLoader $loader = null, CodeCoverageFilter $filter = null)
126
    {
127
        if ($filter === null) {
128
            $filter = new CodeCoverageFilter;
129
        }
130
 
131
        $this->codeCoverageFilter = $filter;
132
        $this->loader             = $loader;
133
        $this->timer              = new Timer;
134
    }
135
 
136
    /**
137
     * @throws \PHPUnit\Runner\Exception
138
     * @throws \PHPUnit\TextUI\XmlConfiguration\Exception
139
     * @throws Exception
140
     */
141
    public function run(TestSuite $suite, array $arguments = [], array $warnings = [], bool $exit = true): TestResult
142
    {
143
        if (isset($arguments['configuration'])) {
144
            $GLOBALS['__PHPUNIT_CONFIGURATION_FILE'] = $arguments['configuration'];
145
        }
146
 
147
        $this->handleConfiguration($arguments);
148
 
149
        $warnings = array_merge($warnings, $arguments['warnings']);
150
 
151
        if (is_int($arguments['columns']) && $arguments['columns'] < 16) {
152
            $arguments['columns']   = 16;
153
            $tooFewColumnsRequested = true;
154
        }
155
 
156
        if (isset($arguments['bootstrap'])) {
157
            $GLOBALS['__PHPUNIT_BOOTSTRAP'] = $arguments['bootstrap'];
158
        }
159
 
160
        if ($arguments['backupGlobals'] === true) {
161
            $suite->setBackupGlobals(true);
162
        }
163
 
164
        if ($arguments['backupStaticAttributes'] === true) {
165
            $suite->setBackupStaticAttributes(true);
166
        }
167
 
168
        if ($arguments['beStrictAboutChangesToGlobalState'] === true) {
169
            $suite->setBeStrictAboutChangesToGlobalState(true);
170
        }
171
 
172
        if ($arguments['executionOrder'] === TestSuiteSorter::ORDER_RANDOMIZED) {
173
            mt_srand($arguments['randomOrderSeed']);
174
        }
175
 
176
        if ($arguments['cacheResult']) {
177
            if (!isset($arguments['cacheResultFile'])) {
178
                if (isset($arguments['configurationObject'])) {
179
                    assert($arguments['configurationObject'] instanceof Configuration);
180
 
181
                    $cacheLocation = $arguments['configurationObject']->filename();
182
                } else {
183
                    $cacheLocation = $_SERVER['PHP_SELF'];
184
                }
185
 
186
                $arguments['cacheResultFile'] = null;
187
 
188
                $cacheResultFile = realpath($cacheLocation);
189
 
190
                if ($cacheResultFile !== false) {
191
                    $arguments['cacheResultFile'] = dirname($cacheResultFile);
192
                }
193
            }
194
 
195
            $cache = new DefaultTestResultCache($arguments['cacheResultFile']);
196
 
197
            $this->addExtension(new ResultCacheExtension($cache));
198
        }
199
 
200
        if ($arguments['executionOrder'] !== TestSuiteSorter::ORDER_DEFAULT || $arguments['executionOrderDefects'] !== TestSuiteSorter::ORDER_DEFAULT || $arguments['resolveDependencies']) {
201
            $cache = $cache ?? new NullTestResultCache;
202
 
203
            $cache->load();
204
 
205
            $sorter = new TestSuiteSorter($cache);
206
 
207
            $sorter->reorderTestsInSuite($suite, $arguments['executionOrder'], $arguments['resolveDependencies'], $arguments['executionOrderDefects']);
208
            $originalExecutionOrder = $sorter->getOriginalExecutionOrder();
209
 
210
            unset($sorter);
211
        }
212
 
213
        if (is_int($arguments['repeat']) && $arguments['repeat'] > 0) {
214
            $_suite = new TestSuite;
215
 
216
            /* @noinspection PhpUnusedLocalVariableInspection */
217
            foreach (range(1, $arguments['repeat']) as $step) {
218
                $_suite->addTest($suite);
219
            }
220
 
221
            $suite = $_suite;
222
 
223
            unset($_suite);
224
        }
225
 
226
        $result = $this->createTestResult();
227
 
228
        $listener       = new TestListenerAdapter;
229
        $listenerNeeded = false;
230
 
231
        foreach ($this->extensions as $extension) {
232
            if ($extension instanceof TestHook) {
233
                $listener->add($extension);
234
 
235
                $listenerNeeded = true;
236
            }
237
        }
238
 
239
        if ($listenerNeeded) {
240
            $result->addListener($listener);
241
        }
242
 
243
        unset($listener, $listenerNeeded);
244
 
245
        if ($arguments['convertDeprecationsToExceptions']) {
246
            $result->convertDeprecationsToExceptions(true);
247
        }
248
 
249
        if (!$arguments['convertErrorsToExceptions']) {
250
            $result->convertErrorsToExceptions(false);
251
        }
252
 
253
        if (!$arguments['convertNoticesToExceptions']) {
254
            $result->convertNoticesToExceptions(false);
255
        }
256
 
257
        if (!$arguments['convertWarningsToExceptions']) {
258
            $result->convertWarningsToExceptions(false);
259
        }
260
 
261
        if ($arguments['stopOnError']) {
262
            $result->stopOnError(true);
263
        }
264
 
265
        if ($arguments['stopOnFailure']) {
266
            $result->stopOnFailure(true);
267
        }
268
 
269
        if ($arguments['stopOnWarning']) {
270
            $result->stopOnWarning(true);
271
        }
272
 
273
        if ($arguments['stopOnIncomplete']) {
274
            $result->stopOnIncomplete(true);
275
        }
276
 
277
        if ($arguments['stopOnRisky']) {
278
            $result->stopOnRisky(true);
279
        }
280
 
281
        if ($arguments['stopOnSkipped']) {
282
            $result->stopOnSkipped(true);
283
        }
284
 
285
        if ($arguments['stopOnDefect']) {
286
            $result->stopOnDefect(true);
287
        }
288
 
289
        if ($arguments['registerMockObjectsFromTestArgumentsRecursively']) {
290
            $result->setRegisterMockObjectsFromTestArgumentsRecursively(true);
291
        }
292
 
293
        if ($this->printer === null) {
294
            if (isset($arguments['printer'])) {
295
                if ($arguments['printer'] instanceof ResultPrinter) {
296
                    $this->printer = $arguments['printer'];
297
                } elseif (is_string($arguments['printer']) && class_exists($arguments['printer'], false)) {
298
                    try {
299
                        $reflector = new ReflectionClass($arguments['printer']);
300
 
301
                        if ($reflector->implementsInterface(ResultPrinter::class)) {
302
                            $this->printer = $this->createPrinter($arguments['printer'], $arguments);
303
                        }
304
 
305
                        // @codeCoverageIgnoreStart
306
                    } catch (ReflectionException $e) {
307
                        throw new Exception(
308
                            $e->getMessage(),
309
                            $e->getCode(),
310
                            $e
311
                        );
312
                    }
313
                    // @codeCoverageIgnoreEnd
314
                }
315
            } else {
316
                $this->printer = $this->createPrinter(DefaultResultPrinter::class, $arguments);
317
            }
318
        }
319
 
320
        if (isset($originalExecutionOrder) && $this->printer instanceof CliTestDoxPrinter) {
321
            assert($this->printer instanceof CliTestDoxPrinter);
322
 
323
            $this->printer->setOriginalExecutionOrder($originalExecutionOrder);
324
            $this->printer->setShowProgressAnimation(!$arguments['noInteraction']);
325
        }
326
 
327
        $this->write(Version::getVersionString() . "\n");
328
 
329
        foreach ($arguments['listeners'] as $listener) {
330
            $result->addListener($listener);
331
        }
332
 
333
        $result->addListener($this->printer);
334
 
335
        $coverageFilterFromConfigurationFile = false;
336
        $coverageFilterFromOption            = false;
337
        $codeCoverageReports                 = 0;
338
 
339
        if (isset($arguments['testdoxHTMLFile'])) {
340
            $result->addListener(
341
                new HtmlResultPrinter(
342
                    $arguments['testdoxHTMLFile'],
343
                    $arguments['testdoxGroups'],
344
                    $arguments['testdoxExcludeGroups']
345
                )
346
            );
347
        }
348
 
349
        if (isset($arguments['testdoxTextFile'])) {
350
            $result->addListener(
351
                new TextResultPrinter(
352
                    $arguments['testdoxTextFile'],
353
                    $arguments['testdoxGroups'],
354
                    $arguments['testdoxExcludeGroups']
355
                )
356
            );
357
        }
358
 
359
        if (isset($arguments['testdoxXMLFile'])) {
360
            $result->addListener(
361
                new XmlResultPrinter(
362
                    $arguments['testdoxXMLFile']
363
                )
364
            );
365
        }
366
 
367
        if (isset($arguments['teamcityLogfile'])) {
368
            $result->addListener(
369
                new TeamCity($arguments['teamcityLogfile'])
370
            );
371
        }
372
 
373
        if (isset($arguments['junitLogfile'])) {
374
            $result->addListener(
375
                new JUnit(
376
                    $arguments['junitLogfile'],
377
                    $arguments['reportUselessTests']
378
                )
379
            );
380
        }
381
 
382
        if (isset($arguments['coverageClover'])) {
383
            $codeCoverageReports++;
384
        }
385
 
386
        if (isset($arguments['coverageCobertura'])) {
387
            $codeCoverageReports++;
388
        }
389
 
390
        if (isset($arguments['coverageCrap4J'])) {
391
            $codeCoverageReports++;
392
        }
393
 
394
        if (isset($arguments['coverageHtml'])) {
395
            $codeCoverageReports++;
396
        }
397
 
398
        if (isset($arguments['coveragePHP'])) {
399
            $codeCoverageReports++;
400
        }
401
 
402
        if (isset($arguments['coverageText'])) {
403
            $codeCoverageReports++;
404
        }
405
 
406
        if (isset($arguments['coverageXml'])) {
407
            $codeCoverageReports++;
408
        }
409
 
410
        if ($codeCoverageReports > 0 || isset($arguments['xdebugFilterFile'])) {
411
            if (isset($arguments['coverageFilter'])) {
412
                if (!is_array($arguments['coverageFilter'])) {
413
                    $coverageFilterDirectories = [$arguments['coverageFilter']];
414
                } else {
415
                    $coverageFilterDirectories = $arguments['coverageFilter'];
416
                }
417
 
418
                foreach ($coverageFilterDirectories as $coverageFilterDirectory) {
419
                    $this->codeCoverageFilter->includeDirectory($coverageFilterDirectory);
420
                }
421
 
422
                $coverageFilterFromOption = true;
423
            }
424
 
425
            if (isset($arguments['configurationObject'])) {
426
                assert($arguments['configurationObject'] instanceof Configuration);
427
 
428
                $codeCoverageConfiguration = $arguments['configurationObject']->codeCoverage();
429
 
430
                if ($codeCoverageConfiguration->hasNonEmptyListOfFilesToBeIncludedInCodeCoverageReport()) {
431
                    $coverageFilterFromConfigurationFile = true;
432
 
433
                    (new FilterMapper)->map(
434
                        $this->codeCoverageFilter,
435
                        $codeCoverageConfiguration
436
                    );
437
                }
438
            }
439
        }
440
 
441
        if ($codeCoverageReports > 0) {
442
            try {
443
                if (isset($codeCoverageConfiguration) &&
444
                    ($codeCoverageConfiguration->pathCoverage() || (isset($arguments['pathCoverage']) && $arguments['pathCoverage'] === true))) {
445
                    $codeCoverageDriver = (new Selector)->forLineAndPathCoverage($this->codeCoverageFilter);
446
                } else {
447
                    $codeCoverageDriver = (new Selector)->forLineCoverage($this->codeCoverageFilter);
448
                }
449
 
450
                $codeCoverage = new CodeCoverage(
451
                    $codeCoverageDriver,
452
                    $this->codeCoverageFilter
453
                );
454
 
455
                if (isset($codeCoverageConfiguration) && $codeCoverageConfiguration->hasCacheDirectory()) {
456
                    $codeCoverage->cacheStaticAnalysis($codeCoverageConfiguration->cacheDirectory()->path());
457
                }
458
 
459
                if (isset($arguments['coverageCacheDirectory'])) {
460
                    $codeCoverage->cacheStaticAnalysis($arguments['coverageCacheDirectory']);
461
                }
462
 
463
                $codeCoverage->excludeSubclassesOfThisClassFromUnintentionallyCoveredCodeCheck(Comparator::class);
464
 
465
                if ($arguments['strictCoverage']) {
466
                    $codeCoverage->enableCheckForUnintentionallyCoveredCode();
467
                }
468
 
469
                if (isset($arguments['ignoreDeprecatedCodeUnitsFromCodeCoverage'])) {
470
                    if ($arguments['ignoreDeprecatedCodeUnitsFromCodeCoverage']) {
471
                        $codeCoverage->ignoreDeprecatedCode();
472
                    } else {
473
                        $codeCoverage->doNotIgnoreDeprecatedCode();
474
                    }
475
                }
476
 
477
                if (isset($arguments['disableCodeCoverageIgnore'])) {
478
                    if ($arguments['disableCodeCoverageIgnore']) {
479
                        $codeCoverage->disableAnnotationsForIgnoringCode();
480
                    } else {
481
                        $codeCoverage->enableAnnotationsForIgnoringCode();
482
                    }
483
                }
484
 
485
                if (isset($arguments['configurationObject'])) {
486
                    $codeCoverageConfiguration = $arguments['configurationObject']->codeCoverage();
487
 
488
                    if ($codeCoverageConfiguration->hasNonEmptyListOfFilesToBeIncludedInCodeCoverageReport()) {
489
                        if ($codeCoverageConfiguration->includeUncoveredFiles()) {
490
                            $codeCoverage->includeUncoveredFiles();
491
                        } else {
492
                            $codeCoverage->excludeUncoveredFiles();
493
                        }
494
 
495
                        if ($codeCoverageConfiguration->processUncoveredFiles()) {
496
                            $codeCoverage->processUncoveredFiles();
497
                        } else {
498
                            $codeCoverage->doNotProcessUncoveredFiles();
499
                        }
500
                    }
501
                }
502
 
503
                if ($this->codeCoverageFilter->isEmpty()) {
504
                    if (!$coverageFilterFromConfigurationFile && !$coverageFilterFromOption) {
505
                        $warnings[] = 'No filter is configured, code coverage will not be processed';
506
                    } else {
507
                        $warnings[] = 'Incorrect filter configuration, code coverage will not be processed';
508
                    }
509
 
510
                    unset($codeCoverage);
511
                }
512
            } catch (CodeCoverageException $e) {
513
                $warnings[] = $e->getMessage();
514
            }
515
        }
516
 
517
        if ($arguments['verbose']) {
518
            if (PHP_SAPI === 'phpdbg') {
519
                $this->writeMessage('Runtime', 'PHPDBG ' . PHP_VERSION);
520
            } else {
521
                $runtime = 'PHP ' . PHP_VERSION;
522
 
523
                if (isset($codeCoverageDriver)) {
524
                    $runtime .= ' with ' . $codeCoverageDriver->nameAndVersion();
525
                }
526
 
527
                $this->writeMessage('Runtime', $runtime);
528
            }
529
 
530
            if (isset($arguments['configurationObject'])) {
531
                assert($arguments['configurationObject'] instanceof Configuration);
532
 
533
                $this->writeMessage(
534
                    'Configuration',
535
                    $arguments['configurationObject']->filename()
536
                );
537
            }
538
 
539
            foreach ($arguments['loadedExtensions'] as $extension) {
540
                $this->writeMessage(
541
                    'Extension',
542
                    $extension
543
                );
544
            }
545
 
546
            foreach ($arguments['notLoadedExtensions'] as $extension) {
547
                $this->writeMessage(
548
                    'Extension',
549
                    $extension
550
                );
551
            }
552
        }
553
 
554
        if ($arguments['executionOrder'] === TestSuiteSorter::ORDER_RANDOMIZED) {
555
            $this->writeMessage(
556
                'Random Seed',
557
                (string) $arguments['randomOrderSeed']
558
            );
559
        }
560
 
561
        if (isset($tooFewColumnsRequested)) {
562
            $warnings[] = 'Less than 16 columns requested, number of columns set to 16';
563
        }
564
 
565
        if ((new Runtime)->discardsComments()) {
566
            $warnings[] = 'opcache.save_comments=0 set; annotations will not work';
567
        }
568
 
569
        if (isset($arguments['conflictBetweenPrinterClassAndTestdox'])) {
570
            $warnings[] = 'Directives printerClass and testdox are mutually exclusive';
571
        }
572
 
150 lars 573
        $warnings = array_merge($warnings, $suite->warnings());
574
        sort($warnings);
575
 
148 lars 576
        foreach ($warnings as $warning) {
577
            $this->writeMessage('Warning', $warning);
578
        }
579
 
580
        if (isset($arguments['configurationObject'])) {
581
            assert($arguments['configurationObject'] instanceof Configuration);
582
 
583
            if ($arguments['configurationObject']->hasValidationErrors()) {
584
                if ((new SchemaDetector)->detect($arguments['configurationObject']->filename())->detected()) {
585
                    $this->writeMessage('Warning', 'Your XML configuration validates against a deprecated schema.');
586
                    $this->writeMessage('Suggestion', 'Migrate your XML configuration using "--migrate-configuration"!');
587
                } else {
588
                    $this->write(
589
                        "\n  Warning - The configuration file did not pass validation!\n  The following problems have been detected:\n"
590
                    );
591
 
592
                    $this->write($arguments['configurationObject']->validationErrors());
593
 
594
                    $this->write("\n  Test results may not be as expected.\n\n");
595
                }
596
            }
597
        }
598
 
599
        if (isset($arguments['xdebugFilterFile'], $codeCoverageConfiguration)) {
600
            $this->write(PHP_EOL . 'Please note that --dump-xdebug-filter and --prepend are deprecated and will be removed in PHPUnit 10.' . PHP_EOL);
601
 
602
            $script = (new XdebugFilterScriptGenerator)->generate($codeCoverageConfiguration);
603
 
604
            if ($arguments['xdebugFilterFile'] !== 'php://stdout' && $arguments['xdebugFilterFile'] !== 'php://stderr' && !Filesystem::createDirectory(dirname($arguments['xdebugFilterFile']))) {
605
                $this->write(sprintf('Cannot write Xdebug filter script to %s ' . PHP_EOL, $arguments['xdebugFilterFile']));
606
 
607
                exit(self::EXCEPTION_EXIT);
608
            }
609
 
610
            file_put_contents($arguments['xdebugFilterFile'], $script);
611
 
612
            $this->write(sprintf('Wrote Xdebug filter script to %s ' . PHP_EOL . PHP_EOL, $arguments['xdebugFilterFile']));
613
 
614
            exit(self::SUCCESS_EXIT);
615
        }
616
 
617
        $this->write("\n");
618
 
619
        if (isset($codeCoverage)) {
620
            $result->setCodeCoverage($codeCoverage);
621
        }
622
 
623
        $result->beStrictAboutTestsThatDoNotTestAnything($arguments['reportUselessTests']);
624
        $result->beStrictAboutOutputDuringTests($arguments['disallowTestOutput']);
625
        $result->beStrictAboutTodoAnnotatedTests($arguments['disallowTodoAnnotatedTests']);
626
        $result->beStrictAboutResourceUsageDuringSmallTests($arguments['beStrictAboutResourceUsageDuringSmallTests']);
627
 
628
        if ($arguments['enforceTimeLimit'] === true && !(new Invoker)->canInvokeWithTimeout()) {
629
            $this->writeMessage('Error', 'PHP extension pcntl is required for enforcing time limits');
630
        }
631
 
632
        $result->enforceTimeLimit($arguments['enforceTimeLimit']);
633
        $result->setDefaultTimeLimit($arguments['defaultTimeLimit']);
634
        $result->setTimeoutForSmallTests($arguments['timeoutForSmallTests']);
635
        $result->setTimeoutForMediumTests($arguments['timeoutForMediumTests']);
636
        $result->setTimeoutForLargeTests($arguments['timeoutForLargeTests']);
637
 
638
        if (isset($arguments['forceCoversAnnotation']) && $arguments['forceCoversAnnotation'] === true) {
639
            $result->forceCoversAnnotation();
640
        }
641
 
642
        $this->processSuiteFilters($suite, $arguments);
643
        $suite->setRunTestInSeparateProcess($arguments['processIsolation']);
644
 
645
        foreach ($this->extensions as $extension) {
646
            if ($extension instanceof BeforeFirstTestHook) {
647
                $extension->executeBeforeFirstTest();
648
            }
649
        }
650
 
651
        $suite->run($result);
652
 
653
        foreach ($this->extensions as $extension) {
654
            if ($extension instanceof AfterLastTestHook) {
655
                $extension->executeAfterLastTest();
656
            }
657
        }
658
 
659
        $result->flushListeners();
660
        $this->printer->printResult($result);
661
 
662
        if (isset($codeCoverage)) {
663
            if (isset($arguments['coverageClover'])) {
664
                $this->codeCoverageGenerationStart('Clover XML');
665
 
666
                try {
667
                    $writer = new CloverReport;
668
                    $writer->process($codeCoverage, $arguments['coverageClover']);
669
 
670
                    $this->codeCoverageGenerationSucceeded();
671
 
672
                    unset($writer);
673
                } catch (CodeCoverageException $e) {
674
                    $this->codeCoverageGenerationFailed($e);
675
                }
676
            }
677
 
678
            if (isset($arguments['coverageCobertura'])) {
679
                $this->codeCoverageGenerationStart('Cobertura XML');
680
 
681
                try {
682
                    $writer = new CoberturaReport;
683
                    $writer->process($codeCoverage, $arguments['coverageCobertura']);
684
 
685
                    $this->codeCoverageGenerationSucceeded();
686
 
687
                    unset($writer);
688
                } catch (CodeCoverageException $e) {
689
                    $this->codeCoverageGenerationFailed($e);
690
                }
691
            }
692
 
693
            if (isset($arguments['coverageCrap4J'])) {
694
                $this->codeCoverageGenerationStart('Crap4J XML');
695
 
696
                try {
697
                    $writer = new Crap4jReport($arguments['crap4jThreshold']);
698
                    $writer->process($codeCoverage, $arguments['coverageCrap4J']);
699
 
700
                    $this->codeCoverageGenerationSucceeded();
701
 
702
                    unset($writer);
703
                } catch (CodeCoverageException $e) {
704
                    $this->codeCoverageGenerationFailed($e);
705
                }
706
            }
707
 
708
            if (isset($arguments['coverageHtml'])) {
709
                $this->codeCoverageGenerationStart('HTML');
710
 
711
                try {
712
                    $writer = new HtmlReport(
713
                        $arguments['reportLowUpperBound'],
714
                        $arguments['reportHighLowerBound'],
715
                        sprintf(
716
                            ' and <a href="https://phpunit.de/">PHPUnit %s</a>',
717
                            Version::id()
718
                        )
719
                    );
720
 
721
                    $writer->process($codeCoverage, $arguments['coverageHtml']);
722
 
723
                    $this->codeCoverageGenerationSucceeded();
724
 
725
                    unset($writer);
726
                } catch (CodeCoverageException $e) {
727
                    $this->codeCoverageGenerationFailed($e);
728
                }
729
            }
730
 
731
            if (isset($arguments['coveragePHP'])) {
732
                $this->codeCoverageGenerationStart('PHP');
733
 
734
                try {
735
                    $writer = new PhpReport;
736
                    $writer->process($codeCoverage, $arguments['coveragePHP']);
737
 
738
                    $this->codeCoverageGenerationSucceeded();
739
 
740
                    unset($writer);
741
                } catch (CodeCoverageException $e) {
742
                    $this->codeCoverageGenerationFailed($e);
743
                }
744
            }
745
 
746
            if (isset($arguments['coverageText'])) {
747
                if ($arguments['coverageText'] === 'php://stdout') {
748
                    $outputStream = $this->printer;
749
                    $colors       = $arguments['colors'] && $arguments['colors'] !== DefaultResultPrinter::COLOR_NEVER;
750
                } else {
751
                    $outputStream = new Printer($arguments['coverageText']);
752
                    $colors       = false;
753
                }
754
 
755
                $processor = new TextReport(
756
                    $arguments['reportLowUpperBound'],
757
                    $arguments['reportHighLowerBound'],
758
                    $arguments['coverageTextShowUncoveredFiles'],
759
                    $arguments['coverageTextShowOnlySummary']
760
                );
761
 
762
                $outputStream->write(
763
                    $processor->process($codeCoverage, $colors)
764
                );
765
            }
766
 
767
            if (isset($arguments['coverageXml'])) {
768
                $this->codeCoverageGenerationStart('PHPUnit XML');
769
 
770
                try {
771
                    $writer = new XmlReport(Version::id());
772
                    $writer->process($codeCoverage, $arguments['coverageXml']);
773
 
774
                    $this->codeCoverageGenerationSucceeded();
775
 
776
                    unset($writer);
777
                } catch (CodeCoverageException $e) {
778
                    $this->codeCoverageGenerationFailed($e);
779
                }
780
            }
781
        }
782
 
783
        if ($exit) {
784
            if (isset($arguments['failOnEmptyTestSuite']) && $arguments['failOnEmptyTestSuite'] === true && count($result) === 0) {
785
                exit(self::FAILURE_EXIT);
786
            }
787
 
788
            if ($result->wasSuccessfulIgnoringWarnings()) {
789
                if ($arguments['failOnRisky'] && !$result->allHarmless()) {
790
                    exit(self::FAILURE_EXIT);
791
                }
792
 
793
                if ($arguments['failOnWarning'] && $result->warningCount() > 0) {
794
                    exit(self::FAILURE_EXIT);
795
                }
796
 
797
                if ($arguments['failOnIncomplete'] && $result->notImplementedCount() > 0) {
798
                    exit(self::FAILURE_EXIT);
799
                }
800
 
801
                if ($arguments['failOnSkipped'] && $result->skippedCount() > 0) {
802
                    exit(self::FAILURE_EXIT);
803
                }
804
 
805
                exit(self::SUCCESS_EXIT);
806
            }
807
 
808
            if ($result->errorCount() > 0) {
809
                exit(self::EXCEPTION_EXIT);
810
            }
811
 
812
            if ($result->failureCount() > 0) {
813
                exit(self::FAILURE_EXIT);
814
            }
815
        }
816
 
817
        return $result;
818
    }
819
 
820
    /**
821
     * Returns the loader to be used.
822
     */
823
    public function getLoader(): TestSuiteLoader
824
    {
825
        if ($this->loader === null) {
826
            $this->loader = new StandardTestSuiteLoader;
827
        }
828
 
829
        return $this->loader;
830
    }
831
 
832
    public function addExtension(Hook $extension): void
833
    {
834
        $this->extensions[] = $extension;
835
    }
836
 
837
    /**
838
     * Override to define how to handle a failed loading of
839
     * a test suite.
840
     */
841
    protected function runFailed(string $message): void
842
    {
843
        $this->write($message . PHP_EOL);
844
 
845
        exit(self::FAILURE_EXIT);
846
    }
847
 
848
    private function createTestResult(): TestResult
849
    {
850
        return new TestResult;
851
    }
852
 
853
    private function write(string $buffer): void
854
    {
855
        if (PHP_SAPI !== 'cli' && PHP_SAPI !== 'phpdbg') {
856
            $buffer = htmlspecialchars($buffer);
857
        }
858
 
859
        if ($this->printer !== null) {
860
            $this->printer->write($buffer);
861
        } else {
862
            print $buffer;
863
        }
864
    }
865
 
866
    /**
867
     * @throws \PHPUnit\TextUI\XmlConfiguration\Exception
868
     * @throws Exception
869
     */
870
    private function handleConfiguration(array &$arguments): void
871
    {
872
        if (!isset($arguments['configurationObject']) && isset($arguments['configuration'])) {
873
            $arguments['configurationObject'] = (new Loader)->load($arguments['configuration']);
874
        }
875
 
876
        if (!isset($arguments['warnings'])) {
877
            $arguments['warnings'] = [];
878
        }
879
 
880
        $arguments['debug']     = $arguments['debug'] ?? false;
881
        $arguments['filter']    = $arguments['filter'] ?? false;
882
        $arguments['listeners'] = $arguments['listeners'] ?? [];
883
 
884
        if (isset($arguments['configurationObject'])) {
885
            (new PhpHandler)->handle($arguments['configurationObject']->php());
886
 
887
            $codeCoverageConfiguration = $arguments['configurationObject']->codeCoverage();
888
 
889
            if (!isset($arguments['noCoverage'])) {
890
                if (!isset($arguments['coverageClover']) && $codeCoverageConfiguration->hasClover()) {
891
                    $arguments['coverageClover'] = $codeCoverageConfiguration->clover()->target()->path();
892
                }
893
 
894
                if (!isset($arguments['coverageCobertura']) && $codeCoverageConfiguration->hasCobertura()) {
895
                    $arguments['coverageCobertura'] = $codeCoverageConfiguration->cobertura()->target()->path();
896
                }
897
 
898
                if (!isset($arguments['coverageCrap4J']) && $codeCoverageConfiguration->hasCrap4j()) {
899
                    $arguments['coverageCrap4J'] = $codeCoverageConfiguration->crap4j()->target()->path();
900
 
901
                    if (!isset($arguments['crap4jThreshold'])) {
902
                        $arguments['crap4jThreshold'] = $codeCoverageConfiguration->crap4j()->threshold();
903
                    }
904
                }
905
 
906
                if (!isset($arguments['coverageHtml']) && $codeCoverageConfiguration->hasHtml()) {
907
                    $arguments['coverageHtml'] = $codeCoverageConfiguration->html()->target()->path();
908
 
909
                    if (!isset($arguments['reportLowUpperBound'])) {
910
                        $arguments['reportLowUpperBound'] = $codeCoverageConfiguration->html()->lowUpperBound();
911
                    }
912
 
913
                    if (!isset($arguments['reportHighLowerBound'])) {
914
                        $arguments['reportHighLowerBound'] = $codeCoverageConfiguration->html()->highLowerBound();
915
                    }
916
                }
917
 
918
                if (!isset($arguments['coveragePHP']) && $codeCoverageConfiguration->hasPhp()) {
919
                    $arguments['coveragePHP'] = $codeCoverageConfiguration->php()->target()->path();
920
                }
921
 
922
                if (!isset($arguments['coverageText']) && $codeCoverageConfiguration->hasText()) {
923
                    $arguments['coverageText']                   = $codeCoverageConfiguration->text()->target()->path();
924
                    $arguments['coverageTextShowUncoveredFiles'] = $codeCoverageConfiguration->text()->showUncoveredFiles();
925
                    $arguments['coverageTextShowOnlySummary']    = $codeCoverageConfiguration->text()->showOnlySummary();
926
                }
927
 
928
                if (!isset($arguments['coverageXml']) && $codeCoverageConfiguration->hasXml()) {
929
                    $arguments['coverageXml'] = $codeCoverageConfiguration->xml()->target()->path();
930
                }
931
            }
932
 
933
            $phpunitConfiguration = $arguments['configurationObject']->phpunit();
934
 
935
            $arguments['backupGlobals']                                   = $arguments['backupGlobals'] ?? $phpunitConfiguration->backupGlobals();
936
            $arguments['backupStaticAttributes']                          = $arguments['backupStaticAttributes'] ?? $phpunitConfiguration->backupStaticAttributes();
937
            $arguments['beStrictAboutChangesToGlobalState']               = $arguments['beStrictAboutChangesToGlobalState'] ?? $phpunitConfiguration->beStrictAboutChangesToGlobalState();
938
            $arguments['cacheResult']                                     = $arguments['cacheResult'] ?? $phpunitConfiguration->cacheResult();
939
            $arguments['colors']                                          = $arguments['colors'] ?? $phpunitConfiguration->colors();
940
            $arguments['convertDeprecationsToExceptions']                 = $arguments['convertDeprecationsToExceptions'] ?? $phpunitConfiguration->convertDeprecationsToExceptions();
941
            $arguments['convertErrorsToExceptions']                       = $arguments['convertErrorsToExceptions'] ?? $phpunitConfiguration->convertErrorsToExceptions();
942
            $arguments['convertNoticesToExceptions']                      = $arguments['convertNoticesToExceptions'] ?? $phpunitConfiguration->convertNoticesToExceptions();
943
            $arguments['convertWarningsToExceptions']                     = $arguments['convertWarningsToExceptions'] ?? $phpunitConfiguration->convertWarningsToExceptions();
944
            $arguments['processIsolation']                                = $arguments['processIsolation'] ?? $phpunitConfiguration->processIsolation();
945
            $arguments['stopOnDefect']                                    = $arguments['stopOnDefect'] ?? $phpunitConfiguration->stopOnDefect();
946
            $arguments['stopOnError']                                     = $arguments['stopOnError'] ?? $phpunitConfiguration->stopOnError();
947
            $arguments['stopOnFailure']                                   = $arguments['stopOnFailure'] ?? $phpunitConfiguration->stopOnFailure();
948
            $arguments['stopOnWarning']                                   = $arguments['stopOnWarning'] ?? $phpunitConfiguration->stopOnWarning();
949
            $arguments['stopOnIncomplete']                                = $arguments['stopOnIncomplete'] ?? $phpunitConfiguration->stopOnIncomplete();
950
            $arguments['stopOnRisky']                                     = $arguments['stopOnRisky'] ?? $phpunitConfiguration->stopOnRisky();
951
            $arguments['stopOnSkipped']                                   = $arguments['stopOnSkipped'] ?? $phpunitConfiguration->stopOnSkipped();
952
            $arguments['failOnEmptyTestSuite']                            = $arguments['failOnEmptyTestSuite'] ?? $phpunitConfiguration->failOnEmptyTestSuite();
953
            $arguments['failOnIncomplete']                                = $arguments['failOnIncomplete'] ?? $phpunitConfiguration->failOnIncomplete();
954
            $arguments['failOnRisky']                                     = $arguments['failOnRisky'] ?? $phpunitConfiguration->failOnRisky();
955
            $arguments['failOnSkipped']                                   = $arguments['failOnSkipped'] ?? $phpunitConfiguration->failOnSkipped();
956
            $arguments['failOnWarning']                                   = $arguments['failOnWarning'] ?? $phpunitConfiguration->failOnWarning();
957
            $arguments['enforceTimeLimit']                                = $arguments['enforceTimeLimit'] ?? $phpunitConfiguration->enforceTimeLimit();
958
            $arguments['defaultTimeLimit']                                = $arguments['defaultTimeLimit'] ?? $phpunitConfiguration->defaultTimeLimit();
959
            $arguments['timeoutForSmallTests']                            = $arguments['timeoutForSmallTests'] ?? $phpunitConfiguration->timeoutForSmallTests();
960
            $arguments['timeoutForMediumTests']                           = $arguments['timeoutForMediumTests'] ?? $phpunitConfiguration->timeoutForMediumTests();
961
            $arguments['timeoutForLargeTests']                            = $arguments['timeoutForLargeTests'] ?? $phpunitConfiguration->timeoutForLargeTests();
962
            $arguments['reportUselessTests']                              = $arguments['reportUselessTests'] ?? $phpunitConfiguration->beStrictAboutTestsThatDoNotTestAnything();
963
            $arguments['strictCoverage']                                  = $arguments['strictCoverage'] ?? $phpunitConfiguration->beStrictAboutCoversAnnotation();
964
            $arguments['ignoreDeprecatedCodeUnitsFromCodeCoverage']       = $arguments['ignoreDeprecatedCodeUnitsFromCodeCoverage'] ?? $codeCoverageConfiguration->ignoreDeprecatedCodeUnits();
965
            $arguments['disallowTestOutput']                              = $arguments['disallowTestOutput'] ?? $phpunitConfiguration->beStrictAboutOutputDuringTests();
966
            $arguments['disallowTodoAnnotatedTests']                      = $arguments['disallowTodoAnnotatedTests'] ?? $phpunitConfiguration->beStrictAboutTodoAnnotatedTests();
967
            $arguments['beStrictAboutResourceUsageDuringSmallTests']      = $arguments['beStrictAboutResourceUsageDuringSmallTests'] ?? $phpunitConfiguration->beStrictAboutResourceUsageDuringSmallTests();
968
            $arguments['verbose']                                         = $arguments['verbose'] ?? $phpunitConfiguration->verbose();
969
            $arguments['reverseDefectList']                               = $arguments['reverseDefectList'] ?? $phpunitConfiguration->reverseDefectList();
970
            $arguments['forceCoversAnnotation']                           = $arguments['forceCoversAnnotation'] ?? $phpunitConfiguration->forceCoversAnnotation();
971
            $arguments['disableCodeCoverageIgnore']                       = $arguments['disableCodeCoverageIgnore'] ?? $codeCoverageConfiguration->disableCodeCoverageIgnore();
972
            $arguments['registerMockObjectsFromTestArgumentsRecursively'] = $arguments['registerMockObjectsFromTestArgumentsRecursively'] ?? $phpunitConfiguration->registerMockObjectsFromTestArgumentsRecursively();
973
            $arguments['noInteraction']                                   = $arguments['noInteraction'] ?? $phpunitConfiguration->noInteraction();
974
            $arguments['executionOrder']                                  = $arguments['executionOrder'] ?? $phpunitConfiguration->executionOrder();
975
            $arguments['resolveDependencies']                             = $arguments['resolveDependencies'] ?? $phpunitConfiguration->resolveDependencies();
976
 
977
            if (!isset($arguments['bootstrap']) && $phpunitConfiguration->hasBootstrap()) {
978
                $arguments['bootstrap'] = $phpunitConfiguration->bootstrap();
979
            }
980
 
981
            if (!isset($arguments['cacheResultFile']) && $phpunitConfiguration->hasCacheResultFile()) {
982
                $arguments['cacheResultFile'] = $phpunitConfiguration->cacheResultFile();
983
            }
984
 
985
            if (!isset($arguments['executionOrderDefects'])) {
986
                $arguments['executionOrderDefects'] = $phpunitConfiguration->defectsFirst() ? TestSuiteSorter::ORDER_DEFECTS_FIRST : TestSuiteSorter::ORDER_DEFAULT;
987
            }
988
 
989
            if ($phpunitConfiguration->conflictBetweenPrinterClassAndTestdox()) {
990
                $arguments['conflictBetweenPrinterClassAndTestdox'] = true;
991
            }
992
 
993
            $groupCliArgs = [];
994
 
995
            if (!empty($arguments['groups'])) {
996
                $groupCliArgs = $arguments['groups'];
997
            }
998
 
999
            $groupConfiguration = $arguments['configurationObject']->groups();
1000
 
1001
            if (!isset($arguments['groups']) && $groupConfiguration->hasInclude()) {
1002
                $arguments['groups'] = $groupConfiguration->include()->asArrayOfStrings();
1003
            }
1004
 
1005
            if (!isset($arguments['excludeGroups']) && $groupConfiguration->hasExclude()) {
1006
                $arguments['excludeGroups'] = array_diff($groupConfiguration->exclude()->asArrayOfStrings(), $groupCliArgs);
1007
            }
1008
 
621 lars 1009
            if (!isset($this->arguments['noExtensions'])) {
1010
                $extensionHandler = new ExtensionHandler;
148 lars 1011
 
621 lars 1012
                foreach ($arguments['configurationObject']->extensions() as $extension) {
1013
                    $extensionHandler->registerExtension($extension, $this);
1014
                }
148 lars 1015
 
621 lars 1016
                foreach ($arguments['configurationObject']->listeners() as $listener) {
1017
                    $arguments['listeners'][] = $extensionHandler->createTestListenerInstance($listener);
1018
                }
1019
 
1020
                unset($extensionHandler);
148 lars 1021
            }
1022
 
1023
            foreach ($arguments['unavailableExtensions'] as $extension) {
1024
                $arguments['warnings'][] = sprintf(
1025
                    'Extension "%s" is not available',
1026
                    $extension
1027
                );
1028
            }
1029
 
1030
            $loggingConfiguration = $arguments['configurationObject']->logging();
1031
 
1032
            if (!isset($arguments['noLogging'])) {
1033
                if ($loggingConfiguration->hasText()) {
1034
                    $arguments['listeners'][] = new DefaultResultPrinter(
1035
                        $loggingConfiguration->text()->target()->path(),
1036
                        true
1037
                    );
1038
                }
1039
 
1040
                if (!isset($arguments['teamcityLogfile']) && $loggingConfiguration->hasTeamCity()) {
1041
                    $arguments['teamcityLogfile'] = $loggingConfiguration->teamCity()->target()->path();
1042
                }
1043
 
1044
                if (!isset($arguments['junitLogfile']) && $loggingConfiguration->hasJunit()) {
1045
                    $arguments['junitLogfile'] = $loggingConfiguration->junit()->target()->path();
1046
                }
1047
 
1048
                if (!isset($arguments['testdoxHTMLFile']) && $loggingConfiguration->hasTestDoxHtml()) {
1049
                    $arguments['testdoxHTMLFile'] = $loggingConfiguration->testDoxHtml()->target()->path();
1050
                }
1051
 
1052
                if (!isset($arguments['testdoxTextFile']) && $loggingConfiguration->hasTestDoxText()) {
1053
                    $arguments['testdoxTextFile'] = $loggingConfiguration->testDoxText()->target()->path();
1054
                }
1055
 
1056
                if (!isset($arguments['testdoxXMLFile']) && $loggingConfiguration->hasTestDoxXml()) {
1057
                    $arguments['testdoxXMLFile'] = $loggingConfiguration->testDoxXml()->target()->path();
1058
                }
1059
            }
1060
 
1061
            $testdoxGroupConfiguration = $arguments['configurationObject']->testdoxGroups();
1062
 
1063
            if (!isset($arguments['testdoxGroups']) && $testdoxGroupConfiguration->hasInclude()) {
1064
                $arguments['testdoxGroups'] = $testdoxGroupConfiguration->include()->asArrayOfStrings();
1065
            }
1066
 
1067
            if (!isset($arguments['testdoxExcludeGroups']) && $testdoxGroupConfiguration->hasExclude()) {
1068
                $arguments['testdoxExcludeGroups'] = $testdoxGroupConfiguration->exclude()->asArrayOfStrings();
1069
            }
1070
        }
1071
 
1072
        $extensionHandler = new ExtensionHandler;
1073
 
1074
        foreach ($arguments['extensions'] as $extension) {
1075
            $extensionHandler->registerExtension($extension, $this);
1076
        }
1077
 
1078
        unset($extensionHandler);
1079
 
1080
        $arguments['backupGlobals']                                   = $arguments['backupGlobals'] ?? null;
1081
        $arguments['backupStaticAttributes']                          = $arguments['backupStaticAttributes'] ?? null;
1082
        $arguments['beStrictAboutChangesToGlobalState']               = $arguments['beStrictAboutChangesToGlobalState'] ?? null;
1083
        $arguments['beStrictAboutResourceUsageDuringSmallTests']      = $arguments['beStrictAboutResourceUsageDuringSmallTests'] ?? false;
1084
        $arguments['cacheResult']                                     = $arguments['cacheResult'] ?? true;
1085
        $arguments['colors']                                          = $arguments['colors'] ?? DefaultResultPrinter::COLOR_DEFAULT;
1086
        $arguments['columns']                                         = $arguments['columns'] ?? 80;
1087
        $arguments['convertDeprecationsToExceptions']                 = $arguments['convertDeprecationsToExceptions'] ?? false;
1088
        $arguments['convertErrorsToExceptions']                       = $arguments['convertErrorsToExceptions'] ?? true;
1089
        $arguments['convertNoticesToExceptions']                      = $arguments['convertNoticesToExceptions'] ?? true;
1090
        $arguments['convertWarningsToExceptions']                     = $arguments['convertWarningsToExceptions'] ?? true;
1091
        $arguments['crap4jThreshold']                                 = $arguments['crap4jThreshold'] ?? 30;
1092
        $arguments['disallowTestOutput']                              = $arguments['disallowTestOutput'] ?? false;
1093
        $arguments['disallowTodoAnnotatedTests']                      = $arguments['disallowTodoAnnotatedTests'] ?? false;
1094
        $arguments['defaultTimeLimit']                                = $arguments['defaultTimeLimit'] ?? 0;
1095
        $arguments['enforceTimeLimit']                                = $arguments['enforceTimeLimit'] ?? false;
1096
        $arguments['excludeGroups']                                   = $arguments['excludeGroups'] ?? [];
1097
        $arguments['executionOrder']                                  = $arguments['executionOrder'] ?? TestSuiteSorter::ORDER_DEFAULT;
1098
        $arguments['executionOrderDefects']                           = $arguments['executionOrderDefects'] ?? TestSuiteSorter::ORDER_DEFAULT;
1099
        $arguments['failOnIncomplete']                                = $arguments['failOnIncomplete'] ?? false;
1100
        $arguments['failOnRisky']                                     = $arguments['failOnRisky'] ?? false;
1101
        $arguments['failOnSkipped']                                   = $arguments['failOnSkipped'] ?? false;
1102
        $arguments['failOnWarning']                                   = $arguments['failOnWarning'] ?? false;
1103
        $arguments['groups']                                          = $arguments['groups'] ?? [];
1104
        $arguments['noInteraction']                                   = $arguments['noInteraction'] ?? false;
1105
        $arguments['processIsolation']                                = $arguments['processIsolation'] ?? false;
1106
        $arguments['randomOrderSeed']                                 = $arguments['randomOrderSeed'] ?? time();
1107
        $arguments['registerMockObjectsFromTestArgumentsRecursively'] = $arguments['registerMockObjectsFromTestArgumentsRecursively'] ?? false;
1108
        $arguments['repeat']                                          = $arguments['repeat'] ?? false;
1109
        $arguments['reportHighLowerBound']                            = $arguments['reportHighLowerBound'] ?? 90;
1110
        $arguments['reportLowUpperBound']                             = $arguments['reportLowUpperBound'] ?? 50;
1111
        $arguments['reportUselessTests']                              = $arguments['reportUselessTests'] ?? true;
1112
        $arguments['reverseList']                                     = $arguments['reverseList'] ?? false;
1113
        $arguments['resolveDependencies']                             = $arguments['resolveDependencies'] ?? true;
1114
        $arguments['stopOnError']                                     = $arguments['stopOnError'] ?? false;
1115
        $arguments['stopOnFailure']                                   = $arguments['stopOnFailure'] ?? false;
1116
        $arguments['stopOnIncomplete']                                = $arguments['stopOnIncomplete'] ?? false;
1117
        $arguments['stopOnRisky']                                     = $arguments['stopOnRisky'] ?? false;
1118
        $arguments['stopOnSkipped']                                   = $arguments['stopOnSkipped'] ?? false;
1119
        $arguments['stopOnWarning']                                   = $arguments['stopOnWarning'] ?? false;
1120
        $arguments['stopOnDefect']                                    = $arguments['stopOnDefect'] ?? false;
1121
        $arguments['strictCoverage']                                  = $arguments['strictCoverage'] ?? false;
1122
        $arguments['testdoxExcludeGroups']                            = $arguments['testdoxExcludeGroups'] ?? [];
1123
        $arguments['testdoxGroups']                                   = $arguments['testdoxGroups'] ?? [];
1124
        $arguments['timeoutForLargeTests']                            = $arguments['timeoutForLargeTests'] ?? 60;
1125
        $arguments['timeoutForMediumTests']                           = $arguments['timeoutForMediumTests'] ?? 10;
1126
        $arguments['timeoutForSmallTests']                            = $arguments['timeoutForSmallTests'] ?? 1;
1127
        $arguments['verbose']                                         = $arguments['verbose'] ?? false;
1128
 
1129
        if ($arguments['reportLowUpperBound'] > $arguments['reportHighLowerBound']) {
1130
            $arguments['reportLowUpperBound']  = 50;
1131
            $arguments['reportHighLowerBound'] = 90;
1132
        }
1133
    }
1134
 
1135
    private function processSuiteFilters(TestSuite $suite, array $arguments): void
1136
    {
1137
        if (!$arguments['filter'] &&
1138
            empty($arguments['groups']) &&
1139
            empty($arguments['excludeGroups']) &&
1140
            empty($arguments['testsCovering']) &&
1141
            empty($arguments['testsUsing'])) {
1142
            return;
1143
        }
1144
 
1145
        $filterFactory = new Factory;
1146
 
1147
        if (!empty($arguments['excludeGroups'])) {
1148
            $filterFactory->addFilter(
1149
                new ReflectionClass(ExcludeGroupFilterIterator::class),
1150
                $arguments['excludeGroups']
1151
            );
1152
        }
1153
 
1154
        if (!empty($arguments['groups'])) {
1155
            $filterFactory->addFilter(
1156
                new ReflectionClass(IncludeGroupFilterIterator::class),
1157
                $arguments['groups']
1158
            );
1159
        }
1160
 
1161
        if (!empty($arguments['testsCovering'])) {
1162
            $filterFactory->addFilter(
1163
                new ReflectionClass(IncludeGroupFilterIterator::class),
1164
                array_map(
1165
                    static function (string $name): string
1166
                    {
1167
                        return '__phpunit_covers_' . $name;
1168
                    },
1169
                    $arguments['testsCovering']
1170
                )
1171
            );
1172
        }
1173
 
1174
        if (!empty($arguments['testsUsing'])) {
1175
            $filterFactory->addFilter(
1176
                new ReflectionClass(IncludeGroupFilterIterator::class),
1177
                array_map(
1178
                    static function (string $name): string
1179
                    {
1180
                        return '__phpunit_uses_' . $name;
1181
                    },
1182
                    $arguments['testsUsing']
1183
                )
1184
            );
1185
        }
1186
 
1187
        if ($arguments['filter']) {
1188
            $filterFactory->addFilter(
1189
                new ReflectionClass(NameFilterIterator::class),
1190
                $arguments['filter']
1191
            );
1192
        }
1193
 
1194
        $suite->injectFilter($filterFactory);
1195
    }
1196
 
1197
    private function writeMessage(string $type, string $message): void
1198
    {
1199
        if (!$this->messagePrinted) {
1200
            $this->write("\n");
1201
        }
1202
 
1203
        $this->write(
1204
            sprintf(
1205
                "%-15s%s\n",
1206
                $type . ':',
1207
                $message
1208
            )
1209
        );
1210
 
1211
        $this->messagePrinted = true;
1212
    }
1213
 
1214
    private function createPrinter(string $class, array $arguments): ResultPrinter
1215
    {
1216
        $object = new $class(
1217
            (isset($arguments['stderr']) && $arguments['stderr'] === true) ? 'php://stderr' : null,
1218
            $arguments['verbose'],
1219
            $arguments['colors'],
1220
            $arguments['debug'],
1221
            $arguments['columns'],
1222
            $arguments['reverseList']
1223
        );
1224
 
1225
        assert($object instanceof ResultPrinter);
1226
 
1227
        return $object;
1228
    }
1229
 
1230
    private function codeCoverageGenerationStart(string $format): void
1231
    {
1232
        $this->write(
1233
            sprintf(
1234
                "\nGenerating code coverage report in %s format ... ",
1235
                $format
1236
            )
1237
        );
1238
 
1239
        $this->timer->start();
1240
    }
1241
 
1242
    private function codeCoverageGenerationSucceeded(): void
1243
    {
1244
        $this->write(
1245
            sprintf(
1246
                "done [%s]\n",
1247
                $this->timer->stop()->asString()
1248
            )
1249
        );
1250
    }
1251
 
1252
    private function codeCoverageGenerationFailed(\Exception $e): void
1253
    {
1254
        $this->write(
1255
            sprintf(
1256
                "failed [%s]\n%s\n",
1257
                $this->timer->stop()->asString(),
1258
                $e->getMessage()
1259
            )
1260
        );
1261
    }
1262
}