TestSuite::createTest()   F
last analyzed

Complexity

Conditions 29
Paths 1334

Size

Total Lines 185
Code Lines 103

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 29
eloc 103
nc 1334
nop 2
dl 0
loc 185
rs 0
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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