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
11/**
12 * A TestSuite is a composite of Tests. It runs a collection of test cases.
13 */
14class PHPUnit_Framework_TestSuite implements PHPUnit_Framework_Test, PHPUnit_Framework_SelfDescribing, IteratorAggregate
15{
16    /**
17     * Last count of tests in this suite.
18     *
19     * @var int|null
20     */
21    private $cachedNumTests;
22
23    /**
24     * Enable or disable the backup and restoration of the $GLOBALS array.
25     *
26     * @var bool
27     */
28    protected $backupGlobals = null;
29
30    /**
31     * Enable or disable the backup and restoration of static attributes.
32     *
33     * @var bool
34     */
35    protected $backupStaticAttributes = null;
36
37    /**
38     * @var bool
39     */
40    private $beStrictAboutChangesToGlobalState = null;
41
42    /**
43     * @var bool
44     */
45    protected $runTestInSeparateProcess = false;
46
47    /**
48     * The name of the test suite.
49     *
50     * @var string
51     */
52    protected $name = '';
53
54    /**
55     * The test groups of the test suite.
56     *
57     * @var array
58     */
59    protected $groups = [];
60
61    /**
62     * The tests in the test suite.
63     *
64     * @var array
65     */
66    protected $tests = [];
67
68    /**
69     * The number of tests in the test suite.
70     *
71     * @var int
72     */
73    protected $numTests = -1;
74
75    /**
76     * @var bool
77     */
78    protected $testCase = false;
79
80    /**
81     * @var array
82     */
83    protected $foundClasses = [];
84
85    /**
86     * @var PHPUnit_Runner_Filter_Factory
87     */
88    private $iteratorFilter = null;
89
90    /**
91     * @var string[]
92     */
93    private $declaredClasses;
94
95    /**
96     * Constructs a new TestSuite:
97     *
98     *   - PHPUnit_Framework_TestSuite() constructs an empty TestSuite.
99     *
100     *   - PHPUnit_Framework_TestSuite(ReflectionClass) constructs a
101     *     TestSuite from the given class.
102     *
103     *   - PHPUnit_Framework_TestSuite(ReflectionClass, String)
104     *     constructs a TestSuite from the given class with the given
105     *     name.
106     *
107     *   - PHPUnit_Framework_TestSuite(String) either constructs a
108     *     TestSuite from the given class (if the passed string is the
109     *     name of an existing class) or constructs an empty TestSuite
110     *     with the given name.
111     *
112     * @param mixed  $theClass
113     * @param string $name
114     *
115     * @throws PHPUnit_Framework_Exception
116     */
117    public function __construct($theClass = '', $name = '')
118    {
119        $this->declaredClasses = get_declared_classes();
120
121        $argumentsValid = false;
122
123        if (is_object($theClass) &&
124            $theClass instanceof ReflectionClass) {
125            $argumentsValid = true;
126        } elseif (is_string($theClass) &&
127                 $theClass !== '' &&
128                 class_exists($theClass, false)) {
129            $argumentsValid = true;
130
131            if ($name == '') {
132                $name = $theClass;
133            }
134
135            $theClass = new ReflectionClass($theClass);
136        } elseif (is_string($theClass)) {
137            $this->setName($theClass);
138
139            return;
140        }
141
142        if (!$argumentsValid) {
143            throw new PHPUnit_Framework_Exception;
144        }
145
146        if (!$theClass->isSubclassOf('PHPUnit_Framework_TestCase')) {
147            throw new PHPUnit_Framework_Exception(
148                'Class "' . $theClass->name . '" does not extend PHPUnit_Framework_TestCase.'
149            );
150        }
151
152        if ($name != '') {
153            $this->setName($name);
154        } else {
155            $this->setName($theClass->getName());
156        }
157
158        $constructor = $theClass->getConstructor();
159
160        if ($constructor !== null &&
161            !$constructor->isPublic()) {
162            $this->addTest(
163                self::warning(
164                    sprintf(
165                        'Class "%s" has no public constructor.',
166                        $theClass->getName()
167                    )
168                )
169            );
170
171            return;
172        }
173
174        foreach ($theClass->getMethods() as $method) {
175            $this->addTestMethod($theClass, $method);
176        }
177
178        if (empty($this->tests)) {
179            $this->addTest(
180                self::warning(
181                    sprintf(
182                        'No tests found in class "%s".',
183                        $theClass->getName()
184                    )
185                )
186            );
187        }
188
189        $this->testCase = true;
190    }
191
192    /**
193     * Returns a string representation of the test suite.
194     *
195     * @return string
196     */
197    public function toString()
198    {
199        return $this->getName();
200    }
201
202    /**
203     * Adds a test to the suite.
204     *
205     * @param PHPUnit_Framework_Test $test
206     * @param array                  $groups
207     */
208    public function addTest(PHPUnit_Framework_Test $test, $groups = [])
209    {
210        $class = new ReflectionClass($test);
211
212        if (!$class->isAbstract()) {
213            $this->tests[]  = $test;
214            $this->numTests = -1;
215
216            if ($test instanceof self &&
217                empty($groups)) {
218                $groups = $test->getGroups();
219            }
220
221            if (empty($groups)) {
222                $groups = ['default'];
223            }
224
225            foreach ($groups as $group) {
226                if (!isset($this->groups[$group])) {
227                    $this->groups[$group] = [$test];
228                } else {
229                    $this->groups[$group][] = $test;
230                }
231            }
232
233            if ($test instanceof PHPUnit_Framework_TestCase) {
234                $test->setGroups($groups);
235            }
236        }
237    }
238
239    /**
240     * Adds the tests from the given class to the suite.
241     *
242     * @param mixed $testClass
243     *
244     * @throws PHPUnit_Framework_Exception
245     */
246    public function addTestSuite($testClass)
247    {
248        if (is_string($testClass) && class_exists($testClass)) {
249            $testClass = new ReflectionClass($testClass);
250        }
251
252        if (!is_object($testClass)) {
253            throw PHPUnit_Util_InvalidArgumentHelper::factory(
254                1,
255                'class name or object'
256            );
257        }
258
259        if ($testClass instanceof self) {
260            $this->addTest($testClass);
261        } elseif ($testClass instanceof ReflectionClass) {
262            $suiteMethod = false;
263
264            if (!$testClass->isAbstract()) {
265                if ($testClass->hasMethod(PHPUnit_Runner_BaseTestRunner::SUITE_METHODNAME)) {
266                    $method = $testClass->getMethod(
267                        PHPUnit_Runner_BaseTestRunner::SUITE_METHODNAME
268                    );
269
270                    if ($method->isStatic()) {
271                        $this->addTest(
272                            $method->invoke(null, $testClass->getName())
273                        );
274
275                        $suiteMethod = true;
276                    }
277                }
278            }
279
280            if (!$suiteMethod && !$testClass->isAbstract() && $testClass->isSubclassOf(PHPUnit_Framework_TestCase::class)) {
281                $this->addTest(new self($testClass));
282            }
283        } else {
284            throw new PHPUnit_Framework_Exception;
285        }
286    }
287
288    /**
289     * Wraps both <code>addTest()</code> and <code>addTestSuite</code>
290     * as well as the separate import statements for the user's convenience.
291     *
292     * If the named file cannot be read or there are no new tests that can be
293     * added, a <code>PHPUnit_Framework_WarningTestCase</code> will be created instead,
294     * leaving the current test run untouched.
295     *
296     * @param string $filename
297     *
298     * @throws PHPUnit_Framework_Exception
299     */
300    public function addTestFile($filename)
301    {
302        if (!is_string($filename)) {
303            throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'string');
304        }
305
306        if (file_exists($filename) && substr($filename, -5) == '.phpt') {
307            $this->addTest(
308                new PHPUnit_Extensions_PhptTestCase($filename)
309            );
310
311            return;
312        }
313
314        // The given file may contain further stub classes in addition to the
315        // test class itself. Figure out the actual test class.
316        $filename   = PHPUnit_Util_Fileloader::checkAndLoad($filename);
317        $newClasses = array_diff(get_declared_classes(), $this->declaredClasses);
318
319        // The diff is empty in case a parent class (with test methods) is added
320        // AFTER a child class that inherited from it. To account for that case,
321        // cumulate all discovered classes, so the parent class may be found in
322        // a later invocation.
323        if (!empty($newClasses)) {
324            // On the assumption that test classes are defined first in files,
325            // process discovered classes in approximate LIFO order, so as to
326            // avoid unnecessary reflection.
327            $this->foundClasses = array_merge($newClasses, $this->foundClasses);
328            $this->declaredClasses = get_declared_classes();
329        }
330
331        // The test class's name must match the filename, either in full, or as
332        // a PEAR/PSR-0 prefixed shortname ('NameSpace_ShortName'), or as a
333        // PSR-1 local shortname ('NameSpace\ShortName'). The comparison must be
334        // anchored to prevent false-positive matches (e.g., 'OtherShortName').
335        $shortname      = basename($filename, '.php');
336        $shortnameRegEx = '/(?:^|_|\\\\)' . preg_quote($shortname, '/') . '$/';
337
338        foreach ($this->foundClasses as $i => $className) {
339            if (preg_match($shortnameRegEx, $className)) {
340                $class = new ReflectionClass($className);
341
342                if ($class->getFileName() == $filename) {
343                    $newClasses = [$className];
344                    unset($this->foundClasses[$i]);
345                    break;
346                }
347            }
348        }
349
350        foreach ($newClasses as $className) {
351            if (strpos($className, 'PHPUnit_Framework') === 0) {
352                continue;
353            }
354
355            $class = new ReflectionClass($className);
356
357            if (!$class->isAbstract()) {
358                if ($class->hasMethod(PHPUnit_Runner_BaseTestRunner::SUITE_METHODNAME)) {
359                    $method = $class->getMethod(
360                        PHPUnit_Runner_BaseTestRunner::SUITE_METHODNAME
361                    );
362
363                    if ($method->isStatic()) {
364                        $this->addTest($method->invoke(null, $className));
365                    }
366                } elseif ($class->implementsInterface('PHPUnit_Framework_Test')) {
367                    $this->addTestSuite($class);
368                }
369            }
370        }
371
372        $this->numTests = -1;
373    }
374
375    /**
376     * Wrapper for addTestFile() that adds multiple test files.
377     *
378     * @param array|Iterator $filenames
379     *
380     * @throws PHPUnit_Framework_Exception
381     */
382    public function addTestFiles($filenames)
383    {
384        if (!(is_array($filenames) ||
385             (is_object($filenames) && $filenames instanceof Iterator))) {
386            throw PHPUnit_Util_InvalidArgumentHelper::factory(
387                1,
388                'array or iterator'
389            );
390        }
391
392        foreach ($filenames as $filename) {
393            $this->addTestFile((string) $filename);
394        }
395    }
396
397    /**
398     * Counts the number of test cases that will be run by this test.
399     *
400     * @param bool $preferCache Indicates if cache is preferred.
401     *
402     * @return int
403     */
404    public function count($preferCache = false)
405    {
406        if ($preferCache && $this->cachedNumTests !== null) {
407            $numTests = $this->cachedNumTests;
408        } else {
409            $numTests = 0;
410
411            foreach ($this as $test) {
412                $numTests += count($test);
413            }
414
415            $this->cachedNumTests = $numTests;
416        }
417
418        return $numTests;
419    }
420
421    /**
422     * @param ReflectionClass $theClass
423     * @param string          $name
424     *
425     * @return PHPUnit_Framework_Test
426     *
427     * @throws PHPUnit_Framework_Exception
428     */
429    public static function createTest(ReflectionClass $theClass, $name)
430    {
431        $className = $theClass->getName();
432
433        if (!$theClass->isInstantiable()) {
434            return self::warning(
435                sprintf('Cannot instantiate class "%s".', $className)
436            );
437        }
438
439        $backupSettings = PHPUnit_Util_Test::getBackupSettings(
440            $className,
441            $name
442        );
443
444        $preserveGlobalState = PHPUnit_Util_Test::getPreserveGlobalStateSettings(
445            $className,
446            $name
447        );
448
449        $runTestInSeparateProcess = PHPUnit_Util_Test::getProcessIsolationSettings(
450            $className,
451            $name
452        );
453
454        $constructor = $theClass->getConstructor();
455
456        if ($constructor !== null) {
457            $parameters = $constructor->getParameters();
458
459            // TestCase() or TestCase($name)
460            if (count($parameters) < 2) {
461                $test = new $className;
462            } // TestCase($name, $data)
463            else {
464                try {
465                    $data = PHPUnit_Util_Test::getProvidedData(
466                        $className,
467                        $name
468                    );
469                } catch (PHPUnit_Framework_IncompleteTestError $e) {
470                    $message = sprintf(
471                        'Test for %s::%s marked incomplete by data provider',
472                        $className,
473                        $name
474                    );
475
476                    $_message = $e->getMessage();
477
478                    if (!empty($_message)) {
479                        $message .= "\n" . $_message;
480                    }
481
482                    $data = self::incompleteTest($className, $name, $message);
483                } catch (PHPUnit_Framework_SkippedTestError $e) {
484                    $message = sprintf(
485                        'Test for %s::%s skipped by data provider',
486                        $className,
487                        $name
488                    );
489
490                    $_message = $e->getMessage();
491
492                    if (!empty($_message)) {
493                        $message .= "\n" . $_message;
494                    }
495
496                    $data = self::skipTest($className, $name, $message);
497                } catch (Throwable $_t) {
498                    $t = $_t;
499                } catch (Exception $_t) {
500                    $t = $_t;
501                }
502
503                if (isset($t)) {
504                    $message = sprintf(
505                        'The data provider specified for %s::%s is invalid.',
506                        $className,
507                        $name
508                    );
509
510                    $_message = $t->getMessage();
511
512                    if (!empty($_message)) {
513                        $message .= "\n" . $_message;
514                    }
515
516                    $data = self::warning($message);
517                }
518
519                // Test method with @dataProvider.
520                if (isset($data)) {
521                    $test = new PHPUnit_Framework_TestSuite_DataProvider(
522                        $className . '::' . $name
523                    );
524
525                    if (empty($data)) {
526                        $data = self::warning(
527                            sprintf(
528                                'No tests found in suite "%s".',
529                                $test->getName()
530                            )
531                        );
532                    }
533
534                    $groups = PHPUnit_Util_Test::getGroups($className, $name);
535
536                    if ($data instanceof PHPUnit_Framework_WarningTestCase ||
537                        $data instanceof PHPUnit_Framework_SkippedTestCase ||
538                        $data instanceof PHPUnit_Framework_IncompleteTestCase) {
539                        $test->addTest($data, $groups);
540                    } else {
541                        foreach ($data as $_dataName => $_data) {
542                            $_test = new $className($name, $_data, $_dataName);
543
544                            if ($runTestInSeparateProcess) {
545                                $_test->setRunTestInSeparateProcess(true);
546
547                                if ($preserveGlobalState !== null) {
548                                    $_test->setPreserveGlobalState($preserveGlobalState);
549                                }
550                            }
551
552                            if ($backupSettings['backupGlobals'] !== null) {
553                                $_test->setBackupGlobals(
554                                    $backupSettings['backupGlobals']
555                                );
556                            }
557
558                            if ($backupSettings['backupStaticAttributes'] !== null) {
559                                $_test->setBackupStaticAttributes(
560                                    $backupSettings['backupStaticAttributes']
561                                );
562                            }
563
564                            $test->addTest($_test, $groups);
565                        }
566                    }
567                } else {
568                    $test = new $className;
569                }
570            }
571        }
572
573        if (!isset($test)) {
574            throw new PHPUnit_Framework_Exception('No valid test provided.');
575        }
576
577        if ($test instanceof PHPUnit_Framework_TestCase) {
578            $test->setName($name);
579
580            if ($runTestInSeparateProcess) {
581                $test->setRunTestInSeparateProcess(true);
582
583                if ($preserveGlobalState !== null) {
584                    $test->setPreserveGlobalState($preserveGlobalState);
585                }
586            }
587
588            if ($backupSettings['backupGlobals'] !== null) {
589                $test->setBackupGlobals($backupSettings['backupGlobals']);
590            }
591
592            if ($backupSettings['backupStaticAttributes'] !== null) {
593                $test->setBackupStaticAttributes(
594                    $backupSettings['backupStaticAttributes']
595                );
596            }
597        }
598
599        return $test;
600    }
601
602    /**
603     * Creates a default TestResult object.
604     *
605     * @return PHPUnit_Framework_TestResult
606     */
607    protected function createResult()
608    {
609        return new PHPUnit_Framework_TestResult;
610    }
611
612    /**
613     * Returns the name of the suite.
614     *
615     * @return string
616     */
617    public function getName()
618    {
619        return $this->name;
620    }
621
622    /**
623     * Returns the test groups of the suite.
624     *
625     * @return array
626     */
627    public function getGroups()
628    {
629        return array_keys($this->groups);
630    }
631
632    public function getGroupDetails()
633    {
634        return $this->groups;
635    }
636
637    /**
638     * Set tests groups of the test case
639     *
640     * @param array $groups
641     */
642    public function setGroupDetails(array $groups)
643    {
644        $this->groups = $groups;
645    }
646
647    /**
648     * Runs the tests and collects their result in a TestResult.
649     *
650     * @param PHPUnit_Framework_TestResult $result
651     *
652     * @return PHPUnit_Framework_TestResult
653     */
654    public function run(PHPUnit_Framework_TestResult $result = null)
655    {
656        if ($result === null) {
657            $result = $this->createResult();
658        }
659
660        if (count($this) == 0) {
661            return $result;
662        }
663
664        $hookMethods = PHPUnit_Util_Test::getHookMethods($this->name);
665
666        $result->startTestSuite($this);
667
668        try {
669            $this->setUp();
670
671            foreach ($hookMethods['beforeClass'] as $beforeClassMethod) {
672                if ($this->testCase === true &&
673                    class_exists($this->name, false) &&
674                    method_exists($this->name, $beforeClassMethod)) {
675                    if ($missingRequirements = PHPUnit_Util_Test::getMissingRequirements($this->name, $beforeClassMethod)) {
676                        $this->markTestSuiteSkipped(implode(PHP_EOL, $missingRequirements));
677                    }
678
679                    call_user_func([$this->name, $beforeClassMethod]);
680                }
681            }
682        } catch (PHPUnit_Framework_SkippedTestSuiteError $e) {
683            $numTests = count($this);
684
685            for ($i = 0; $i < $numTests; $i++) {
686                $result->startTest($this);
687                $result->addFailure($this, $e, 0);
688                $result->endTest($this, 0);
689            }
690
691            $this->tearDown();
692            $result->endTestSuite($this);
693
694            return $result;
695        } catch (Throwable $_t) {
696            $t = $_t;
697        } catch (Exception $_t) {
698            $t = $_t;
699        }
700
701        if (isset($t)) {
702            $numTests = count($this);
703
704            for ($i = 0; $i < $numTests; $i++) {
705                if ($result->shouldStop()) {
706                    break;
707                }
708
709                $result->startTest($this);
710                $result->addError($this, $t, 0);
711                $result->endTest($this, 0);
712            }
713
714            $this->tearDown();
715            $result->endTestSuite($this);
716
717            return $result;
718        }
719
720        foreach ($this as $test) {
721            if ($result->shouldStop()) {
722                break;
723            }
724
725            if ($test instanceof PHPUnit_Framework_TestCase ||
726                $test instanceof self) {
727                $test->setBeStrictAboutChangesToGlobalState($this->beStrictAboutChangesToGlobalState);
728                $test->setBackupGlobals($this->backupGlobals);
729                $test->setBackupStaticAttributes($this->backupStaticAttributes);
730                $test->setRunTestInSeparateProcess($this->runTestInSeparateProcess);
731            }
732
733            $test->run($result);
734        }
735
736        foreach ($hookMethods['afterClass'] as $afterClassMethod) {
737            if ($this->testCase === true && class_exists($this->name, false) && method_exists($this->name, $afterClassMethod)) {
738                call_user_func([$this->name, $afterClassMethod]);
739            }
740        }
741
742        $this->tearDown();
743
744        $result->endTestSuite($this);
745
746        return $result;
747    }
748
749    /**
750     * @param bool $runTestInSeparateProcess
751     *
752     * @throws PHPUnit_Framework_Exception
753     */
754    public function setRunTestInSeparateProcess($runTestInSeparateProcess)
755    {
756        if (is_bool($runTestInSeparateProcess)) {
757            $this->runTestInSeparateProcess = $runTestInSeparateProcess;
758        } else {
759            throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'boolean');
760        }
761    }
762
763    /**
764     * Runs a test.
765     *
766     * @deprecated
767     *
768     * @param PHPUnit_Framework_Test       $test
769     * @param PHPUnit_Framework_TestResult $result
770     */
771    public function runTest(PHPUnit_Framework_Test $test, PHPUnit_Framework_TestResult $result)
772    {
773        $test->run($result);
774    }
775
776    /**
777     * Sets the name of the suite.
778     *
779     * @param  string
780     */
781    public function setName($name)
782    {
783        $this->name = $name;
784    }
785
786    /**
787     * Returns the test at the given index.
788     *
789     * @param  int|false
790     *
791     * @return PHPUnit_Framework_Test
792     */
793    public function testAt($index)
794    {
795        if (isset($this->tests[$index])) {
796            return $this->tests[$index];
797        } else {
798            return false;
799        }
800    }
801
802    /**
803     * Returns the tests as an enumeration.
804     *
805     * @return array
806     */
807    public function tests()
808    {
809        return $this->tests;
810    }
811
812    /**
813     * Set tests of the test suite
814     *
815     * @param array $tests
816     */
817    public function setTests(array $tests)
818    {
819        $this->tests = $tests;
820    }
821
822    /**
823     * Mark the test suite as skipped.
824     *
825     * @param string $message
826     *
827     * @throws PHPUnit_Framework_SkippedTestSuiteError
828     */
829    public function markTestSuiteSkipped($message = '')
830    {
831        throw new PHPUnit_Framework_SkippedTestSuiteError($message);
832    }
833
834    /**
835     * @param ReflectionClass  $class
836     * @param ReflectionMethod $method
837     */
838    protected function addTestMethod(ReflectionClass $class, ReflectionMethod $method)
839    {
840        if (!$this->isTestMethod($method)) {
841            return;
842        }
843
844        $name = $method->getName();
845
846        if (!$method->isPublic()) {
847            $this->addTest(
848                self::warning(
849                    sprintf(
850                        'Test method "%s" in test class "%s" is not public.',
851                        $name,
852                        $class->getName()
853                    )
854                )
855            );
856
857            return;
858        }
859
860        $test = self::createTest($class, $name);
861
862        if ($test instanceof PHPUnit_Framework_TestCase ||
863            $test instanceof PHPUnit_Framework_TestSuite_DataProvider) {
864            $test->setDependencies(
865                PHPUnit_Util_Test::getDependencies($class->getName(), $name)
866            );
867        }
868
869        $this->addTest(
870            $test,
871            PHPUnit_Util_Test::getGroups($class->getName(), $name)
872        );
873    }
874
875    /**
876     * @param ReflectionMethod $method
877     *
878     * @return bool
879     */
880    public static function isTestMethod(ReflectionMethod $method)
881    {
882        if (strpos($method->name, 'test') === 0) {
883            return true;
884        }
885
886        // @scenario on TestCase::testMethod()
887        // @test     on TestCase::testMethod()
888        $docComment = $method->getDocComment();
889
890        return strpos($docComment, '@test') !== false ||
891               strpos($docComment, '@scenario') !== false;
892    }
893
894    /**
895     * @param string $message
896     *
897     * @return PHPUnit_Framework_WarningTestCase
898     */
899    protected static function warning($message)
900    {
901        return new PHPUnit_Framework_WarningTestCase($message);
902    }
903
904    /**
905     * @param string $class
906     * @param string $methodName
907     * @param string $message
908     *
909     * @return PHPUnit_Framework_SkippedTestCase
910     */
911    protected static function skipTest($class, $methodName, $message)
912    {
913        return new PHPUnit_Framework_SkippedTestCase($class, $methodName, $message);
914    }
915
916    /**
917     * @param string $class
918     * @param string $methodName
919     * @param string $message
920     *
921     * @return PHPUnit_Framework_IncompleteTestCase
922     */
923    protected static function incompleteTest($class, $methodName, $message)
924    {
925        return new PHPUnit_Framework_IncompleteTestCase($class, $methodName, $message);
926    }
927
928    /**
929     * @param bool $beStrictAboutChangesToGlobalState
930     */
931    public function setBeStrictAboutChangesToGlobalState($beStrictAboutChangesToGlobalState)
932    {
933        if (is_null($this->beStrictAboutChangesToGlobalState) && is_bool($beStrictAboutChangesToGlobalState)) {
934            $this->beStrictAboutChangesToGlobalState = $beStrictAboutChangesToGlobalState;
935        }
936    }
937
938    /**
939     * @param bool $backupGlobals
940     */
941    public function setBackupGlobals($backupGlobals)
942    {
943        if (is_null($this->backupGlobals) && is_bool($backupGlobals)) {
944            $this->backupGlobals = $backupGlobals;
945        }
946    }
947
948    /**
949     * @param bool $backupStaticAttributes
950     */
951    public function setBackupStaticAttributes($backupStaticAttributes)
952    {
953        if (is_null($this->backupStaticAttributes) &&
954            is_bool($backupStaticAttributes)) {
955            $this->backupStaticAttributes = $backupStaticAttributes;
956        }
957    }
958
959    /**
960     * Returns an iterator for this test suite.
961     *
962     * @return RecursiveIteratorIterator
963     */
964    public function getIterator()
965    {
966        $iterator = new PHPUnit_Util_TestSuiteIterator($this);
967
968        if ($this->iteratorFilter !== null) {
969            $iterator = $this->iteratorFilter->factory($iterator, $this);
970        }
971
972        return $iterator;
973    }
974
975    public function injectFilter(PHPUnit_Runner_Filter_Factory $filter)
976    {
977        $this->iteratorFilter = $filter;
978        foreach ($this as $test) {
979            if ($test instanceof self) {
980                $test->injectFilter($filter);
981            }
982        }
983    }
984
985    /**
986     * Template Method that is called before the tests
987     * of this test suite are run.
988     */
989    protected function setUp()
990    {
991    }
992
993    /**
994     * Template Method that is called after the tests
995     * of this test suite have finished running.
996     */
997    protected function tearDown()
998    {
999    }
1000}
1001