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