Completed
Push — master ( 01e071...007090 )
by Ehsan
01:46 queued 13s
created

TestResult   F

Complexity

Total Complexity 176

Size/Duplication

Total Lines 1273
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 21

Importance

Changes 0
Metric Value
dl 0
loc 1273
rs 0.6314
c 0
b 0
f 0
wmc 176
lcom 1
cbo 21

How to fix   Complexity   

Complex Class

Complex classes like TestResult often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use TestResult, and based on these observations, apply Extract Interface, too.

1
<?php
2
/*
3
 * This file is part of PHPUnit.
4
 *
5
 * (c) Sebastian Bergmann <[email protected]>
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 */
10
11
namespace PHPUnit\Framework;
12
13
use AssertionError;
14
use Countable;
15
use Error;
16
use PHP_Invoker;
17
use PHP_Timer;
18
use PHPUnit_Framework_MockObject_Exception;
19
use PHPUnit\Util\Blacklist;
20
use PHPUnit\Util\InvalidArgumentHelper;
21
use PHPUnit\Util\Printer;
22
use ReflectionClass;
23
use SebastianBergmann\CodeCoverage\CodeCoverage;
24
use SebastianBergmann\CodeCoverage\Exception as OriginalCodeCoverageException;
25
use SebastianBergmann\CodeCoverage\CoveredCodeNotExecutedException as OriginalCoveredCodeNotExecutedException;
26
use SebastianBergmann\CodeCoverage\MissingCoversAnnotationException as OriginalMissingCoversAnnotationException;
27
use SebastianBergmann\CodeCoverage\UnintentionallyCoveredCodeException;
28
use SebastianBergmann\ResourceOperations\ResourceOperations;
29
use Throwable;
30
31
/**
32
 * A TestResult collects the results of executing a test case.
33
 */
34
class TestResult implements Countable
35
{
36
    /**
37
     * @var array
38
     */
39
    protected $passed = [];
40
41
    /**
42
     * @var array
43
     */
44
    protected $errors = [];
45
46
    /**
47
     * @var array
48
     */
49
    protected $failures = [];
50
51
    /**
52
     * @var array
53
     */
54
    protected $warnings = [];
55
56
    /**
57
     * @var array
58
     */
59
    protected $notImplemented = [];
60
61
    /**
62
     * @var array
63
     */
64
    protected $risky = [];
65
66
    /**
67
     * @var array
68
     */
69
    protected $skipped = [];
70
71
    /**
72
     * @var array
73
     */
74
    protected $listeners = [];
75
76
    /**
77
     * @var int
78
     */
79
    protected $runTests = 0;
80
81
    /**
82
     * @var float
83
     */
84
    protected $time = 0;
85
86
    /**
87
     * @var TestSuite
88
     */
89
    protected $topTestSuite;
90
91
    /**
92
     * Code Coverage information.
93
     *
94
     * @var CodeCoverage
95
     */
96
    protected $codeCoverage;
97
98
    /**
99
     * @var bool
100
     */
101
    protected $convertErrorsToExceptions = true;
102
103
    /**
104
     * @var bool
105
     */
106
    protected $stop = false;
107
108
    /**
109
     * @var bool
110
     */
111
    protected $stopOnError = false;
112
113
    /**
114
     * @var bool
115
     */
116
    protected $stopOnFailure = false;
117
118
    /**
119
     * @var bool
120
     */
121
    protected $stopOnWarning = false;
122
123
    /**
124
     * @var bool
125
     */
126
    protected $beStrictAboutTestsThatDoNotTestAnything = true;
127
128
    /**
129
     * @var bool
130
     */
131
    protected $beStrictAboutOutputDuringTests = false;
132
133
    /**
134
     * @var bool
135
     */
136
    protected $beStrictAboutTodoAnnotatedTests = false;
137
138
    /**
139
     * @var bool
140
     */
141
    protected $beStrictAboutResourceUsageDuringSmallTests = false;
142
143
    /**
144
     * @var bool
145
     */
146
    protected $enforceTimeLimit = false;
147
148
    /**
149
     * @var int
150
     */
151
    protected $timeoutForSmallTests = 1;
152
153
    /**
154
     * @var int
155
     */
156
    protected $timeoutForMediumTests = 10;
157
158
    /**
159
     * @var int
160
     */
161
    protected $timeoutForLargeTests = 60;
162
163
    /**
164
     * @var bool
165
     */
166
    protected $stopOnRisky = false;
167
168
    /**
169
     * @var bool
170
     */
171
    protected $stopOnIncomplete = false;
172
173
    /**
174
     * @var bool
175
     */
176
    protected $stopOnSkipped = false;
177
178
    /**
179
     * @var bool
180
     */
181
    protected $lastTestFailed = false;
182
183
    /**
184
     * @var bool
185
     */
186
    private $registerMockObjectsFromTestArgumentsRecursively = false;
187
188
    /**
189
     * Registers a TestListener.
190
     *
191
     * @param TestListener $listener
192
     */
193
    public function addListener(TestListener $listener)
194
    {
195
        $this->listeners[] = $listener;
196
    }
197
198
    /**
199
     * Unregisters a TestListener.
200
     *
201
     * @param TestListener $listener
202
     */
203
    public function removeListener(TestListener $listener)
204
    {
205
        foreach ($this->listeners as $key => $_listener) {
206
            if ($listener === $_listener) {
207
                unset($this->listeners[$key]);
208
            }
209
        }
210
    }
211
212
    /**
213
     * Flushes all flushable TestListeners.
214
     */
215
    public function flushListeners()
216
    {
217
        foreach ($this->listeners as $listener) {
218
            if ($listener instanceof Printer) {
219
                $listener->flush();
220
            }
221
        }
222
    }
223
224
    /**
225
     * Adds an error to the list of errors.
226
     *
227
     * @param Test      $test
228
     * @param Throwable $t
229
     * @param float     $time
230
     */
231
    public function addError(Test $test, Throwable $t, $time)
232
    {
233
        if ($t instanceof RiskyTest) {
234
            $this->risky[] = new TestFailure($test, $t);
235
            $notifyMethod  = 'addRiskyTest';
236
237
            if ($test instanceof TestCase) {
238
                $test->markAsRisky();
239
            }
240
241
            if ($this->stopOnRisky) {
242
                $this->stop();
243
            }
244
        } elseif ($t instanceof IncompleteTest) {
245
            $this->notImplemented[] = new TestFailure($test, $t);
246
            $notifyMethod           = 'addIncompleteTest';
247
248
            if ($this->stopOnIncomplete) {
249
                $this->stop();
250
            }
251
        } elseif ($t instanceof SkippedTest) {
252
            $this->skipped[] = new TestFailure($test, $t);
253
            $notifyMethod    = 'addSkippedTest';
254
255
            if ($this->stopOnSkipped) {
256
                $this->stop();
257
            }
258
        } else {
259
            $this->errors[] = new TestFailure($test, $t);
260
            $notifyMethod   = 'addError';
261
262
            if ($this->stopOnError || $this->stopOnFailure) {
263
                $this->stop();
264
            }
265
        }
266
267
        // @see https://github.com/sebastianbergmann/phpunit/issues/1953
268
        if ($t instanceof Error) {
269
            $t = new ExceptionWrapper($t);
270
        }
271
272
        foreach ($this->listeners as $listener) {
273
            $listener->$notifyMethod($test, $t, $time);
274
        }
275
276
        $this->lastTestFailed = true;
277
        $this->time += $time;
278
    }
279
280
    /**
281
     * Adds a warning to the list of warnings.
282
     * The passed in exception caused the warning.
283
     *
284
     * @param Test    $test
285
     * @param Warning $e
286
     * @param float   $time
287
     */
288
    public function addWarning(Test $test, Warning $e, $time)
289
    {
290
        if ($this->stopOnWarning) {
291
            $this->stop();
292
        }
293
294
        $this->warnings[] = new TestFailure($test, $e);
295
296
        foreach ($this->listeners as $listener) {
297
            $listener->addWarning($test, $e, $time);
298
        }
299
300
        $this->time += $time;
301
    }
302
303
    /**
304
     * Adds a failure to the list of failures.
305
     * The passed in exception caused the failure.
306
     *
307
     * @param Test                 $test
308
     * @param AssertionFailedError $e
309
     * @param float                $time
310
     */
311
    public function addFailure(Test $test, AssertionFailedError $e, $time)
312
    {
313
        if ($e instanceof RiskyTest || $e instanceof OutputError) {
314
            $this->risky[] = new TestFailure($test, $e);
315
            $notifyMethod  = 'addRiskyTest';
316
317
            if ($test instanceof TestCase) {
318
                $test->markAsRisky();
319
            }
320
321
            if ($this->stopOnRisky) {
322
                $this->stop();
323
            }
324
        } elseif ($e instanceof IncompleteTest) {
325
            $this->notImplemented[] = new TestFailure($test, $e);
326
            $notifyMethod           = 'addIncompleteTest';
327
328
            if ($this->stopOnIncomplete) {
329
                $this->stop();
330
            }
331
        } elseif ($e instanceof SkippedTest) {
332
            $this->skipped[] = new TestFailure($test, $e);
333
            $notifyMethod    = 'addSkippedTest';
334
335
            if ($this->stopOnSkipped) {
336
                $this->stop();
337
            }
338
        } else {
339
            $this->failures[] = new TestFailure($test, $e);
340
            $notifyMethod     = 'addFailure';
341
342
            if ($this->stopOnFailure) {
343
                $this->stop();
344
            }
345
        }
346
347
        foreach ($this->listeners as $listener) {
348
            $listener->$notifyMethod($test, $e, $time);
349
        }
350
351
        $this->lastTestFailed = true;
352
        $this->time += $time;
353
    }
354
355
    /**
356
     * Informs the result that a testsuite will be started.
357
     *
358
     * @param TestSuite $suite
359
     */
360
    public function startTestSuite(TestSuite $suite)
361
    {
362
        if ($this->topTestSuite === null) {
363
            $this->topTestSuite = $suite;
364
        }
365
366
        foreach ($this->listeners as $listener) {
367
            $listener->startTestSuite($suite);
368
        }
369
    }
370
371
    /**
372
     * Informs the result that a testsuite was completed.
373
     *
374
     * @param TestSuite $suite
375
     */
376
    public function endTestSuite(TestSuite $suite)
377
    {
378
        foreach ($this->listeners as $listener) {
379
            $listener->endTestSuite($suite);
380
        }
381
    }
382
383
    /**
384
     * Informs the result that a test will be started.
385
     *
386
     * @param Test $test
387
     */
388
    public function startTest(Test $test)
389
    {
390
        $this->lastTestFailed = false;
391
        $this->runTests += \count($test);
392
393
        foreach ($this->listeners as $listener) {
394
            $listener->startTest($test);
395
        }
396
    }
397
398
    /**
399
     * Informs the result that a test was completed.
400
     *
401
     * @param Test  $test
402
     * @param float $time
403
     */
404
    public function endTest(Test $test, $time)
405
    {
406
        foreach ($this->listeners as $listener) {
407
            $listener->endTest($test, $time);
408
        }
409
410
        if (!$this->lastTestFailed && $test instanceof TestCase) {
411
            $class = \get_class($test);
412
            $key   = $class . '::' . $test->getName();
413
414
            $this->passed[$key] = [
415
                'result' => $test->getResult(),
416
                'size'   => \PHPUnit\Util\Test::getSize(
417
                    $class,
418
                    $test->getName(false)
419
                )
420
            ];
421
422
            $this->time += $time;
423
        }
424
    }
425
426
    /**
427
     * Returns true if no risky test occurred.
428
     *
429
     * @return bool
430
     */
431
    public function allHarmless()
432
    {
433
        return $this->riskyCount() == 0;
434
    }
435
436
    /**
437
     * Gets the number of risky tests.
438
     *
439
     * @return int
440
     */
441
    public function riskyCount()
442
    {
443
        return \count($this->risky);
444
    }
445
446
    /**
447
     * Returns true if no incomplete test occurred.
448
     *
449
     * @return bool
450
     */
451
    public function allCompletelyImplemented()
452
    {
453
        return $this->notImplementedCount() == 0;
454
    }
455
456
    /**
457
     * Gets the number of incomplete tests.
458
     *
459
     * @return int
460
     */
461
    public function notImplementedCount()
462
    {
463
        return \count($this->notImplemented);
464
    }
465
466
    /**
467
     * Returns an Enumeration for the risky tests.
468
     *
469
     * @return array
470
     */
471
    public function risky()
472
    {
473
        return $this->risky;
474
    }
475
476
    /**
477
     * Returns an Enumeration for the incomplete tests.
478
     *
479
     * @return array
480
     */
481
    public function notImplemented()
482
    {
483
        return $this->notImplemented;
484
    }
485
486
    /**
487
     * Returns true if no test has been skipped.
488
     *
489
     * @return bool
490
     */
491
    public function noneSkipped()
492
    {
493
        return $this->skippedCount() == 0;
494
    }
495
496
    /**
497
     * Gets the number of skipped tests.
498
     *
499
     * @return int
500
     */
501
    public function skippedCount()
502
    {
503
        return \count($this->skipped);
504
    }
505
506
    /**
507
     * Returns an Enumeration for the skipped tests.
508
     *
509
     * @return array
510
     */
511
    public function skipped()
512
    {
513
        return $this->skipped;
514
    }
515
516
    /**
517
     * Gets the number of detected errors.
518
     *
519
     * @return int
520
     */
521
    public function errorCount()
522
    {
523
        return \count($this->errors);
524
    }
525
526
    /**
527
     * Returns an Enumeration for the errors.
528
     *
529
     * @return array
530
     */
531
    public function errors()
532
    {
533
        return $this->errors;
534
    }
535
536
    /**
537
     * Gets the number of detected failures.
538
     *
539
     * @return int
540
     */
541
    public function failureCount()
542
    {
543
        return \count($this->failures);
544
    }
545
546
    /**
547
     * Returns an Enumeration for the failures.
548
     *
549
     * @return array
550
     */
551
    public function failures()
552
    {
553
        return $this->failures;
554
    }
555
556
    /**
557
     * Gets the number of detected warnings.
558
     *
559
     * @return int
560
     */
561
    public function warningCount()
562
    {
563
        return \count($this->warnings);
564
    }
565
566
    /**
567
     * Returns an Enumeration for the warnings.
568
     *
569
     * @return array
570
     */
571
    public function warnings()
572
    {
573
        return $this->warnings;
574
    }
575
576
    /**
577
     * Returns the names of the tests that have passed.
578
     *
579
     * @return array
580
     */
581
    public function passed()
582
    {
583
        return $this->passed;
584
    }
585
586
    /**
587
     * Returns the (top) test suite.
588
     *
589
     * @return TestSuite
590
     */
591
    public function topTestSuite()
592
    {
593
        return $this->topTestSuite;
594
    }
595
596
    /**
597
     * Returns whether code coverage information should be collected.
598
     *
599
     * @return bool If code coverage should be collected
600
     */
601
    public function getCollectCodeCoverageInformation()
602
    {
603
        return $this->codeCoverage !== null;
604
    }
605
606
    /**
607
     * Runs a TestCase.
608
     *
609
     * @param Test $test
610
     */
611
    public function run(Test $test)
612
    {
613
        Assert::resetCount();
614
615
        $coversNothing = false;
616
617
        if ($test instanceof TestCase) {
618
            $test->setRegisterMockObjectsFromTestArgumentsRecursively(
619
                $this->registerMockObjectsFromTestArgumentsRecursively
620
            );
621
622
            $annotations = $test->getAnnotations();
623
624
            if (isset($annotations['class']['coversNothing']) || isset($annotations['method']['coversNothing'])) {
625
                $coversNothing = true;
626
            }
627
        }
628
629
        $error      = false;
630
        $failure    = false;
631
        $warning    = false;
632
        $incomplete = false;
633
        $risky      = false;
634
        $skipped    = false;
635
636
        $this->startTest($test);
637
638
        $errorHandlerSet = false;
639
640
        if ($this->convertErrorsToExceptions) {
641
            $oldErrorHandler = \set_error_handler(
642
                [\PHPUnit\Util\ErrorHandler::class, 'handleError'],
643
                E_ALL | E_STRICT
644
            );
645
646
            if ($oldErrorHandler === null) {
647
                $errorHandlerSet = true;
648
            } else {
649
                \restore_error_handler();
650
            }
651
        }
652
653
        $collectCodeCoverage = $this->codeCoverage !== null &&
654
                               !$test instanceof WarningTestCase &&
655
                               !$coversNothing;
656
657
        if ($collectCodeCoverage) {
658
            $this->codeCoverage->start($test);
659
        }
660
661
        $monitorFunctions = $this->beStrictAboutResourceUsageDuringSmallTests &&
662
            !$test instanceof WarningTestCase &&
663
            $test->getSize() == \PHPUnit\Util\Test::SMALL &&
664
            \function_exists('xdebug_start_function_monitor');
665
666
        if ($monitorFunctions) {
667
            \xdebug_start_function_monitor(ResourceOperations::getFunctions());
668
        }
669
670
        PHP_Timer::start();
671
672
        try {
673
            if (!$test instanceof WarningTestCase &&
674
                $test->getSize() != \PHPUnit\Util\Test::UNKNOWN &&
675
                $this->enforceTimeLimit &&
676
                \extension_loaded('pcntl') && \class_exists('PHP_Invoker')) {
677
                switch ($test->getSize()) {
678
                    case \PHPUnit\Util\Test::SMALL:
679
                        $_timeout = $this->timeoutForSmallTests;
680
                        break;
681
682
                    case \PHPUnit\Util\Test::MEDIUM:
683
                        $_timeout = $this->timeoutForMediumTests;
684
                        break;
685
686
                    case \PHPUnit\Util\Test::LARGE:
687
                        $_timeout = $this->timeoutForLargeTests;
688
                        break;
689
                }
690
691
                $invoker = new PHP_Invoker;
692
                $invoker->invoke([$test, 'runBare'], [], $_timeout);
693
            } else {
694
                $test->runBare();
695
            }
696
        } catch (PHP_Invoker_TimeoutException $e) {
697
            $this->addFailure(
698
                $test,
699
                new PHPUnit_Framework_RiskyTestError(
700
                    $e->getMessage()
701
                ),
702
                $_timeout
703
            );
704
705
            $risky = true;
706
        } catch (PHPUnit_Framework_MockObject_Exception $e) {
707
            $e = new Warning(
708
                $e->getMessage()
709
            );
710
711
            $warning = true;
712
        } catch (AssertionFailedError $e) {
713
            $failure = true;
714
715
            if ($e instanceof RiskyTestError) {
716
                $risky = true;
717
            } elseif ($e instanceof IncompleteTestError) {
718
                $incomplete = true;
719
            } elseif ($e instanceof SkippedTestError) {
720
                $skipped = true;
721
            }
722
        } catch (AssertionError $e) {
723
            $test->addToAssertionCount(1);
724
725
            $failure = true;
726
            $frame   = $e->getTrace()[0];
727
728
            $e = new AssertionFailedError(
729
                \sprintf(
730
                    '%s in %s:%s',
731
                    $e->getMessage(),
732
                    $frame['file'],
733
                    $frame['line']
734
                )
735
            );
736
        } catch (Warning $e) {
737
            $warning = true;
738
        } catch (Exception $e) {
739
            $error = true;
740
        } catch (Throwable $e) {
741
            $e     = new ExceptionWrapper($e);
742
            $error = true;
743
        }
744
745
        $time = PHP_Timer::stop();
746
        $test->addToAssertionCount(Assert::getCount());
747
748
        if ($monitorFunctions) {
749
            $blacklist = new Blacklist;
750
            $functions = \xdebug_get_monitored_functions();
751
            \xdebug_stop_function_monitor();
752
753
            foreach ($functions as $function) {
754
                if (!$blacklist->isBlacklisted($function['filename'])) {
755
                    $this->addFailure(
756
                        $test,
757
                        new RiskyTestError(
758
                            \sprintf(
759
                                '%s() used in %s:%s',
760
                                $function['function'],
761
                                $function['filename'],
762
                                $function['lineno']
763
                            )
764
                        ),
765
                        $time
766
                    );
767
                }
768
            }
769
        }
770
771
        if ($this->beStrictAboutTestsThatDoNotTestAnything &&
772
            $test->getNumAssertions() == 0) {
773
            $risky = true;
774
        }
775
776
        if ($collectCodeCoverage) {
777
            $append           = !$risky && !$incomplete && !$skipped;
778
            $linesToBeCovered = [];
779
            $linesToBeUsed    = [];
780
781
            if ($append && $test instanceof TestCase) {
782
                try {
783
                    $linesToBeCovered = \PHPUnit\Util\Test::getLinesToBeCovered(
784
                        \get_class($test),
785
                        $test->getName(false)
786
                    );
787
788
                    $linesToBeUsed = \PHPUnit\Util\Test::getLinesToBeUsed(
789
                        \get_class($test),
790
                        $test->getName(false)
791
                    );
792
                } catch (InvalidCoversTargetException $cce) {
793
                    $this->addWarning(
794
                        $test,
795
                        new Warning(
796
                            $cce->getMessage()
797
                        ),
798
                        $time
799
                    );
800
                }
801
            }
802
803
            try {
804
                $this->codeCoverage->stop(
805
                    $append,
806
                    $linesToBeCovered,
807
                    $linesToBeUsed
808
                );
809
            } catch (UnintentionallyCoveredCodeException $cce) {
810
                $this->addFailure(
811
                    $test,
812
                    new UnintentionallyCoveredCodeError(
813
                        'This test executed code that is not listed as code to be covered or used:' .
814
                        PHP_EOL . $cce->getMessage()
815
                    ),
816
                    $time
817
                );
818
            } catch (OriginalCoveredCodeNotExecutedException $cce) {
819
                $this->addFailure(
820
                    $test,
821
                    new CoveredCodeNotExecutedException(
822
                        'This test did not execute all the code that is listed as code to be covered:' .
823
                        PHP_EOL . $cce->getMessage()
824
                    ),
825
                    $time
826
                );
827
            } catch (OriginalMissingCoversAnnotationException $cce) {
828
                if ($linesToBeCovered !== false) {
829
                    $this->addFailure(
830
                        $test,
831
                        new MissingCoversAnnotationException(
832
                            'This test does not have a @covers annotation but is expected to have one'
833
                        ),
834
                        $time
835
                    );
836
                }
837
            } catch (OriginalCodeCoverageException $cce) {
838
                $error = true;
839
840
                if (!isset($e)) {
841
                    $e = $cce;
842
                }
843
            }
844
        }
845
846
        if ($errorHandlerSet === true) {
847
            \restore_error_handler();
848
        }
849
850
        if ($error === true) {
851
            $this->addError($test, $e, $time);
852
        } elseif ($failure === true) {
853
            $this->addFailure($test, $e, $time);
854
        } elseif ($warning === true) {
855
            $this->addWarning($test, $e, $time);
856
        } elseif ($this->beStrictAboutTestsThatDoNotTestAnything &&
857
            !$test->doesNotPerformAssertions() &&
858
            $test->getNumAssertions() == 0) {
859
            $this->addFailure(
860
                $test,
861
                new RiskyTestError(
862
                    'This test did not perform any assertions'
863
                ),
864
                $time
865
            );
866
        } elseif ($this->beStrictAboutOutputDuringTests && $test->hasOutput()) {
867
            $this->addFailure(
868
                $test,
869
                new OutputError(
870
                    \sprintf(
871
                        'This test printed output: %s',
872
                        $test->getActualOutput()
873
                    )
874
                ),
875
                $time
876
            );
877
        } elseif ($this->beStrictAboutTodoAnnotatedTests && $test instanceof TestCase) {
878
            $annotations = $test->getAnnotations();
879
880
            if (isset($annotations['method']['todo'])) {
881
                $this->addFailure(
882
                    $test,
883
                    new RiskyTestError(
884
                        'Test method is annotated with @todo'
885
                    ),
886
                    $time
887
                );
888
            }
889
        }
890
891
        $this->endTest($test, $time);
892
    }
893
894
    /**
895
     * Gets the number of run tests.
896
     *
897
     * @return int
898
     */
899
    public function count()
900
    {
901
        return $this->runTests;
902
    }
903
904
    /**
905
     * Checks whether the test run should stop.
906
     *
907
     * @return bool
908
     */
909
    public function shouldStop()
910
    {
911
        return $this->stop;
912
    }
913
914
    /**
915
     * Marks that the test run should stop.
916
     */
917
    public function stop()
918
    {
919
        $this->stop = true;
920
    }
921
922
    /**
923
     * Returns the code coverage object.
924
     *
925
     * @return CodeCoverage
926
     */
927
    public function getCodeCoverage()
928
    {
929
        return $this->codeCoverage;
930
    }
931
932
    /**
933
     * Sets the code coverage object.
934
     *
935
     * @param CodeCoverage $codeCoverage
936
     */
937
    public function setCodeCoverage(CodeCoverage $codeCoverage)
938
    {
939
        $this->codeCoverage = $codeCoverage;
940
    }
941
942
    /**
943
     * Enables or disables the error-to-exception conversion.
944
     *
945
     * @param bool $flag
946
     *
947
     * @throws Exception
948
     */
949
    public function convertErrorsToExceptions($flag)
950
    {
951
        if (!\is_bool($flag)) {
952
            throw InvalidArgumentHelper::factory(1, 'boolean');
953
        }
954
955
        $this->convertErrorsToExceptions = $flag;
956
    }
957
958
    /**
959
     * Returns the error-to-exception conversion setting.
960
     *
961
     * @return bool
962
     */
963
    public function getConvertErrorsToExceptions()
964
    {
965
        return $this->convertErrorsToExceptions;
966
    }
967
968
    /**
969
     * Enables or disables the stopping when an error occurs.
970
     *
971
     * @param bool $flag
972
     *
973
     * @throws Exception
974
     */
975
    public function stopOnError($flag)
976
    {
977
        if (!\is_bool($flag)) {
978
            throw InvalidArgumentHelper::factory(1, 'boolean');
979
        }
980
981
        $this->stopOnError = $flag;
982
    }
983
984
    /**
985
     * Enables or disables the stopping when a failure occurs.
986
     *
987
     * @param bool $flag
988
     *
989
     * @throws Exception
990
     */
991
    public function stopOnFailure($flag)
992
    {
993
        if (!\is_bool($flag)) {
994
            throw InvalidArgumentHelper::factory(1, 'boolean');
995
        }
996
997
        $this->stopOnFailure = $flag;
998
    }
999
1000
    /**
1001
     * Enables or disables the stopping when a warning occurs.
1002
     *
1003
     * @param bool $flag
1004
     *
1005
     * @throws Exception
1006
     */
1007
    public function stopOnWarning($flag)
1008
    {
1009
        if (!\is_bool($flag)) {
1010
            throw InvalidArgumentHelper::factory(1, 'boolean');
1011
        }
1012
1013
        $this->stopOnWarning = $flag;
1014
    }
1015
1016
    /**
1017
     * @param bool $flag
1018
     *
1019
     * @throws Exception
1020
     */
1021
    public function beStrictAboutTestsThatDoNotTestAnything($flag)
1022
    {
1023
        if (!\is_bool($flag)) {
1024
            throw InvalidArgumentHelper::factory(1, 'boolean');
1025
        }
1026
1027
        $this->beStrictAboutTestsThatDoNotTestAnything = $flag;
1028
    }
1029
1030
    /**
1031
     * @return bool
1032
     */
1033
    public function isStrictAboutTestsThatDoNotTestAnything()
1034
    {
1035
        return $this->beStrictAboutTestsThatDoNotTestAnything;
1036
    }
1037
1038
    /**
1039
     * @param bool $flag
1040
     *
1041
     * @throws Exception
1042
     */
1043
    public function beStrictAboutOutputDuringTests($flag)
1044
    {
1045
        if (!\is_bool($flag)) {
1046
            throw InvalidArgumentHelper::factory(1, 'boolean');
1047
        }
1048
1049
        $this->beStrictAboutOutputDuringTests = $flag;
1050
    }
1051
1052
    /**
1053
     * @return bool
1054
     */
1055
    public function isStrictAboutOutputDuringTests()
1056
    {
1057
        return $this->beStrictAboutOutputDuringTests;
1058
    }
1059
1060
    /**
1061
     * @param bool $flag
1062
     *
1063
     * @throws Exception
1064
     */
1065
    public function beStrictAboutResourceUsageDuringSmallTests($flag)
1066
    {
1067
        if (!\is_bool($flag)) {
1068
            throw InvalidArgumentHelper::factory(1, 'boolean');
1069
        }
1070
1071
        $this->beStrictAboutResourceUsageDuringSmallTests = $flag;
1072
    }
1073
1074
    /**
1075
     * @return bool
1076
     */
1077
    public function isStrictAboutResourceUsageDuringSmallTests()
1078
    {
1079
        return $this->beStrictAboutResourceUsageDuringSmallTests;
1080
    }
1081
1082
    /**
1083
     * @param bool $flag
1084
     *
1085
     * @throws Exception
1086
     */
1087
    public function enforceTimeLimit($flag)
1088
    {
1089
        if (!\is_bool($flag)) {
1090
            throw InvalidArgumentHelper::factory(1, 'boolean');
1091
        }
1092
1093
        $this->enforceTimeLimit = $flag;
1094
    }
1095
1096
    /**
1097
     * @return bool
1098
     */
1099
    public function enforcesTimeLimit()
1100
    {
1101
        return $this->enforceTimeLimit;
1102
    }
1103
1104
    /**
1105
     * @param bool $flag
1106
     *
1107
     * @throws Exception
1108
     */
1109
    public function beStrictAboutTodoAnnotatedTests($flag)
1110
    {
1111
        if (!\is_bool($flag)) {
1112
            throw InvalidArgumentHelper::factory(1, 'boolean');
1113
        }
1114
1115
        $this->beStrictAboutTodoAnnotatedTests = $flag;
1116
    }
1117
1118
    /**
1119
     * @return bool
1120
     */
1121
    public function isStrictAboutTodoAnnotatedTests()
1122
    {
1123
        return $this->beStrictAboutTodoAnnotatedTests;
1124
    }
1125
1126
    /**
1127
     * Enables or disables the stopping for risky tests.
1128
     *
1129
     * @param bool $flag
1130
     *
1131
     * @throws Exception
1132
     */
1133
    public function stopOnRisky($flag)
1134
    {
1135
        if (!\is_bool($flag)) {
1136
            throw InvalidArgumentHelper::factory(1, 'boolean');
1137
        }
1138
1139
        $this->stopOnRisky = $flag;
1140
    }
1141
1142
    /**
1143
     * Enables or disables the stopping for incomplete tests.
1144
     *
1145
     * @param bool $flag
1146
     *
1147
     * @throws Exception
1148
     */
1149
    public function stopOnIncomplete($flag)
1150
    {
1151
        if (!\is_bool($flag)) {
1152
            throw InvalidArgumentHelper::factory(1, 'boolean');
1153
        }
1154
1155
        $this->stopOnIncomplete = $flag;
1156
    }
1157
1158
    /**
1159
     * Enables or disables the stopping for skipped tests.
1160
     *
1161
     * @param bool $flag
1162
     *
1163
     * @throws Exception
1164
     */
1165
    public function stopOnSkipped($flag)
1166
    {
1167
        if (!\is_bool($flag)) {
1168
            throw InvalidArgumentHelper::factory(1, 'boolean');
1169
        }
1170
1171
        $this->stopOnSkipped = $flag;
1172
    }
1173
1174
    /**
1175
     * Returns the time spent running the tests.
1176
     *
1177
     * @return float
1178
     */
1179
    public function time()
1180
    {
1181
        return $this->time;
1182
    }
1183
1184
    /**
1185
     * Returns whether the entire test was successful or not.
1186
     *
1187
     * @return bool
1188
     */
1189
    public function wasSuccessful()
1190
    {
1191
        return empty($this->errors) && empty($this->failures) && empty($this->warnings);
1192
    }
1193
1194
    /**
1195
     * Sets the timeout for small tests.
1196
     *
1197
     * @param int $timeout
1198
     *
1199
     * @throws Exception
1200
     */
1201
    public function setTimeoutForSmallTests($timeout)
1202
    {
1203
        if (!\is_int($timeout)) {
1204
            throw InvalidArgumentHelper::factory(1, 'integer');
1205
        }
1206
1207
        $this->timeoutForSmallTests = $timeout;
1208
    }
1209
1210
    /**
1211
     * Sets the timeout for medium tests.
1212
     *
1213
     * @param int $timeout
1214
     *
1215
     * @throws Exception
1216
     */
1217
    public function setTimeoutForMediumTests($timeout)
1218
    {
1219
        if (!\is_int($timeout)) {
1220
            throw InvalidArgumentHelper::factory(1, 'integer');
1221
        }
1222
1223
        $this->timeoutForMediumTests = $timeout;
1224
    }
1225
1226
    /**
1227
     * Sets the timeout for large tests.
1228
     *
1229
     * @param int $timeout
1230
     *
1231
     * @throws Exception
1232
     */
1233
    public function setTimeoutForLargeTests($timeout)
1234
    {
1235
        if (!\is_int($timeout)) {
1236
            throw InvalidArgumentHelper::factory(1, 'integer');
1237
        }
1238
1239
        $this->timeoutForLargeTests = $timeout;
1240
    }
1241
1242
    /**
1243
     * Returns the set timeout for large tests.
1244
     *
1245
     * @return int
1246
     */
1247
    public function getTimeoutForLargeTests()
1248
    {
1249
        return $this->timeoutForLargeTests;
1250
    }
1251
1252
    /**
1253
     * @param bool $flag
1254
     */
1255
    public function setRegisterMockObjectsFromTestArgumentsRecursively($flag)
1256
    {
1257
        if (!\is_bool($flag)) {
1258
            throw InvalidArgumentHelper::factory(1, 'boolean');
1259
        }
1260
1261
        $this->registerMockObjectsFromTestArgumentsRecursively = $flag;
1262
    }
1263
1264
    /**
1265
     * Returns the class hierarchy for a given class.
1266
     *
1267
     * @param string $className
1268
     * @param bool   $asReflectionObjects
1269
     *
1270
     * @return array
1271
     */
1272
    protected function getHierarchy($className, $asReflectionObjects = false)
1273
    {
1274
        if ($asReflectionObjects) {
1275
            $classes = [new ReflectionClass($className)];
1276
        } else {
1277
            $classes = [$className];
1278
        }
1279
1280
        $done = false;
1281
1282
        while (!$done) {
1283
            if ($asReflectionObjects) {
1284
                $class = new ReflectionClass(
1285
                    $classes[\count($classes) - 1]->getName()
1286
                );
1287
            } else {
1288
                $class = new ReflectionClass($classes[\count($classes) - 1]);
1289
            }
1290
1291
            $parent = $class->getParentClass();
1292
1293
            if ($parent !== false) {
1294
                if ($asReflectionObjects) {
1295
                    $classes[] = $parent;
1296
                } else {
1297
                    $classes[] = $parent->getName();
1298
                }
1299
            } else {
1300
                $done = true;
1301
            }
1302
        }
1303
1304
        return $classes;
1305
    }
1306
}
1307