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\GlobalState\Snapshot;
12use SebastianBergmann\GlobalState\Restorer;
13use SebastianBergmann\GlobalState\Blacklist;
14use SebastianBergmann\Diff\Differ;
15use SebastianBergmann\Exporter\Exporter;
16use SebastianBergmann\ObjectEnumerator\Enumerator;
17use Prophecy\Exception\Prediction\PredictionException;
18use Prophecy\Prophet;
19use DeepCopy\DeepCopy;
20
21/**
22 * A TestCase defines the fixture to run multiple tests.
23 *
24 * To define a TestCase
25 *
26 *   1) Implement a subclass of PHPUnit_Framework_TestCase.
27 *   2) Define instance variables that store the state of the fixture.
28 *   3) Initialize the fixture state by overriding setUp().
29 *   4) Clean-up after a test by overriding tearDown().
30 *
31 * Each test runs in its own fixture so there can be no side effects
32 * among test runs.
33 *
34 * Here is an example:
35 *
36 * <code>
37 * <?php
38 * class MathTest extends PHPUnit_Framework_TestCase
39 * {
40 *     public $value1;
41 *     public $value2;
42 *
43 *     protected function setUp()
44 *     {
45 *         $this->value1 = 2;
46 *         $this->value2 = 3;
47 *     }
48 * }
49 * ?>
50 * </code>
51 *
52 * For each test implement a method which interacts with the fixture.
53 * Verify the expected results with assertions specified by calling
54 * assert with a boolean.
55 *
56 * <code>
57 * <?php
58 * public function testPass()
59 * {
60 *     $this->assertTrue($this->value1 + $this->value2 == 5);
61 * }
62 * ?>
63 * </code>
64 */
65abstract class PHPUnit_Framework_TestCase extends PHPUnit_Framework_Assert implements PHPUnit_Framework_Test, PHPUnit_Framework_SelfDescribing
66{
67    /**
68     * Enable or disable the backup and restoration of the $GLOBALS array.
69     * Overwrite this attribute in a child class of TestCase.
70     * Setting this attribute in setUp() has no effect!
71     *
72     * @var bool
73     */
74    protected $backupGlobals = null;
75
76    /**
77     * @var array
78     */
79    protected $backupGlobalsBlacklist = [];
80
81    /**
82     * Enable or disable the backup and restoration of static attributes.
83     * Overwrite this attribute in a child class of TestCase.
84     * Setting this attribute in setUp() has no effect!
85     *
86     * @var bool
87     */
88    protected $backupStaticAttributes = null;
89
90    /**
91     * @var array
92     */
93    protected $backupStaticAttributesBlacklist = [];
94
95    /**
96     * Whether or not this test is to be run in a separate PHP process.
97     *
98     * @var bool
99     */
100    protected $runTestInSeparateProcess = null;
101
102    /**
103     * Whether or not this test should preserve the global state when
104     * running in a separate PHP process.
105     *
106     * @var bool
107     */
108    protected $preserveGlobalState = true;
109
110    /**
111     * Whether or not this test is running in a separate PHP process.
112     *
113     * @var bool
114     */
115    private $inIsolation = false;
116
117    /**
118     * @var array
119     */
120    private $data = [];
121
122    /**
123     * @var string
124     */
125    private $dataName = '';
126
127    /**
128     * @var bool
129     */
130    private $useErrorHandler = null;
131
132    /**
133     * The name of the expected Exception.
134     *
135     * @var string
136     */
137    private $expectedException = null;
138
139    /**
140     * The message of the expected Exception.
141     *
142     * @var string
143     */
144    private $expectedExceptionMessage = null;
145
146    /**
147     * The regex pattern to validate the expected Exception message.
148     *
149     * @var string
150     */
151    private $expectedExceptionMessageRegExp = null;
152
153    /**
154     * The code of the expected Exception.
155     *
156     * @var int|string
157     */
158    private $expectedExceptionCode = null;
159
160    /**
161     * The name of the test case.
162     *
163     * @var string
164     */
165    private $name = null;
166
167    /**
168     * @var array
169     */
170    private $dependencies = [];
171
172    /**
173     * @var array
174     */
175    private $dependencyInput = [];
176
177    /**
178     * @var array
179     */
180    private $iniSettings = [];
181
182    /**
183     * @var array
184     */
185    private $locale = [];
186
187    /**
188     * @var array
189     */
190    private $mockObjects = [];
191
192    /**
193     * @var MockGenerator
194     */
195    private $mockObjectGenerator = null;
196
197    /**
198     * @var int
199     */
200    private $status;
201
202    /**
203     * @var string
204     */
205    private $statusMessage = '';
206
207    /**
208     * @var int
209     */
210    private $numAssertions = 0;
211
212    /**
213     * @var PHPUnit_Framework_TestResult
214     */
215    private $result;
216
217    /**
218     * @var mixed
219     */
220    private $testResult;
221
222    /**
223     * @var string
224     */
225    private $output = '';
226
227    /**
228     * @var string
229     */
230    private $outputExpectedRegex = null;
231
232    /**
233     * @var string
234     */
235    private $outputExpectedString = null;
236
237    /**
238     * @var mixed
239     */
240    private $outputCallback = false;
241
242    /**
243     * @var bool
244     */
245    private $outputBufferingActive = false;
246
247    /**
248     * @var int
249     */
250    private $outputBufferingLevel;
251
252    /**
253     * @var SebastianBergmann\GlobalState\Snapshot
254     */
255    private $snapshot;
256
257    /**
258     * @var Prophecy\Prophet
259     */
260    private $prophet;
261
262    /**
263     * @var bool
264     */
265    private $beStrictAboutChangesToGlobalState = false;
266
267    /**
268     * @var bool
269     */
270    private $registerMockObjectsFromTestArgumentsRecursively = false;
271
272    /**
273     * @var string[]
274     */
275    private $warnings = [];
276
277    /**
278     * @var array
279     */
280    private $groups = [];
281
282    /**
283     * @var bool
284     */
285    private $doesNotPerformAssertions = false;
286
287    /**
288     * Constructs a test case with the given name.
289     *
290     * @param string $name
291     * @param array  $data
292     * @param string $dataName
293     */
294    public function __construct($name = null, array $data = [], $dataName = '')
295    {
296        if ($name !== null) {
297            $this->setName($name);
298        }
299
300        $this->data     = $data;
301        $this->dataName = $dataName;
302    }
303
304    /**
305     * Returns a string representation of the test case.
306     *
307     * @return string
308     */
309    public function toString()
310    {
311        $class = new ReflectionClass($this);
312
313        $buffer = sprintf(
314            '%s::%s',
315            $class->name,
316            $this->getName(false)
317        );
318
319        return $buffer . $this->getDataSetAsString();
320    }
321
322    /**
323     * Counts the number of test cases executed by run(TestResult result).
324     *
325     * @return int
326     */
327    public function count()
328    {
329        return 1;
330    }
331
332    public function getGroups()
333    {
334        return $this->groups;
335    }
336
337    /**
338     * @param array $groups
339     */
340    public function setGroups(array $groups)
341    {
342        $this->groups = $groups;
343    }
344
345    /**
346     * Returns the annotations for this test.
347     *
348     * @return array
349     */
350    public function getAnnotations()
351    {
352        return PHPUnit_Util_Test::parseTestMethodAnnotations(
353            get_class($this),
354            $this->name
355        );
356    }
357
358    /**
359     * Gets the name of a TestCase.
360     *
361     * @param bool $withDataSet
362     *
363     * @return string
364     */
365    public function getName($withDataSet = true)
366    {
367        if ($withDataSet) {
368            return $this->name . $this->getDataSetAsString(false);
369        } else {
370            return $this->name;
371        }
372    }
373
374    /**
375     * Returns the size of the test.
376     *
377     * @return int
378     */
379    public function getSize()
380    {
381        return PHPUnit_Util_Test::getSize(
382            get_class($this),
383            $this->getName(false)
384        );
385    }
386
387    /**
388     * @return bool
389     */
390    public function hasSize()
391    {
392        return $this->getSize() !== PHPUnit_Util_Test::UNKNOWN;
393    }
394
395    /**
396     * @return bool
397     */
398    public function isSmall()
399    {
400        return $this->getSize() === PHPUnit_Util_Test::SMALL;
401    }
402
403    /**
404     * @return bool
405     */
406    public function isMedium()
407    {
408        return $this->getSize() === PHPUnit_Util_Test::MEDIUM;
409    }
410
411    /**
412     * @return bool
413     */
414    public function isLarge()
415    {
416        return $this->getSize() === PHPUnit_Util_Test::LARGE;
417    }
418
419    /**
420     * @return string
421     */
422    public function getActualOutput()
423    {
424        if (!$this->outputBufferingActive) {
425            return $this->output;
426        } else {
427            return ob_get_contents();
428        }
429    }
430
431    /**
432     * @return bool
433     */
434    public function hasOutput()
435    {
436        if (strlen($this->output) === 0) {
437            return false;
438        }
439
440        if ($this->hasExpectationOnOutput()) {
441            return false;
442        }
443
444        return true;
445    }
446
447    /**
448     * @return bool
449     */
450    public function doesNotPerformAssertions()
451    {
452        return $this->doesNotPerformAssertions;
453    }
454
455    /**
456     * @param string $expectedRegex
457     *
458     * @throws PHPUnit_Framework_Exception
459     */
460    public function expectOutputRegex($expectedRegex)
461    {
462        if ($this->outputExpectedString !== null) {
463            throw new PHPUnit_Framework_Exception;
464        }
465
466        if (is_string($expectedRegex) || is_null($expectedRegex)) {
467            $this->outputExpectedRegex = $expectedRegex;
468        }
469    }
470
471    /**
472     * @param string $expectedString
473     */
474    public function expectOutputString($expectedString)
475    {
476        if ($this->outputExpectedRegex !== null) {
477            throw new PHPUnit_Framework_Exception;
478        }
479
480        if (is_string($expectedString) || is_null($expectedString)) {
481            $this->outputExpectedString = $expectedString;
482        }
483    }
484
485    /**
486     * @return bool
487     *
488     * @deprecated Use hasExpectationOnOutput() instead
489     */
490    public function hasPerformedExpectationsOnOutput()
491    {
492        return $this->hasExpectationOnOutput();
493    }
494
495    /**
496     * @return bool
497     */
498    public function hasExpectationOnOutput()
499    {
500        return is_string($this->outputExpectedString) || is_string($this->outputExpectedRegex);
501    }
502
503    /**
504     * @return string
505     */
506    public function getExpectedException()
507    {
508        return $this->expectedException;
509    }
510
511    /**
512     * @param mixed      $exception
513     * @param string     $message   Null means we do not check message at all, string (even empty) means we do. Default: null.
514     * @param int|string $code      Null means we do not check code at all, non-null means we do.
515     *
516     * @throws PHPUnit_Framework_Exception
517     *
518     * @deprecated Method deprecated since Release 5.2.0; use expectException() instead
519     */
520    public function setExpectedException($exception, $message = '', $code = null)
521    {
522        if (null !== $message && !is_string($message)) {
523            throw PHPUnit_Util_InvalidArgumentHelper::factory(2, 'string');
524        }
525
526        if (func_num_args() < 2) {
527            $message = null;
528        }
529
530        $this->expectedException = $exception;
531
532        if ($message !== null) {
533            $this->expectExceptionMessage($message);
534        }
535
536        if ($code !== null) {
537            $this->expectExceptionCode($code);
538        }
539    }
540
541    /**
542     * @param mixed  $exception
543     * @param string $messageRegExp
544     * @param int    $code
545     *
546     * @throws PHPUnit_Framework_Exception
547     *
548     * @deprecated Method deprecated since Release 5.6.0; use expectExceptionMessageRegExp() instead
549     */
550    public function setExpectedExceptionRegExp($exception, $messageRegExp = '', $code = null)
551    {
552        if (!is_string($messageRegExp)) {
553            throw PHPUnit_Util_InvalidArgumentHelper::factory(2, 'string');
554        }
555
556        $this->expectedException              = $exception;
557        $this->expectedExceptionMessageRegExp = $messageRegExp;
558
559        if ($code !== null) {
560            $this->expectExceptionCode($code);
561        }
562    }
563
564    /**
565     * @param string $exception
566     */
567    public function expectException($exception)
568    {
569        if (!is_string($exception)) {
570            throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'string');
571        }
572
573        $this->expectedException = $exception;
574    }
575
576    /**
577     * @param int|string $code
578     *
579     * @throws PHPUnit_Framework_Exception
580     */
581    public function expectExceptionCode($code)
582    {
583        if (!$this->expectedException) {
584            $this->expectedException = \Exception::class;
585        }
586
587        if (!is_int($code) && !is_string($code)) {
588            throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'integer or string');
589        }
590
591        $this->expectedExceptionCode = $code;
592    }
593
594    /**
595     * @param string $message
596     *
597     * @throws PHPUnit_Framework_Exception
598     */
599    public function expectExceptionMessage($message)
600    {
601        if (!$this->expectedException) {
602            $this->expectedException = \Exception::class;
603        }
604
605        if (!is_string($message)) {
606            throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'string');
607        }
608
609        $this->expectedExceptionMessage = $message;
610    }
611
612    /**
613     * @param string $messageRegExp
614     *
615     * @throws PHPUnit_Framework_Exception
616     */
617    public function expectExceptionMessageRegExp($messageRegExp)
618    {
619        if (!is_string($messageRegExp)) {
620            throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'string');
621        }
622
623        $this->expectedExceptionMessageRegExp = $messageRegExp;
624    }
625
626    /**
627     * @param bool $flag
628     */
629    public function setRegisterMockObjectsFromTestArgumentsRecursively($flag)
630    {
631        if (!is_bool($flag)) {
632            throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'boolean');
633        }
634
635        $this->registerMockObjectsFromTestArgumentsRecursively = $flag;
636    }
637
638    protected function setExpectedExceptionFromAnnotation()
639    {
640        try {
641            $expectedException = PHPUnit_Util_Test::getExpectedException(
642                get_class($this),
643                $this->name
644            );
645
646            if ($expectedException !== false) {
647                $this->expectException($expectedException['class']);
648
649                if ($expectedException['code'] !== null) {
650                    $this->expectExceptionCode($expectedException['code']);
651                }
652
653                if ($expectedException['message'] !== '') {
654                    $this->expectExceptionMessage($expectedException['message']);
655                } elseif ($expectedException['message_regex'] !== '') {
656                    $this->expectExceptionMessageRegExp($expectedException['message_regex']);
657                }
658            }
659        } catch (ReflectionException $e) {
660        }
661    }
662
663    /**
664     * @param bool $useErrorHandler
665     */
666    public function setUseErrorHandler($useErrorHandler)
667    {
668        $this->useErrorHandler = $useErrorHandler;
669    }
670
671    protected function setUseErrorHandlerFromAnnotation()
672    {
673        try {
674            $useErrorHandler = PHPUnit_Util_Test::getErrorHandlerSettings(
675                get_class($this),
676                $this->name
677            );
678
679            if ($useErrorHandler !== null) {
680                $this->setUseErrorHandler($useErrorHandler);
681            }
682        } catch (ReflectionException $e) {
683        }
684    }
685
686    protected function checkRequirements()
687    {
688        if (!$this->name || !method_exists($this, $this->name)) {
689            return;
690        }
691
692        $missingRequirements = PHPUnit_Util_Test::getMissingRequirements(
693            get_class($this),
694            $this->name
695        );
696
697        if (!empty($missingRequirements)) {
698            $this->markTestSkipped(implode(PHP_EOL, $missingRequirements));
699        }
700    }
701
702    /**
703     * Returns the status of this test.
704     *
705     * @return int
706     */
707    public function getStatus()
708    {
709        return $this->status;
710    }
711
712    public function markAsRisky()
713    {
714        $this->status = PHPUnit_Runner_BaseTestRunner::STATUS_RISKY;
715    }
716
717    /**
718     * Returns the status message of this test.
719     *
720     * @return string
721     */
722    public function getStatusMessage()
723    {
724        return $this->statusMessage;
725    }
726
727    /**
728     * Returns whether or not this test has failed.
729     *
730     * @return bool
731     */
732    public function hasFailed()
733    {
734        $status = $this->getStatus();
735
736        return $status == PHPUnit_Runner_BaseTestRunner::STATUS_FAILURE ||
737               $status == PHPUnit_Runner_BaseTestRunner::STATUS_ERROR;
738    }
739
740    /**
741     * Runs the test case and collects the results in a TestResult object.
742     * If no TestResult object is passed a new one will be created.
743     *
744     * @param PHPUnit_Framework_TestResult $result
745     *
746     * @return PHPUnit_Framework_TestResult
747     *
748     * @throws PHPUnit_Framework_Exception
749     */
750    public function run(PHPUnit_Framework_TestResult $result = null)
751    {
752        if ($result === null) {
753            $result = $this->createResult();
754        }
755
756        if (!$this instanceof PHPUnit_Framework_WarningTestCase) {
757            $this->setTestResultObject($result);
758            $this->setUseErrorHandlerFromAnnotation();
759        }
760
761        if ($this->useErrorHandler !== null) {
762            $oldErrorHandlerSetting = $result->getConvertErrorsToExceptions();
763            $result->convertErrorsToExceptions($this->useErrorHandler);
764        }
765
766        if (!$this instanceof PHPUnit_Framework_WarningTestCase &&
767            !$this instanceof PHPUnit_Framework_SkippedTestCase &&
768            !$this->handleDependencies()) {
769            return;
770        }
771
772        if ($this->runTestInSeparateProcess === true &&
773            $this->inIsolation !== true &&
774            !$this instanceof PHPUnit_Extensions_PhptTestCase) {
775            $class = new ReflectionClass($this);
776
777            $template = new Text_Template(
778                __DIR__ . '/../Util/PHP/Template/TestCaseMethod.tpl'
779            );
780
781            if ($this->preserveGlobalState) {
782                $constants     = PHPUnit_Util_GlobalState::getConstantsAsString();
783                $globals       = PHPUnit_Util_GlobalState::getGlobalsAsString();
784                $includedFiles = PHPUnit_Util_GlobalState::getIncludedFilesAsString();
785                $iniSettings   = PHPUnit_Util_GlobalState::getIniSettingsAsString();
786            } else {
787                $constants     = '';
788                if (!empty($GLOBALS['__PHPUNIT_BOOTSTRAP'])) {
789                    $globals     = '$GLOBALS[\'__PHPUNIT_BOOTSTRAP\'] = ' . var_export($GLOBALS['__PHPUNIT_BOOTSTRAP'], true) . ";\n";
790                } else {
791                    $globals     = '';
792                }
793                $includedFiles = '';
794                $iniSettings   = '';
795            }
796
797            $coverage                                   = $result->getCollectCodeCoverageInformation()          ? 'true' : 'false';
798            $isStrictAboutTestsThatDoNotTestAnything    = $result->isStrictAboutTestsThatDoNotTestAnything()    ? 'true' : 'false';
799            $isStrictAboutOutputDuringTests             = $result->isStrictAboutOutputDuringTests()             ? 'true' : 'false';
800            $enforcesTimeLimit                          = $result->enforcesTimeLimit()                          ? 'true' : 'false';
801            $isStrictAboutTodoAnnotatedTests            = $result->isStrictAboutTodoAnnotatedTests()            ? 'true' : 'false';
802            $isStrictAboutResourceUsageDuringSmallTests = $result->isStrictAboutResourceUsageDuringSmallTests() ? 'true' : 'false';
803
804            if (defined('PHPUNIT_COMPOSER_INSTALL')) {
805                $composerAutoload = var_export(PHPUNIT_COMPOSER_INSTALL, true);
806            } else {
807                $composerAutoload = '\'\'';
808            }
809
810            if (defined('__PHPUNIT_PHAR__')) {
811                $phar = var_export(__PHPUNIT_PHAR__, true);
812            } else {
813                $phar = '\'\'';
814            }
815
816            if ($result->getCodeCoverage()) {
817                $codeCoverageFilter = $result->getCodeCoverage()->filter();
818            } else {
819                $codeCoverageFilter = null;
820            }
821
822            $data               = var_export(serialize($this->data), true);
823            $dataName           = var_export($this->dataName, true);
824            $dependencyInput    = var_export(serialize($this->dependencyInput), true);
825            $includePath        = var_export(get_include_path(), true);
826            $codeCoverageFilter = var_export(serialize($codeCoverageFilter), true);
827            // must do these fixes because TestCaseMethod.tpl has unserialize('{data}') in it, and we can't break BC
828            // the lines above used to use addcslashes() rather than var_export(), which breaks null byte escape sequences
829            $data               = "'." . $data . ".'";
830            $dataName           = "'.(" . $dataName . ").'";
831            $dependencyInput    = "'." . $dependencyInput . ".'";
832            $includePath        = "'." . $includePath . ".'";
833            $codeCoverageFilter = "'." . $codeCoverageFilter . ".'";
834
835            $configurationFilePath = (isset($GLOBALS['__PHPUNIT_CONFIGURATION_FILE']) ? $GLOBALS['__PHPUNIT_CONFIGURATION_FILE'] : '');
836
837            $template->setVar(
838                [
839                    'composerAutoload'                           => $composerAutoload,
840                    'phar'                                       => $phar,
841                    'filename'                                   => $class->getFileName(),
842                    'className'                                  => $class->getName(),
843                    'methodName'                                 => $this->name,
844                    'collectCodeCoverageInformation'             => $coverage,
845                    'data'                                       => $data,
846                    'dataName'                                   => $dataName,
847                    'dependencyInput'                            => $dependencyInput,
848                    'constants'                                  => $constants,
849                    'globals'                                    => $globals,
850                    'include_path'                               => $includePath,
851                    'included_files'                             => $includedFiles,
852                    'iniSettings'                                => $iniSettings,
853                    'isStrictAboutTestsThatDoNotTestAnything'    => $isStrictAboutTestsThatDoNotTestAnything,
854                    'isStrictAboutOutputDuringTests'             => $isStrictAboutOutputDuringTests,
855                    'enforcesTimeLimit'                          => $enforcesTimeLimit,
856                    'isStrictAboutTodoAnnotatedTests'            => $isStrictAboutTodoAnnotatedTests,
857                    'isStrictAboutResourceUsageDuringSmallTests' => $isStrictAboutResourceUsageDuringSmallTests,
858                    'codeCoverageFilter'                         => $codeCoverageFilter,
859                    'configurationFilePath'                      => $configurationFilePath
860                ]
861            );
862
863            $this->prepareTemplate($template);
864
865            $php = PHPUnit_Util_PHP::factory();
866            $php->runTestJob($template->render(), $this, $result);
867        } else {
868            $result->run($this);
869        }
870
871        if (isset($oldErrorHandlerSetting)) {
872            $result->convertErrorsToExceptions($oldErrorHandlerSetting);
873        }
874
875        $this->result = null;
876
877        return $result;
878    }
879
880    /**
881     * Runs the bare test sequence.
882     */
883    public function runBare()
884    {
885        $this->numAssertions = 0;
886
887        $this->snapshotGlobalState();
888        $this->startOutputBuffering();
889        clearstatcache();
890        $currentWorkingDirectory = getcwd();
891
892        $hookMethods = PHPUnit_Util_Test::getHookMethods(get_class($this));
893
894        try {
895            $hasMetRequirements = false;
896            $this->checkRequirements();
897            $hasMetRequirements = true;
898
899            if ($this->inIsolation) {
900                foreach ($hookMethods['beforeClass'] as $method) {
901                    $this->$method();
902                }
903            }
904
905            $this->setExpectedExceptionFromAnnotation();
906            $this->setDoesNotPerformAssertionsFromAnnotation();
907
908            foreach ($hookMethods['before'] as $method) {
909                $this->$method();
910            }
911
912            $this->assertPreConditions();
913            $this->testResult = $this->runTest();
914            $this->verifyMockObjects();
915            $this->assertPostConditions();
916
917            if (!empty($this->warnings)) {
918                throw new PHPUnit_Framework_Warning(
919                    implode(
920                        "\n",
921                        array_unique($this->warnings)
922                    )
923                );
924            }
925
926            $this->status = PHPUnit_Runner_BaseTestRunner::STATUS_PASSED;
927        } catch (PHPUnit_Framework_IncompleteTest $e) {
928            $this->status        = PHPUnit_Runner_BaseTestRunner::STATUS_INCOMPLETE;
929            $this->statusMessage = $e->getMessage();
930        } catch (PHPUnit_Framework_SkippedTest $e) {
931            $this->status        = PHPUnit_Runner_BaseTestRunner::STATUS_SKIPPED;
932            $this->statusMessage = $e->getMessage();
933        } catch (PHPUnit_Framework_Warning $e) {
934            $this->status        = PHPUnit_Runner_BaseTestRunner::STATUS_WARNING;
935            $this->statusMessage = $e->getMessage();
936        } catch (PHPUnit_Framework_AssertionFailedError $e) {
937            $this->status        = PHPUnit_Runner_BaseTestRunner::STATUS_FAILURE;
938            $this->statusMessage = $e->getMessage();
939        } catch (PredictionException $e) {
940            $this->status        = PHPUnit_Runner_BaseTestRunner::STATUS_FAILURE;
941            $this->statusMessage = $e->getMessage();
942        } catch (Throwable $_e) {
943            $e = $_e;
944        } catch (Exception $_e) {
945            $e = $_e;
946        }
947
948        // Clean up the mock objects.
949        $this->mockObjects = [];
950        $this->prophet     = null;
951
952        // Tear down the fixture. An exception raised in tearDown() will be
953        // caught and passed on when no exception was raised before.
954        try {
955            if ($hasMetRequirements) {
956                foreach ($hookMethods['after'] as $method) {
957                    $this->$method();
958                }
959
960                if ($this->inIsolation) {
961                    foreach ($hookMethods['afterClass'] as $method) {
962                        $this->$method();
963                    }
964                }
965            }
966        } catch (Throwable $_e) {
967            if (!isset($e)) {
968                $e = $_e;
969            }
970        } catch (Exception $_e) {
971            if (!isset($e)) {
972                $e = $_e;
973            }
974        }
975
976        try {
977            $this->stopOutputBuffering();
978        } catch (PHPUnit_Framework_RiskyTestError $_e) {
979            if (!isset($e)) {
980                $e = $_e;
981            }
982        }
983
984        if (isset($_e)) {
985            $this->status        = PHPUnit_Runner_BaseTestRunner::STATUS_ERROR;
986            $this->statusMessage = $_e->getMessage();
987        }
988
989        clearstatcache();
990
991        if ($currentWorkingDirectory != getcwd()) {
992            chdir($currentWorkingDirectory);
993        }
994
995        $this->restoreGlobalState();
996
997        // Clean up INI settings.
998        foreach ($this->iniSettings as $varName => $oldValue) {
999            ini_set($varName, $oldValue);
1000        }
1001
1002        $this->iniSettings = [];
1003
1004        // Clean up locale settings.
1005        foreach ($this->locale as $category => $locale) {
1006            setlocale($category, $locale);
1007        }
1008
1009        // Perform assertion on output.
1010        if (!isset($e)) {
1011            try {
1012                if ($this->outputExpectedRegex !== null) {
1013                    $this->assertRegExp($this->outputExpectedRegex, $this->output);
1014                } elseif ($this->outputExpectedString !== null) {
1015                    $this->assertEquals($this->outputExpectedString, $this->output);
1016                }
1017            } catch (Throwable $_e) {
1018                $e = $_e;
1019            } catch (Exception $_e) {
1020                $e = $_e;
1021            }
1022        }
1023
1024        // Workaround for missing "finally".
1025        if (isset($e)) {
1026            if ($e instanceof PredictionException) {
1027                $e = new PHPUnit_Framework_AssertionFailedError($e->getMessage());
1028            }
1029
1030            $this->onNotSuccessfulTest($e);
1031        }
1032    }
1033
1034    /**
1035     * Override to run the test and assert its state.
1036     *
1037     * @return mixed
1038     *
1039     * @throws Exception|PHPUnit_Framework_Exception
1040     * @throws PHPUnit_Framework_Exception
1041     */
1042    protected function runTest()
1043    {
1044        if ($this->name === null) {
1045            throw new PHPUnit_Framework_Exception(
1046                'PHPUnit_Framework_TestCase::$name must not be null.'
1047            );
1048        }
1049
1050        try {
1051            $class  = new ReflectionClass($this);
1052            $method = $class->getMethod($this->name);
1053        } catch (ReflectionException $e) {
1054            $this->fail($e->getMessage());
1055        }
1056
1057        $testArguments = array_merge($this->data, $this->dependencyInput);
1058
1059        $this->registerMockObjectsFromTestArguments($testArguments);
1060
1061        try {
1062            $testResult = $method->invokeArgs($this, $testArguments);
1063        } catch (Throwable $_e) {
1064            $e = $_e;
1065        } catch (Exception $_e) {
1066            $e = $_e;
1067        }
1068
1069        if (isset($e)) {
1070            $checkException = false;
1071
1072            if (!($e instanceof PHPUnit_Framework_SkippedTestError) && is_string($this->expectedException)) {
1073                $checkException = true;
1074
1075                if ($e instanceof PHPUnit_Framework_Exception) {
1076                    $checkException = false;
1077                }
1078
1079                $reflector = new ReflectionClass($this->expectedException);
1080
1081                if ($this->expectedException === 'PHPUnit_Framework_Exception' ||
1082                    $this->expectedException === '\PHPUnit_Framework_Exception' ||
1083                    $reflector->isSubclassOf('PHPUnit_Framework_Exception')) {
1084                    $checkException = true;
1085                }
1086            }
1087
1088            if ($checkException) {
1089                $this->assertThat(
1090                    $e,
1091                    new PHPUnit_Framework_Constraint_Exception(
1092                        $this->expectedException
1093                    )
1094                );
1095
1096                if ($this->expectedExceptionMessage !== null) {
1097                    $this->assertThat(
1098                        $e,
1099                        new PHPUnit_Framework_Constraint_ExceptionMessage(
1100                            $this->expectedExceptionMessage
1101                        )
1102                    );
1103                }
1104
1105                if ($this->expectedExceptionMessageRegExp !== null) {
1106                    $this->assertThat(
1107                        $e,
1108                        new PHPUnit_Framework_Constraint_ExceptionMessageRegExp(
1109                            $this->expectedExceptionMessageRegExp
1110                        )
1111                    );
1112                }
1113
1114                if ($this->expectedExceptionCode !== null) {
1115                    $this->assertThat(
1116                        $e,
1117                        new PHPUnit_Framework_Constraint_ExceptionCode(
1118                            $this->expectedExceptionCode
1119                        )
1120                    );
1121                }
1122
1123                return;
1124            } else {
1125                throw $e;
1126            }
1127        }
1128
1129        if ($this->expectedException !== null) {
1130            $this->assertThat(
1131                null,
1132                new PHPUnit_Framework_Constraint_Exception(
1133                    $this->expectedException
1134                )
1135            );
1136        }
1137
1138        return $testResult;
1139    }
1140
1141    /**
1142     * Verifies the mock object expectations.
1143     */
1144    protected function verifyMockObjects()
1145    {
1146        foreach ($this->mockObjects as $mockObject) {
1147            if ($mockObject->__phpunit_hasMatchers()) {
1148                $this->numAssertions++;
1149            }
1150
1151            $mockObject->__phpunit_verify(
1152                $this->shouldInvocationMockerBeReset($mockObject)
1153            );
1154        }
1155
1156        if ($this->prophet !== null) {
1157            try {
1158                $this->prophet->checkPredictions();
1159            } catch (Throwable $t) {
1160                /* Intentionally left empty */
1161            } catch (Exception $t) {
1162                /* Intentionally left empty */
1163            }
1164
1165            foreach ($this->prophet->getProphecies() as $objectProphecy) {
1166                foreach ($objectProphecy->getMethodProphecies() as $methodProphecies) {
1167                    foreach ($methodProphecies as $methodProphecy) {
1168                        $this->numAssertions += count($methodProphecy->getCheckedPredictions());
1169                    }
1170                }
1171            }
1172
1173            if (isset($t)) {
1174                throw $t;
1175            }
1176        }
1177    }
1178
1179    /**
1180     * Sets the name of a TestCase.
1181     *
1182     * @param  string
1183     */
1184    public function setName($name)
1185    {
1186        $this->name = $name;
1187    }
1188
1189    /**
1190     * Sets the dependencies of a TestCase.
1191     *
1192     * @param array $dependencies
1193     */
1194    public function setDependencies(array $dependencies)
1195    {
1196        $this->dependencies = $dependencies;
1197    }
1198
1199    /**
1200     * Returns true if the tests has dependencies
1201     *
1202     * @return bool
1203     */
1204    public function hasDependencies()
1205    {
1206        return count($this->dependencies) > 0;
1207    }
1208
1209    /**
1210     * Sets
1211     *
1212     * @param array $dependencyInput
1213     */
1214    public function setDependencyInput(array $dependencyInput)
1215    {
1216        $this->dependencyInput = $dependencyInput;
1217    }
1218
1219    /**
1220     * @param bool $beStrictAboutChangesToGlobalState
1221     */
1222    public function setBeStrictAboutChangesToGlobalState($beStrictAboutChangesToGlobalState)
1223    {
1224        $this->beStrictAboutChangesToGlobalState = $beStrictAboutChangesToGlobalState;
1225    }
1226
1227    /**
1228     * Calling this method in setUp() has no effect!
1229     *
1230     * @param bool $backupGlobals
1231     */
1232    public function setBackupGlobals($backupGlobals)
1233    {
1234        if (is_null($this->backupGlobals) && is_bool($backupGlobals)) {
1235            $this->backupGlobals = $backupGlobals;
1236        }
1237    }
1238
1239    /**
1240     * Calling this method in setUp() has no effect!
1241     *
1242     * @param bool $backupStaticAttributes
1243     */
1244    public function setBackupStaticAttributes($backupStaticAttributes)
1245    {
1246        if (is_null($this->backupStaticAttributes) &&
1247            is_bool($backupStaticAttributes)) {
1248            $this->backupStaticAttributes = $backupStaticAttributes;
1249        }
1250    }
1251
1252    /**
1253     * @param bool $runTestInSeparateProcess
1254     *
1255     * @throws PHPUnit_Framework_Exception
1256     */
1257    public function setRunTestInSeparateProcess($runTestInSeparateProcess)
1258    {
1259        if (is_bool($runTestInSeparateProcess)) {
1260            if ($this->runTestInSeparateProcess === null) {
1261                $this->runTestInSeparateProcess = $runTestInSeparateProcess;
1262            }
1263        } else {
1264            throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'boolean');
1265        }
1266    }
1267
1268    /**
1269     * @param bool $preserveGlobalState
1270     *
1271     * @throws PHPUnit_Framework_Exception
1272     */
1273    public function setPreserveGlobalState($preserveGlobalState)
1274    {
1275        if (is_bool($preserveGlobalState)) {
1276            $this->preserveGlobalState = $preserveGlobalState;
1277        } else {
1278            throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'boolean');
1279        }
1280    }
1281
1282    /**
1283     * @param bool $inIsolation
1284     *
1285     * @throws PHPUnit_Framework_Exception
1286     */
1287    public function setInIsolation($inIsolation)
1288    {
1289        if (is_bool($inIsolation)) {
1290            $this->inIsolation = $inIsolation;
1291        } else {
1292            throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'boolean');
1293        }
1294    }
1295
1296    /**
1297     * @return bool
1298     */
1299    public function isInIsolation()
1300    {
1301        return $this->inIsolation;
1302    }
1303
1304    /**
1305     * @return mixed
1306     */
1307    public function getResult()
1308    {
1309        return $this->testResult;
1310    }
1311
1312    /**
1313     * @param mixed $result
1314     */
1315    public function setResult($result)
1316    {
1317        $this->testResult = $result;
1318    }
1319
1320    /**
1321     * @param callable $callback
1322     *
1323     * @throws PHPUnit_Framework_Exception
1324     */
1325    public function setOutputCallback($callback)
1326    {
1327        if (!is_callable($callback)) {
1328            throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'callback');
1329        }
1330
1331        $this->outputCallback = $callback;
1332    }
1333
1334    /**
1335     * @return PHPUnit_Framework_TestResult
1336     */
1337    public function getTestResultObject()
1338    {
1339        return $this->result;
1340    }
1341
1342    /**
1343     * @param PHPUnit_Framework_TestResult $result
1344     */
1345    public function setTestResultObject(PHPUnit_Framework_TestResult $result)
1346    {
1347        $this->result = $result;
1348    }
1349
1350    /**
1351     * @param PHPUnit_Framework_MockObject_MockObject $mockObject
1352     */
1353    public function registerMockObject(PHPUnit_Framework_MockObject_MockObject $mockObject)
1354    {
1355        $this->mockObjects[] = $mockObject;
1356    }
1357
1358    /**
1359     * This method is a wrapper for the ini_set() function that automatically
1360     * resets the modified php.ini setting to its original value after the
1361     * test is run.
1362     *
1363     * @param string $varName
1364     * @param string $newValue
1365     *
1366     * @throws PHPUnit_Framework_Exception
1367     */
1368    protected function iniSet($varName, $newValue)
1369    {
1370        if (!is_string($varName)) {
1371            throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'string');
1372        }
1373
1374        $currentValue = ini_set($varName, $newValue);
1375
1376        if ($currentValue !== false) {
1377            $this->iniSettings[$varName] = $currentValue;
1378        } else {
1379            throw new PHPUnit_Framework_Exception(
1380                sprintf(
1381                    'INI setting "%s" could not be set to "%s".',
1382                    $varName,
1383                    $newValue
1384                )
1385            );
1386        }
1387    }
1388
1389    /**
1390     * This method is a wrapper for the setlocale() function that automatically
1391     * resets the locale to its original value after the test is run.
1392     *
1393     * @param int    $category
1394     * @param string $locale
1395     *
1396     * @throws PHPUnit_Framework_Exception
1397     */
1398    protected function setLocale()
1399    {
1400        $args = func_get_args();
1401
1402        if (count($args) < 2) {
1403            throw new PHPUnit_Framework_Exception;
1404        }
1405
1406        $category = $args[0];
1407        $locale   = $args[1];
1408
1409        $categories = [
1410            LC_ALL, LC_COLLATE, LC_CTYPE, LC_MONETARY, LC_NUMERIC, LC_TIME
1411        ];
1412
1413        if (defined('LC_MESSAGES')) {
1414            $categories[] = LC_MESSAGES;
1415        }
1416
1417        if (!in_array($category, $categories)) {
1418            throw new PHPUnit_Framework_Exception;
1419        }
1420
1421        if (!is_array($locale) && !is_string($locale)) {
1422            throw new PHPUnit_Framework_Exception;
1423        }
1424
1425        $this->locale[$category] = setlocale($category, 0);
1426
1427        $result = call_user_func_array('setlocale', $args);
1428
1429        if ($result === false) {
1430            throw new PHPUnit_Framework_Exception(
1431                'The locale functionality is not implemented on your platform, ' .
1432                'the specified locale does not exist or the category name is ' .
1433                'invalid.'
1434            );
1435        }
1436    }
1437
1438    /**
1439     * Returns a builder object to create mock objects using a fluent interface.
1440     *
1441     * @param string|string[] $className
1442     *
1443     * @return PHPUnit_Framework_MockObject_MockBuilder
1444     */
1445    public function getMockBuilder($className)
1446    {
1447        return new PHPUnit_Framework_MockObject_MockBuilder($this, $className);
1448    }
1449
1450    /**
1451     * Returns a test double for the specified class.
1452     *
1453     * @param string $originalClassName
1454     *
1455     * @return PHPUnit_Framework_MockObject_MockObject
1456     *
1457     * @throws PHPUnit_Framework_Exception
1458     */
1459    protected function createMock($originalClassName)
1460    {
1461        return $this->getMockBuilder($originalClassName)
1462                    ->disableOriginalConstructor()
1463                    ->disableOriginalClone()
1464                    ->disableArgumentCloning()
1465                    ->disallowMockingUnknownTypes()
1466                    ->getMock();
1467    }
1468
1469    /**
1470     * Returns a configured test double for the specified class.
1471     *
1472     * @param string $originalClassName
1473     * @param array  $configuration
1474     *
1475     * @return PHPUnit_Framework_MockObject_MockObject
1476     *
1477     * @throws PHPUnit_Framework_Exception
1478     */
1479    protected function createConfiguredMock($originalClassName, array $configuration)
1480    {
1481        $o = $this->createMock($originalClassName);
1482
1483        foreach ($configuration as $method => $return) {
1484            $o->method($method)->willReturn($return);
1485        }
1486
1487        return $o;
1488    }
1489
1490    /**
1491     * Returns a partial test double for the specified class.
1492     *
1493     * @param string $originalClassName
1494     * @param array  $methods
1495     *
1496     * @return PHPUnit_Framework_MockObject_MockObject
1497     *
1498     * @throws PHPUnit_Framework_Exception
1499     */
1500    protected function createPartialMock($originalClassName, array $methods)
1501    {
1502        return $this->getMockBuilder($originalClassName)
1503                    ->disableOriginalConstructor()
1504                    ->disableOriginalClone()
1505                    ->disableArgumentCloning()
1506                    ->disallowMockingUnknownTypes()
1507                    ->setMethods(empty($methods) ? null : $methods)
1508                    ->getMock();
1509    }
1510
1511    /**
1512     * Returns a mock object for the specified class.
1513     *
1514     * @param string     $originalClassName       Name of the class to mock.
1515     * @param array|null $methods                 When provided, only methods whose names are in the array
1516     *                                            are replaced with a configurable test double. The behavior
1517     *                                            of the other methods is not changed.
1518     *                                            Providing null means that no methods will be replaced.
1519     * @param array      $arguments               Parameters to pass to the original class' constructor.
1520     * @param string     $mockClassName           Class name for the generated test double class.
1521     * @param bool       $callOriginalConstructor Can be used to disable the call to the original class' constructor.
1522     * @param bool       $callOriginalClone       Can be used to disable the call to the original class' clone constructor.
1523     * @param bool       $callAutoload            Can be used to disable __autoload() during the generation of the test double class.
1524     * @param bool       $cloneArguments
1525     * @param bool       $callOriginalMethods
1526     * @param object     $proxyTarget
1527     *
1528     * @return PHPUnit_Framework_MockObject_MockObject
1529     *
1530     * @throws PHPUnit_Framework_Exception
1531     *
1532     * @deprecated Method deprecated since Release 5.4.0; use createMock() or getMockBuilder() instead
1533     */
1534    protected function getMock($originalClassName, $methods = [], array $arguments = [], $mockClassName = '', $callOriginalConstructor = true, $callOriginalClone = true, $callAutoload = true, $cloneArguments = false, $callOriginalMethods = false, $proxyTarget = null)
1535    {
1536        $this->warnings[] = 'PHPUnit_Framework_TestCase::getMock() is deprecated, use PHPUnit_Framework_TestCase::createMock() or PHPUnit_Framework_TestCase::getMockBuilder() instead';
1537
1538        $mockObject = $this->getMockObjectGenerator()->getMock(
1539            $originalClassName,
1540            $methods,
1541            $arguments,
1542            $mockClassName,
1543            $callOriginalConstructor,
1544            $callOriginalClone,
1545            $callAutoload,
1546            $cloneArguments,
1547            $callOriginalMethods,
1548            $proxyTarget
1549        );
1550
1551        $this->registerMockObject($mockObject);
1552
1553        return $mockObject;
1554    }
1555
1556    /**
1557     * Returns a mock with disabled constructor object for the specified class.
1558     *
1559     * @param string $originalClassName
1560     *
1561     * @return PHPUnit_Framework_MockObject_MockObject
1562     *
1563     * @throws PHPUnit_Framework_Exception
1564     *
1565     * @deprecated Method deprecated since Release 5.4.0; use createMock() instead
1566     */
1567    protected function getMockWithoutInvokingTheOriginalConstructor($originalClassName)
1568    {
1569        $this->warnings[] = 'PHPUnit_Framework_TestCase::getMockWithoutInvokingTheOriginalConstructor() is deprecated, use PHPUnit_Framework_TestCase::createMock() instead';
1570
1571        return $this->getMockBuilder($originalClassName)
1572                    ->disableOriginalConstructor()
1573                    ->getMock();
1574    }
1575
1576    /**
1577     * Mocks the specified class and returns the name of the mocked class.
1578     *
1579     * @param string $originalClassName
1580     * @param array  $methods
1581     * @param array  $arguments
1582     * @param string $mockClassName
1583     * @param bool   $callOriginalConstructor
1584     * @param bool   $callOriginalClone
1585     * @param bool   $callAutoload
1586     * @param bool   $cloneArguments
1587     *
1588     * @return string
1589     *
1590     * @throws PHPUnit_Framework_Exception
1591     */
1592    protected function getMockClass($originalClassName, $methods = [], array $arguments = [], $mockClassName = '', $callOriginalConstructor = false, $callOriginalClone = true, $callAutoload = true, $cloneArguments = false)
1593    {
1594        $mock = $this->getMockObjectGenerator()->getMock(
1595            $originalClassName,
1596            $methods,
1597            $arguments,
1598            $mockClassName,
1599            $callOriginalConstructor,
1600            $callOriginalClone,
1601            $callAutoload,
1602            $cloneArguments
1603        );
1604
1605        return get_class($mock);
1606    }
1607
1608    /**
1609     * Returns a mock object for the specified abstract class with all abstract
1610     * methods of the class mocked. Concrete methods are not mocked by default.
1611     * To mock concrete methods, use the 7th parameter ($mockedMethods).
1612     *
1613     * @param string $originalClassName
1614     * @param array  $arguments
1615     * @param string $mockClassName
1616     * @param bool   $callOriginalConstructor
1617     * @param bool   $callOriginalClone
1618     * @param bool   $callAutoload
1619     * @param array  $mockedMethods
1620     * @param bool   $cloneArguments
1621     *
1622     * @return PHPUnit_Framework_MockObject_MockObject
1623     *
1624     * @throws PHPUnit_Framework_Exception
1625     */
1626    protected function getMockForAbstractClass($originalClassName, array $arguments = [], $mockClassName = '', $callOriginalConstructor = true, $callOriginalClone = true, $callAutoload = true, $mockedMethods = [], $cloneArguments = false)
1627    {
1628        $mockObject = $this->getMockObjectGenerator()->getMockForAbstractClass(
1629            $originalClassName,
1630            $arguments,
1631            $mockClassName,
1632            $callOriginalConstructor,
1633            $callOriginalClone,
1634            $callAutoload,
1635            $mockedMethods,
1636            $cloneArguments
1637        );
1638
1639        $this->registerMockObject($mockObject);
1640
1641        return $mockObject;
1642    }
1643
1644    /**
1645     * Returns a mock object based on the given WSDL file.
1646     *
1647     * @param string $wsdlFile
1648     * @param string $originalClassName
1649     * @param string $mockClassName
1650     * @param array  $methods
1651     * @param bool   $callOriginalConstructor
1652     * @param array  $options                 An array of options passed to SOAPClient::_construct
1653     *
1654     * @return PHPUnit_Framework_MockObject_MockObject
1655     */
1656    protected function getMockFromWsdl($wsdlFile, $originalClassName = '', $mockClassName = '', array $methods = [], $callOriginalConstructor = true, array $options = [])
1657    {
1658        if ($originalClassName === '') {
1659            $originalClassName = pathinfo(basename(parse_url($wsdlFile)['path']), PATHINFO_FILENAME);
1660        }
1661
1662        if (!class_exists($originalClassName)) {
1663            eval(
1664                $this->getMockObjectGenerator()->generateClassFromWsdl(
1665                    $wsdlFile,
1666                    $originalClassName,
1667                    $methods,
1668                    $options
1669                )
1670            );
1671        }
1672
1673        $mockObject = $this->getMockObjectGenerator()->getMock(
1674            $originalClassName,
1675            $methods,
1676            ['', $options],
1677            $mockClassName,
1678            $callOriginalConstructor,
1679            false,
1680            false
1681        );
1682
1683        $this->registerMockObject($mockObject);
1684
1685        return $mockObject;
1686    }
1687
1688    /**
1689     * Returns a mock object for the specified trait with all abstract methods
1690     * of the trait mocked. Concrete methods to mock can be specified with the
1691     * `$mockedMethods` parameter.
1692     *
1693     * @param string $traitName
1694     * @param array  $arguments
1695     * @param string $mockClassName
1696     * @param bool   $callOriginalConstructor
1697     * @param bool   $callOriginalClone
1698     * @param bool   $callAutoload
1699     * @param array  $mockedMethods
1700     * @param bool   $cloneArguments
1701     *
1702     * @return PHPUnit_Framework_MockObject_MockObject
1703     *
1704     * @throws PHPUnit_Framework_Exception
1705     */
1706    protected function getMockForTrait($traitName, array $arguments = [], $mockClassName = '', $callOriginalConstructor = true, $callOriginalClone = true, $callAutoload = true, $mockedMethods = [], $cloneArguments = false)
1707    {
1708        $mockObject = $this->getMockObjectGenerator()->getMockForTrait(
1709            $traitName,
1710            $arguments,
1711            $mockClassName,
1712            $callOriginalConstructor,
1713            $callOriginalClone,
1714            $callAutoload,
1715            $mockedMethods,
1716            $cloneArguments
1717        );
1718
1719        $this->registerMockObject($mockObject);
1720
1721        return $mockObject;
1722    }
1723
1724    /**
1725     * Returns an object for the specified trait.
1726     *
1727     * @param string $traitName
1728     * @param array  $arguments
1729     * @param string $traitClassName
1730     * @param bool   $callOriginalConstructor
1731     * @param bool   $callOriginalClone
1732     * @param bool   $callAutoload
1733     * @param bool   $cloneArguments
1734     *
1735     * @return object
1736     *
1737     * @throws PHPUnit_Framework_Exception
1738     */
1739    protected function getObjectForTrait($traitName, array $arguments = [], $traitClassName = '', $callOriginalConstructor = true, $callOriginalClone = true, $callAutoload = true, $cloneArguments = false)
1740    {
1741        return $this->getMockObjectGenerator()->getObjectForTrait(
1742            $traitName,
1743            $arguments,
1744            $traitClassName,
1745            $callOriginalConstructor,
1746            $callOriginalClone,
1747            $callAutoload,
1748            $cloneArguments
1749        );
1750    }
1751
1752    /**
1753     * @param string|null $classOrInterface
1754     *
1755     * @return \Prophecy\Prophecy\ObjectProphecy
1756     *
1757     * @throws \LogicException
1758     */
1759    protected function prophesize($classOrInterface = null)
1760    {
1761        return $this->getProphet()->prophesize($classOrInterface);
1762    }
1763
1764    /**
1765     * Adds a value to the assertion counter.
1766     *
1767     * @param int $count
1768     */
1769    public function addToAssertionCount($count)
1770    {
1771        $this->numAssertions += $count;
1772    }
1773
1774    /**
1775     * Returns the number of assertions performed by this test.
1776     *
1777     * @return int
1778     */
1779    public function getNumAssertions()
1780    {
1781        return $this->numAssertions;
1782    }
1783
1784    /**
1785     * Returns a matcher that matches when the method is executed
1786     * zero or more times.
1787     *
1788     * @return PHPUnit_Framework_MockObject_Matcher_AnyInvokedCount
1789     */
1790    public static function any()
1791    {
1792        return new PHPUnit_Framework_MockObject_Matcher_AnyInvokedCount;
1793    }
1794
1795    /**
1796     * Returns a matcher that matches when the method is never executed.
1797     *
1798     * @return PHPUnit_Framework_MockObject_Matcher_InvokedCount
1799     */
1800    public static function never()
1801    {
1802        return new PHPUnit_Framework_MockObject_Matcher_InvokedCount(0);
1803    }
1804
1805    /**
1806     * Returns a matcher that matches when the method is executed
1807     * at least N times.
1808     *
1809     * @param int $requiredInvocations
1810     *
1811     * @return PHPUnit_Framework_MockObject_Matcher_InvokedAtLeastCount
1812     */
1813    public static function atLeast($requiredInvocations)
1814    {
1815        return new PHPUnit_Framework_MockObject_Matcher_InvokedAtLeastCount(
1816            $requiredInvocations
1817        );
1818    }
1819
1820    /**
1821     * Returns a matcher that matches when the method is executed at least once.
1822     *
1823     * @return PHPUnit_Framework_MockObject_Matcher_InvokedAtLeastOnce
1824     */
1825    public static function atLeastOnce()
1826    {
1827        return new PHPUnit_Framework_MockObject_Matcher_InvokedAtLeastOnce;
1828    }
1829
1830    /**
1831     * Returns a matcher that matches when the method is executed exactly once.
1832     *
1833     * @return PHPUnit_Framework_MockObject_Matcher_InvokedCount
1834     */
1835    public static function once()
1836    {
1837        return new PHPUnit_Framework_MockObject_Matcher_InvokedCount(1);
1838    }
1839
1840    /**
1841     * Returns a matcher that matches when the method is executed
1842     * exactly $count times.
1843     *
1844     * @param int $count
1845     *
1846     * @return PHPUnit_Framework_MockObject_Matcher_InvokedCount
1847     */
1848    public static function exactly($count)
1849    {
1850        return new PHPUnit_Framework_MockObject_Matcher_InvokedCount($count);
1851    }
1852
1853    /**
1854     * Returns a matcher that matches when the method is executed
1855     * at most N times.
1856     *
1857     * @param int $allowedInvocations
1858     *
1859     * @return PHPUnit_Framework_MockObject_Matcher_InvokedAtMostCount
1860     */
1861    public static function atMost($allowedInvocations)
1862    {
1863        return new PHPUnit_Framework_MockObject_Matcher_InvokedAtMostCount(
1864            $allowedInvocations
1865        );
1866    }
1867
1868    /**
1869     * Returns a matcher that matches when the method is executed
1870     * at the given index.
1871     *
1872     * @param int $index
1873     *
1874     * @return PHPUnit_Framework_MockObject_Matcher_InvokedAtIndex
1875     */
1876    public static function at($index)
1877    {
1878        return new PHPUnit_Framework_MockObject_Matcher_InvokedAtIndex($index);
1879    }
1880
1881    /**
1882     * @param mixed $value
1883     *
1884     * @return PHPUnit_Framework_MockObject_Stub_Return
1885     */
1886    public static function returnValue($value)
1887    {
1888        return new PHPUnit_Framework_MockObject_Stub_Return($value);
1889    }
1890
1891    /**
1892     * @param array $valueMap
1893     *
1894     * @return PHPUnit_Framework_MockObject_Stub_ReturnValueMap
1895     */
1896    public static function returnValueMap(array $valueMap)
1897    {
1898        return new PHPUnit_Framework_MockObject_Stub_ReturnValueMap($valueMap);
1899    }
1900
1901    /**
1902     * @param int $argumentIndex
1903     *
1904     * @return PHPUnit_Framework_MockObject_Stub_ReturnArgument
1905     */
1906    public static function returnArgument($argumentIndex)
1907    {
1908        return new PHPUnit_Framework_MockObject_Stub_ReturnArgument(
1909            $argumentIndex
1910        );
1911    }
1912
1913    /**
1914     * @param mixed $callback
1915     *
1916     * @return PHPUnit_Framework_MockObject_Stub_ReturnCallback
1917     */
1918    public static function returnCallback($callback)
1919    {
1920        return new PHPUnit_Framework_MockObject_Stub_ReturnCallback($callback);
1921    }
1922
1923    /**
1924     * Returns the current object.
1925     *
1926     * This method is useful when mocking a fluent interface.
1927     *
1928     * @return PHPUnit_Framework_MockObject_Stub_ReturnSelf
1929     */
1930    public static function returnSelf()
1931    {
1932        return new PHPUnit_Framework_MockObject_Stub_ReturnSelf();
1933    }
1934
1935    /**
1936     * @param Throwable|Exception $exception
1937     *
1938     * @return PHPUnit_Framework_MockObject_Stub_Exception
1939     *
1940     * @todo   Add type declaration when support for PHP 5 is dropped
1941     */
1942    public static function throwException($exception)
1943    {
1944        return new PHPUnit_Framework_MockObject_Stub_Exception($exception);
1945    }
1946
1947    /**
1948     * @param mixed $value, ...
1949     *
1950     * @return PHPUnit_Framework_MockObject_Stub_ConsecutiveCalls
1951     */
1952    public static function onConsecutiveCalls()
1953    {
1954        $args = func_get_args();
1955
1956        return new PHPUnit_Framework_MockObject_Stub_ConsecutiveCalls($args);
1957    }
1958
1959    /**
1960     * @return bool
1961     */
1962    public function usesDataProvider()
1963    {
1964        return !empty($this->data);
1965    }
1966
1967    /**
1968     * @return string
1969     */
1970    public function dataDescription()
1971    {
1972        return is_string($this->dataName) ? $this->dataName : '';
1973    }
1974
1975    /**
1976     * Gets the data set description of a TestCase.
1977     *
1978     * @param bool $includeData
1979     *
1980     * @return string
1981     */
1982    protected function getDataSetAsString($includeData = true)
1983    {
1984        $buffer = '';
1985
1986        if (!empty($this->data)) {
1987            if (is_int($this->dataName)) {
1988                $buffer .= sprintf(' with data set #%d', $this->dataName);
1989            } else {
1990                $buffer .= sprintf(' with data set "%s"', $this->dataName);
1991            }
1992
1993            $exporter = new Exporter;
1994
1995            if ($includeData) {
1996                $buffer .= sprintf(' (%s)', $exporter->shortenedRecursiveExport($this->data));
1997            }
1998        }
1999
2000        return $buffer;
2001    }
2002
2003    /**
2004     * Gets the data set of a TestCase.
2005     *
2006     * @return array
2007     */
2008    protected function getProvidedData()
2009    {
2010        return $this->data;
2011    }
2012
2013    /**
2014     * Creates a default TestResult object.
2015     *
2016     * @return PHPUnit_Framework_TestResult
2017     */
2018    protected function createResult()
2019    {
2020        return new PHPUnit_Framework_TestResult;
2021    }
2022
2023    protected function handleDependencies()
2024    {
2025        if (!empty($this->dependencies) && !$this->inIsolation) {
2026            $className  = get_class($this);
2027            $passed     = $this->result->passed();
2028            $passedKeys = array_keys($passed);
2029            $numKeys    = count($passedKeys);
2030
2031            for ($i = 0; $i < $numKeys; $i++) {
2032                $pos = strpos($passedKeys[$i], ' with data set');
2033
2034                if ($pos !== false) {
2035                    $passedKeys[$i] = substr($passedKeys[$i], 0, $pos);
2036                }
2037            }
2038
2039            $passedKeys = array_flip(array_unique($passedKeys));
2040
2041            foreach ($this->dependencies as $dependency) {
2042                $clone = false;
2043
2044                if (strpos($dependency, 'clone ') === 0) {
2045                    $clone      = true;
2046                    $dependency = substr($dependency, strlen('clone '));
2047                } elseif (strpos($dependency, '!clone ') === 0) {
2048                    $clone      = false;
2049                    $dependency = substr($dependency, strlen('!clone '));
2050                }
2051
2052                if (strpos($dependency, '::') === false) {
2053                    $dependency = $className . '::' . $dependency;
2054                }
2055
2056                if (!isset($passedKeys[$dependency])) {
2057                    $this->result->startTest($this);
2058                    $this->result->addError(
2059                        $this,
2060                        new PHPUnit_Framework_SkippedTestError(
2061                            sprintf(
2062                                'This test depends on "%s" to pass.',
2063                                $dependency
2064                            )
2065                        ),
2066                        0
2067                    );
2068                    $this->result->endTest($this, 0);
2069
2070                    return false;
2071                }
2072
2073                if (isset($passed[$dependency])) {
2074                    if ($passed[$dependency]['size'] != PHPUnit_Util_Test::UNKNOWN &&
2075                        $this->getSize() != PHPUnit_Util_Test::UNKNOWN &&
2076                        $passed[$dependency]['size'] > $this->getSize()) {
2077                        $this->result->addError(
2078                            $this,
2079                            new PHPUnit_Framework_SkippedTestError(
2080                                'This test depends on a test that is larger than itself.'
2081                            ),
2082                            0
2083                        );
2084
2085                        return false;
2086                    }
2087
2088                    if ($clone) {
2089                        $deepCopy   = new DeepCopy;
2090                        $deepCopy->skipUncloneable(false);
2091
2092                        $this->dependencyInput[$dependency] = $deepCopy->copy($passed[$dependency]['result']);
2093                    } else {
2094                        $this->dependencyInput[$dependency] = $passed[$dependency]['result'];
2095                    }
2096                } else {
2097                    $this->dependencyInput[$dependency] = null;
2098                }
2099            }
2100        }
2101
2102        return true;
2103    }
2104
2105    /**
2106     * This method is called before the first test of this test class is run.
2107     */
2108    public static function setUpBeforeClass()
2109    {
2110    }
2111
2112    /**
2113     * Sets up the fixture, for example, open a network connection.
2114     * This method is called before a test is executed.
2115     */
2116    protected function setUp()
2117    {
2118    }
2119
2120    /**
2121     * Performs assertions shared by all tests of a test case.
2122     *
2123     * This method is called before the execution of a test starts
2124     * and after setUp() is called.
2125     */
2126    protected function assertPreConditions()
2127    {
2128    }
2129
2130    /**
2131     * Performs assertions shared by all tests of a test case.
2132     *
2133     * This method is called after the execution of a test ends
2134     * and before tearDown() is called.
2135     */
2136    protected function assertPostConditions()
2137    {
2138    }
2139
2140    /**
2141     * Tears down the fixture, for example, close a network connection.
2142     * This method is called after a test is executed.
2143     */
2144    protected function tearDown()
2145    {
2146    }
2147
2148    /**
2149     * This method is called after the last test of this test class is run.
2150     */
2151    public static function tearDownAfterClass()
2152    {
2153    }
2154
2155    /**
2156     * This method is called when a test method did not execute successfully.
2157     *
2158     * @param Exception|Throwable $e
2159     *
2160     * @throws Exception|Throwable
2161     */
2162    protected function onNotSuccessfulTest($e)
2163    {
2164        $expected = PHP_MAJOR_VERSION >= 7 ? 'Throwable' : 'Exception';
2165
2166        if ($e instanceof $expected) {
2167            throw $e;
2168        }
2169
2170        throw PHPUnit_Util_InvalidArgumentHelper::factory(
2171            1,
2172            'Throwable or Exception'
2173        );
2174    }
2175
2176    /**
2177     * Performs custom preparations on the process isolation template.
2178     *
2179     * @param Text_Template $template
2180     */
2181    protected function prepareTemplate(Text_Template $template)
2182    {
2183    }
2184
2185    /**
2186     * Get the mock object generator, creating it if it doesn't exist.
2187     *
2188     * @return PHPUnit_Framework_MockObject_Generator
2189     */
2190    protected function getMockObjectGenerator()
2191    {
2192        if (null === $this->mockObjectGenerator) {
2193            $this->mockObjectGenerator = new PHPUnit_Framework_MockObject_Generator;
2194        }
2195
2196        return $this->mockObjectGenerator;
2197    }
2198
2199    private function startOutputBuffering()
2200    {
2201        ob_start();
2202
2203        $this->outputBufferingActive = true;
2204        $this->outputBufferingLevel  = ob_get_level();
2205    }
2206
2207    private function stopOutputBuffering()
2208    {
2209        if (ob_get_level() != $this->outputBufferingLevel) {
2210            while (ob_get_level() >= $this->outputBufferingLevel) {
2211                ob_end_clean();
2212            }
2213
2214            throw new PHPUnit_Framework_RiskyTestError(
2215                'Test code or tested code did not (only) close its own output buffers'
2216            );
2217        }
2218
2219        $output = ob_get_contents();
2220
2221        if ($this->outputCallback === false) {
2222            $this->output = $output;
2223        } else {
2224            $this->output = call_user_func_array(
2225                $this->outputCallback,
2226                [$output]
2227            );
2228        }
2229
2230        ob_end_clean();
2231
2232        $this->outputBufferingActive = false;
2233        $this->outputBufferingLevel  = ob_get_level();
2234    }
2235
2236    private function snapshotGlobalState()
2237    {
2238        $backupGlobals = $this->backupGlobals === null || $this->backupGlobals === true;
2239
2240        if ($this->runTestInSeparateProcess ||
2241            $this->inIsolation ||
2242            (!$backupGlobals && !$this->backupStaticAttributes)) {
2243            return;
2244        }
2245
2246        $this->snapshot = $this->createGlobalStateSnapshot($backupGlobals);
2247    }
2248
2249    private function restoreGlobalState()
2250    {
2251        if (!$this->snapshot instanceof Snapshot) {
2252            return;
2253        }
2254
2255        $backupGlobals = $this->backupGlobals === null || $this->backupGlobals === true;
2256
2257        if ($this->beStrictAboutChangesToGlobalState) {
2258            try {
2259                $this->compareGlobalStateSnapshots(
2260                    $this->snapshot,
2261                    $this->createGlobalStateSnapshot($backupGlobals)
2262                );
2263            } catch (PHPUnit_Framework_RiskyTestError $rte) {
2264                // Intentionally left empty
2265            }
2266        }
2267
2268        $restorer = new Restorer;
2269
2270        if ($backupGlobals) {
2271            $restorer->restoreGlobalVariables($this->snapshot);
2272        }
2273
2274        if ($this->backupStaticAttributes) {
2275            $restorer->restoreStaticAttributes($this->snapshot);
2276        }
2277
2278        $this->snapshot = null;
2279
2280        if (isset($rte)) {
2281            throw $rte;
2282        }
2283    }
2284
2285    /**
2286     * @param bool $backupGlobals
2287     *
2288     * @return Snapshot
2289     */
2290    private function createGlobalStateSnapshot($backupGlobals)
2291    {
2292        $blacklist = new Blacklist;
2293
2294        foreach ($this->backupGlobalsBlacklist as $globalVariable) {
2295            $blacklist->addGlobalVariable($globalVariable);
2296        }
2297
2298        if (!defined('PHPUNIT_TESTSUITE')) {
2299            $blacklist->addClassNamePrefix('PHPUnit');
2300            $blacklist->addClassNamePrefix('File_Iterator');
2301            $blacklist->addClassNamePrefix('SebastianBergmann\CodeCoverage');
2302            $blacklist->addClassNamePrefix('PHP_Invoker');
2303            $blacklist->addClassNamePrefix('PHP_Timer');
2304            $blacklist->addClassNamePrefix('PHP_Token');
2305            $blacklist->addClassNamePrefix('Symfony');
2306            $blacklist->addClassNamePrefix('Text_Template');
2307            $blacklist->addClassNamePrefix('Doctrine\Instantiator');
2308            $blacklist->addClassNamePrefix('Prophecy');
2309
2310            foreach ($this->backupStaticAttributesBlacklist as $class => $attributes) {
2311                foreach ($attributes as $attribute) {
2312                    $blacklist->addStaticAttribute($class, $attribute);
2313                }
2314            }
2315        }
2316
2317        return new Snapshot(
2318            $blacklist,
2319            $backupGlobals,
2320            (bool) $this->backupStaticAttributes,
2321            false,
2322            false,
2323            false,
2324            false,
2325            false,
2326            false,
2327            false
2328        );
2329    }
2330
2331    /**
2332     * @param Snapshot $before
2333     * @param Snapshot $after
2334     *
2335     * @throws PHPUnit_Framework_RiskyTestError
2336     */
2337    private function compareGlobalStateSnapshots(Snapshot $before, Snapshot $after)
2338    {
2339        $backupGlobals = $this->backupGlobals === null || $this->backupGlobals === true;
2340
2341        if ($backupGlobals) {
2342            $this->compareGlobalStateSnapshotPart(
2343                $before->globalVariables(),
2344                $after->globalVariables(),
2345                "--- Global variables before the test\n+++ Global variables after the test\n"
2346            );
2347
2348            $this->compareGlobalStateSnapshotPart(
2349                $before->superGlobalVariables(),
2350                $after->superGlobalVariables(),
2351                "--- Super-global variables before the test\n+++ Super-global variables after the test\n"
2352            );
2353        }
2354
2355        if ($this->backupStaticAttributes) {
2356            $this->compareGlobalStateSnapshotPart(
2357                $before->staticAttributes(),
2358                $after->staticAttributes(),
2359                "--- Static attributes before the test\n+++ Static attributes after the test\n"
2360            );
2361        }
2362    }
2363
2364    /**
2365     * @param array  $before
2366     * @param array  $after
2367     * @param string $header
2368     *
2369     * @throws PHPUnit_Framework_RiskyTestError
2370     */
2371    private function compareGlobalStateSnapshotPart(array $before, array $after, $header)
2372    {
2373        if ($before != $after) {
2374            $differ   = new Differ($header);
2375            $exporter = new Exporter;
2376
2377            $diff = $differ->diff(
2378                $exporter->export($before),
2379                $exporter->export($after)
2380            );
2381
2382            throw new PHPUnit_Framework_RiskyTestError(
2383                $diff
2384            );
2385        }
2386    }
2387
2388    /**
2389     * @return Prophecy\Prophet
2390     */
2391    private function getProphet()
2392    {
2393        if ($this->prophet === null) {
2394            $this->prophet = new Prophet;
2395        }
2396
2397        return $this->prophet;
2398    }
2399
2400    /**
2401     * @param PHPUnit_Framework_MockObject_MockObject $mock
2402     *
2403     * @return bool
2404     */
2405    private function shouldInvocationMockerBeReset(PHPUnit_Framework_MockObject_MockObject $mock)
2406    {
2407        $enumerator = new Enumerator;
2408
2409        foreach ($enumerator->enumerate($this->dependencyInput) as $object) {
2410            if ($mock === $object) {
2411                return false;
2412            }
2413        }
2414
2415        if (!is_array($this->testResult) && !is_object($this->testResult)) {
2416            return true;
2417        }
2418
2419        foreach ($enumerator->enumerate($this->testResult) as $object) {
2420            if ($mock === $object) {
2421                return false;
2422            }
2423        }
2424
2425        return true;
2426    }
2427
2428    /**
2429     * @param array $testArguments
2430     * @param array $originalTestArguments
2431     */
2432    private function registerMockObjectsFromTestArguments(array $testArguments, array &$visited = [])
2433    {
2434        if ($this->registerMockObjectsFromTestArgumentsRecursively) {
2435            $enumerator = new Enumerator;
2436
2437            foreach ($enumerator->enumerate($testArguments) as $object) {
2438                if ($object instanceof PHPUnit_Framework_MockObject_MockObject) {
2439                    $this->registerMockObject($object);
2440                }
2441            }
2442        } else {
2443            foreach ($testArguments as $testArgument) {
2444                if ($testArgument instanceof PHPUnit_Framework_MockObject_MockObject) {
2445                    if ($this->isCloneable($testArgument)) {
2446                        $testArgument = clone $testArgument;
2447                    }
2448
2449                    $this->registerMockObject($testArgument);
2450                } elseif (is_array($testArgument) && !in_array($testArgument, $visited, true)) {
2451                    $visited[] = $testArgument;
2452
2453                    $this->registerMockObjectsFromTestArguments(
2454                        $testArgument,
2455                        $visited
2456                    );
2457                }
2458            }
2459        }
2460    }
2461
2462    private function setDoesNotPerformAssertionsFromAnnotation()
2463    {
2464        $annotations = $this->getAnnotations();
2465
2466        if (isset($annotations['method']['doesNotPerformAssertions'])) {
2467            $this->doesNotPerformAssertions = true;
2468        }
2469    }
2470
2471    /**
2472     * @param PHPUnit_Framework_MockObject_MockObject $testArgument
2473     *
2474     * @return bool
2475     */
2476    private function isCloneable(PHPUnit_Framework_MockObject_MockObject $testArgument)
2477    {
2478        $reflector = new ReflectionObject($testArgument);
2479
2480        if (!$reflector->isCloneable()) {
2481            return false;
2482        }
2483
2484        if ($reflector->hasMethod('__clone') &&
2485            $reflector->getMethod('__clone')->isPublic()) {
2486            return true;
2487        }
2488
2489        return false;
2490    }
2491}
2492