芝麻web文件管理V1.00
编辑当前文件:/home2/sdektunc/xmintal-back/vendor/phpunit/phpunit/src/Framework/TestSuite.php
* * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace PHPUnit\Framework; use const PHP_EOL; use function array_keys; use function array_merge; use function array_slice; use function basename; use function call_user_func; use function class_exists; use function count; use function dirname; use function file_exists; use function get_declared_classes; use function implode; use function is_bool; use function is_object; use function is_string; use function method_exists; use function preg_match; use function preg_quote; use function sprintf; use function substr; use Iterator; use IteratorAggregate; use PHPUnit\Runner\BaseTestRunner; use PHPUnit\Runner\Filter\Factory; use PHPUnit\Runner\PhptTestCase; use PHPUnit\Util\FileLoader; use PHPUnit\Util\Reflection; use PHPUnit\Util\Test as TestUtil; use ReflectionClass; use ReflectionException; use ReflectionMethod; use SebastianBergmann\CodeCoverage\CoveredCodeNotExecutedException; use SebastianBergmann\CodeCoverage\MissingCoversAnnotationException; use SebastianBergmann\CodeCoverage\RuntimeException; use SebastianBergmann\CodeCoverage\UnintentionallyCoveredCodeException; use Throwable; /** * @template-implements IteratorAggregate
* * @internal This class is not covered by the backward compatibility promise for PHPUnit */ class TestSuite implements IteratorAggregate, SelfDescribing, Test { /** * Enable or disable the backup and restoration of the $GLOBALS array. * * @var bool */ protected $backupGlobals; /** * Enable or disable the backup and restoration of static attributes. * * @var bool */ protected $backupStaticAttributes; /** * @var bool */ protected $runTestInSeparateProcess = false; /** * The name of the test suite. * * @var string */ protected $name = ''; /** * The test groups of the test suite. * * @var array */ protected $groups = []; /** * The tests in the test suite. * * @var Test[] */ protected $tests = []; /** * The number of tests in the test suite. * * @var int */ protected $numTests = -1; /** * @var bool */ protected $testCase = false; /** * @var string[] */ protected $foundClasses = []; /** * Last count of tests in this suite. * * @var null|int */ private $cachedNumTests; /** * @var bool */ private $beStrictAboutChangesToGlobalState; /** * @var Factory */ private $iteratorFilter; /** * @var int */ private $declaredClassesPointer; /** * Constructs a new TestSuite:. * * - PHPUnit\Framework\TestSuite() constructs an empty TestSuite. * * - PHPUnit\Framework\TestSuite(ReflectionClass) constructs a * TestSuite from the given class. * * - PHPUnit\Framework\TestSuite(ReflectionClass, String) * constructs a TestSuite from the given class with the given * name. * * - PHPUnit\Framework\TestSuite(String) either constructs a * TestSuite from the given class (if the passed string is the * name of an existing class) or constructs an empty TestSuite * with the given name. * * @param ReflectionClass|string $theClass * * @throws Exception */ public function __construct($theClass = '', string $name = '') { if (!is_string($theClass) && !$theClass instanceof ReflectionClass) { throw InvalidArgumentException::create( 1, 'ReflectionClass object or string' ); } $this->declaredClassesPointer = count(get_declared_classes()); if (!$theClass instanceof ReflectionClass) { if (class_exists($theClass, true)) { if ($name === '') { $name = $theClass; } try { $theClass = new ReflectionClass($theClass); // @codeCoverageIgnoreStart } catch (ReflectionException $e) { throw new Exception( $e->getMessage(), $e->getCode(), $e ); } // @codeCoverageIgnoreEnd } else { $this->setName($theClass); return; } } if (!$theClass->isSubclassOf(TestCase::class)) { $this->setName((string) $theClass); return; } if ($name !== '') { $this->setName($name); } else { $this->setName($theClass->getName()); } $constructor = $theClass->getConstructor(); if ($constructor !== null && !$constructor->isPublic()) { $this->addTest( new WarningTestCase( sprintf( 'Class "%s" has no public constructor.', $theClass->getName() ) ) ); return; } foreach ((new Reflection)->publicMethodsInTestClass($theClass) as $method) { if (!TestUtil::isTestMethod($method)) { continue; } $this->addTestMethod($theClass, $method); } if (empty($this->tests)) { $this->addTest( new WarningTestCase( sprintf( 'No tests found in class "%s".', $theClass->getName() ) ) ); } $this->testCase = true; } /** * Returns a string representation of the test suite. */ public function toString(): string { return $this->getName(); } /** * Adds a test to the suite. * * @param array $groups */ public function addTest(Test $test, $groups = []): void { try { $class = new ReflectionClass($test); // @codeCoverageIgnoreStart } catch (ReflectionException $e) { throw new Exception( $e->getMessage(), $e->getCode(), $e ); } // @codeCoverageIgnoreEnd if (!$class->isAbstract()) { $this->tests[] = $test; $this->numTests = -1; if ($test instanceof self && empty($groups)) { $groups = $test->getGroups(); } if (empty($groups)) { $groups = ['default']; } foreach ($groups as $group) { if (!isset($this->groups[$group])) { $this->groups[$group] = [$test]; } else { $this->groups[$group][] = $test; } } if ($test instanceof TestCase) { $test->setGroups($groups); } } } /** * Adds the tests from the given class to the suite. * * @param object|string $testClass * * @throws Exception */ public function addTestSuite($testClass): void { if (!(is_object($testClass) || (is_string($testClass) && class_exists($testClass)))) { throw InvalidArgumentException::create( 1, 'class name or object' ); } if (!is_object($testClass)) { try { $testClass = new ReflectionClass($testClass); // @codeCoverageIgnoreStart } catch (ReflectionException $e) { throw new Exception( $e->getMessage(), $e->getCode(), $e ); } // @codeCoverageIgnoreEnd } if ($testClass instanceof self) { $this->addTest($testClass); } elseif ($testClass instanceof ReflectionClass) { $suiteMethod = false; if (!$testClass->isAbstract() && $testClass->hasMethod(BaseTestRunner::SUITE_METHODNAME)) { try { $method = $testClass->getMethod( BaseTestRunner::SUITE_METHODNAME ); // @codeCoverageIgnoreStart } catch (ReflectionException $e) { throw new Exception( $e->getMessage(), $e->getCode(), $e ); } // @codeCoverageIgnoreEnd if ($method->isStatic()) { $this->addTest( $method->invoke(null, $testClass->getName()) ); $suiteMethod = true; } } if (!$suiteMethod && !$testClass->isAbstract() && $testClass->isSubclassOf(TestCase::class)) { $this->addTest(new self($testClass)); } } else { throw new Exception; } } /** * Wraps both
addTest()
and
addTestSuite
* as well as the separate import statements for the user's convenience. * * If the named file cannot be read or there are no new tests that can be * added, a
PHPUnit\Framework\WarningTestCase
will be created instead, * leaving the current test run untouched. * * @throws Exception */ public function addTestFile(string $filename): void { if (file_exists($filename) && substr($filename, -5) === '.phpt') { $this->addTest( new PhptTestCase($filename) ); return; } // The given file may contain further stub classes in addition to the // test class itself. Figure out the actual test class. $filename = FileLoader::checkAndLoad($filename); $newClasses = array_slice(get_declared_classes(), $this->declaredClassesPointer); // The diff is empty in case a parent class (with test methods) is added // AFTER a child class that inherited from it. To account for that case, // accumulate all discovered classes, so the parent class may be found in // a later invocation. if (!empty($newClasses)) { // On the assumption that test classes are defined first in files, // process discovered classes in approximate LIFO order, so as to // avoid unnecessary reflection. $this->foundClasses = array_merge($newClasses, $this->foundClasses); $this->declaredClassesPointer = count(get_declared_classes()); } // The test class's name must match the filename, either in full, or as // a PEAR/PSR-0 prefixed short name ('NameSpace_ShortName'), or as a // PSR-1 local short name ('NameSpace\ShortName'). The comparison must be // anchored to prevent false-positive matches (e.g., 'OtherShortName'). $shortName = basename($filename, '.php'); $shortNameRegEx = '/(?:^|_|\\\\)' . preg_quote($shortName, '/') . '$/'; foreach ($this->foundClasses as $i => $className) { if (preg_match($shortNameRegEx, $className)) { try { $class = new ReflectionClass($className); // @codeCoverageIgnoreStart } catch (ReflectionException $e) { throw new Exception( $e->getMessage(), $e->getCode(), $e ); } // @codeCoverageIgnoreEnd if ($class->getFileName() == $filename) { $newClasses = [$className]; unset($this->foundClasses[$i]); break; } } } foreach ($newClasses as $className) { try { $class = new ReflectionClass($className); // @codeCoverageIgnoreStart } catch (ReflectionException $e) { throw new Exception( $e->getMessage(), $e->getCode(), $e ); } // @codeCoverageIgnoreEnd if (dirname($class->getFileName()) === __DIR__) { continue; } if (!$class->isAbstract()) { if ($class->hasMethod(BaseTestRunner::SUITE_METHODNAME)) { try { $method = $class->getMethod( BaseTestRunner::SUITE_METHODNAME ); // @codeCoverageIgnoreStart } catch (ReflectionException $e) { throw new Exception( $e->getMessage(), $e->getCode(), $e ); } // @codeCoverageIgnoreEnd if ($method->isStatic()) { $this->addTest($method->invoke(null, $className)); } } elseif ($class->implementsInterface(Test::class)) { $this->addTestSuite($class); } } } $this->numTests = -1; } /** * Wrapper for addTestFile() that adds multiple test files. * * @throws Exception */ public function addTestFiles(iterable $fileNames): void { foreach ($fileNames as $filename) { $this->addTestFile((string) $filename); } } /** * Counts the number of test cases that will be run by this test. */ public function count(bool $preferCache = false): int { if ($preferCache && $this->cachedNumTests !== null) { return $this->cachedNumTests; } $numTests = 0; foreach ($this as $test) { $numTests += count($test); } $this->cachedNumTests = $numTests; return $numTests; } /** * Returns the name of the suite. */ public function getName(): string { return $this->name; } /** * Returns the test groups of the suite. */ public function getGroups(): array { return array_keys($this->groups); } public function getGroupDetails(): array { return $this->groups; } /** * Set tests groups of the test case. */ public function setGroupDetails(array $groups): void { $this->groups = $groups; } /** * Runs the tests and collects their result in a TestResult. * * @throws \SebastianBergmann\CodeCoverage\InvalidArgumentException * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException * @throws CodeCoverageException * @throws CoveredCodeNotExecutedException * @throws MissingCoversAnnotationException * @throws RuntimeException * @throws UnintentionallyCoveredCodeException * @throws Warning */ public function run(?TestResult $result = null): TestResult { if ($result === null) { $result = $this->createResult(); } if (count($this) === 0) { return $result; } /** @psalm-var class-string $className */ $className = $this->name; $hookMethods = TestUtil::getHookMethods($className); $result->startTestSuite($this); try { foreach ($hookMethods['beforeClass'] as $beforeClassMethod) { if ($this->testCase && class_exists($this->name, false) && method_exists($this->name, $beforeClassMethod)) { if ($missingRequirements = TestUtil::getMissingRequirements($this->name, $beforeClassMethod)) { $this->markTestSuiteSkipped(implode(PHP_EOL, $missingRequirements)); } call_user_func([$this->name, $beforeClassMethod]); } } } catch (SkippedTestSuiteError $error) { foreach ($this->tests() as $test) { $result->startTest($test); $result->addFailure($test, $error, 0); $result->endTest($test, 0); } $result->endTestSuite($this); return $result; } catch (Throwable $t) { $errorAdded = false; foreach ($this->tests() as $test) { if ($result->shouldStop()) { break; } $result->startTest($test); if (!$errorAdded) { $result->addError($test, $t, 0); $errorAdded = true; } else { $result->addFailure( $test, new SkippedTestError('Test skipped because of an error in hook method'), 0 ); } $result->endTest($test, 0); } $result->endTestSuite($this); return $result; } foreach ($this as $test) { if ($result->shouldStop()) { break; } if ($test instanceof TestCase || $test instanceof self) { $test->setBeStrictAboutChangesToGlobalState($this->beStrictAboutChangesToGlobalState); $test->setBackupGlobals($this->backupGlobals); $test->setBackupStaticAttributes($this->backupStaticAttributes); $test->setRunTestInSeparateProcess($this->runTestInSeparateProcess); } $test->run($result); } try { foreach ($hookMethods['afterClass'] as $afterClassMethod) { if ($this->testCase && class_exists($this->name, false) && method_exists($this->name, $afterClassMethod)) { call_user_func([$this->name, $afterClassMethod]); } } } catch (Throwable $t) { $message = "Exception in {$this->name}::{$afterClassMethod}" . PHP_EOL . $t->getMessage(); $error = new SyntheticError($message, 0, $t->getFile(), $t->getLine(), $t->getTrace()); $placeholderTest = clone $test; $placeholderTest->setName($afterClassMethod); $result->startTest($placeholderTest); $result->addFailure($placeholderTest, $error, 0); $result->endTest($placeholderTest, 0); } $result->endTestSuite($this); return $result; } public function setRunTestInSeparateProcess(bool $runTestInSeparateProcess): void { $this->runTestInSeparateProcess = $runTestInSeparateProcess; } public function setName(string $name): void { $this->name = $name; } /** * Returns the test at the given index. * * @return false|Test */ public function testAt(int $index) { return $this->tests[$index] ?? false; } /** * Returns the tests as an enumeration. * * @return Test[] */ public function tests(): array { return $this->tests; } /** * Set tests of the test suite. * * @param Test[] $tests */ public function setTests(array $tests): void { $this->tests = $tests; } /** * Mark the test suite as skipped. * * @param string $message * * @throws SkippedTestSuiteError * * @psalm-return never-return */ public function markTestSuiteSkipped($message = ''): void { throw new SkippedTestSuiteError($message); } /** * @param bool $beStrictAboutChangesToGlobalState */ public function setBeStrictAboutChangesToGlobalState($beStrictAboutChangesToGlobalState): void { if (null === $this->beStrictAboutChangesToGlobalState && is_bool($beStrictAboutChangesToGlobalState)) { $this->beStrictAboutChangesToGlobalState = $beStrictAboutChangesToGlobalState; } } /** * @param bool $backupGlobals */ public function setBackupGlobals($backupGlobals): void { if (null === $this->backupGlobals && is_bool($backupGlobals)) { $this->backupGlobals = $backupGlobals; } } /** * @param bool $backupStaticAttributes */ public function setBackupStaticAttributes($backupStaticAttributes): void { if (null === $this->backupStaticAttributes && is_bool($backupStaticAttributes)) { $this->backupStaticAttributes = $backupStaticAttributes; } } /** * Returns an iterator for this test suite. */ public function getIterator(): Iterator { $iterator = new TestSuiteIterator($this); if ($this->iteratorFilter !== null) { $iterator = $this->iteratorFilter->factory($iterator, $this); } return $iterator; } public function injectFilter(Factory $filter): void { $this->iteratorFilter = $filter; foreach ($this as $test) { if ($test instanceof self) { $test->injectFilter($filter); } } } /** * Creates a default TestResult object. */ protected function createResult(): TestResult { return new TestResult; } /** * @throws Exception */ protected function addTestMethod(ReflectionClass $class, ReflectionMethod $method): void { if (!TestUtil::isTestMethod($method)) { return; } $methodName = $method->getName(); $test = (new TestBuilder)->build($class, $methodName); if ($test instanceof TestCase || $test instanceof DataProviderTestSuite) { $test->setDependencies( TestUtil::getDependencies($class->getName(), $methodName) ); } $this->addTest( $test, TestUtil::getGroups($class->getName(), $methodName) ); } }