From 4b213d63bdcc45826f764e494c51bb1cc503e825 Mon Sep 17 00:00:00 2001 From: Nuno Maduro Date: Sun, 14 Nov 2021 19:58:25 +0000 Subject: [PATCH] feat: reworks evalution of Test Case --- .php-cs-fixer.dist.php | 1 + composer.json | 3 +- overrides/Runner/TestSuiteLoader.php | 122 ++++++--- src/Bootstrappers/BootEmitter.php | 29 -- src/Bootstrappers/BootExceptionHandler.php | 4 +- src/Bootstrappers/BootFiles.php | 3 +- src/Concerns/Testable.php | 81 +----- src/Datasets.php | 45 +++- src/Emitters/DispatchingEmitter.php | 251 ------------------ src/Factories/Annotations/Depends.php | 28 ++ src/Factories/Annotations/Groups.php | 25 ++ src/Factories/Concerns/HigherOrderable.php | 35 +++ src/Factories/TestCaseFactory.php | 205 ++++++++------ src/Factories/TestCaseMethodFactory.php | 102 +++++++ src/IgnorableTestCase.php | 15 ++ src/Kernel.php | 1 - src/Logging/TeamCity.php | 2 +- src/PendingCalls/TestCall.php | 42 +-- src/Pest.php | 2 +- src/Repositories/TestRepository.php | 157 +++++------ src/Subscribers/EnsureTestsAreLoaded.php | 3 + src/Support/HigherOrderMessage.php | 3 +- src/Support/Str.php | 10 + tests/Features/Datasets.php | 8 +- .../PHPUnit/CustomTestCase/CustomTestCase.php | 2 +- tests/Unit/TestSuite.php | 44 +-- 26 files changed, 603 insertions(+), 620 deletions(-) delete mode 100644 src/Bootstrappers/BootEmitter.php delete mode 100644 src/Emitters/DispatchingEmitter.php create mode 100644 src/Factories/Annotations/Depends.php create mode 100644 src/Factories/Annotations/Groups.php create mode 100644 src/Factories/Concerns/HigherOrderable.php create mode 100644 src/Factories/TestCaseMethodFactory.php create mode 100644 src/IgnorableTestCase.php diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php index efa5d003..3454e972 100644 --- a/.php-cs-fixer.dist.php +++ b/.php-cs-fixer.dist.php @@ -3,6 +3,7 @@ $finder = PhpCsFixer\Finder::create() ->in(__DIR__ . DIRECTORY_SEPARATOR . 'tests') ->in(__DIR__ . DIRECTORY_SEPARATOR . 'bin') + ->in(__DIR__ . DIRECTORY_SEPARATOR . 'overrides') ->in(__DIR__ . DIRECTORY_SEPARATOR . 'stubs') ->in(__DIR__ . DIRECTORY_SEPARATOR . 'src') ->append(['.php-cs-fixer.dist.php']); diff --git a/composer.json b/composer.json index a4ef0856..1b8e7aaa 100644 --- a/composer.json +++ b/composer.json @@ -48,8 +48,7 @@ "illuminate/console": "^8.47.0", "illuminate/support": "^8.47.0", "laravel/dusk": "^6.15.0", - "pestphp/pest-dev-tools": "dev-master", - "pestphp/pest-plugin-mock": "^1.0" + "pestphp/pest-dev-tools": "dev-master" }, "minimum-stability": "dev", "prefer-stable": true, diff --git a/overrides/Runner/TestSuiteLoader.php b/overrides/Runner/TestSuiteLoader.php index 6535c0fa..19b37a82 100644 --- a/overrides/Runner/TestSuiteLoader.php +++ b/overrides/Runner/TestSuiteLoader.php @@ -1,22 +1,5 @@ . * All rights reserved. @@ -51,35 +34,82 @@ use PHPUnit\Framework\WarningTestCase; * POSSIBILITY OF SUCH DAMAGE. */ +declare(strict_types=1); + +namespace PHPUnit\Runner; + +use function array_diff; +use function array_values; +use function basename; +use function class_exists; +use function get_declared_classes; +use Pest\IgnorableTestCase; +use Pest\TestSuite; +use PHPUnit\Framework\TestCase; +use ReflectionClass; +use ReflectionException; +use function stripos; +use function strlen; +use function substr; + +/** + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ final class TestSuiteLoader { /** - * Loads the test suite. + * @psalm-var list + */ + private static array $loadedClasses = []; + + /** + * @psalm-var list + */ + private static array $declaredClasses = []; + + public function __construct() + { + if (empty(self::$declaredClasses)) { + self::$declaredClasses = get_declared_classes(); + } + } + + /** + * @throws Exception */ public function load(string $suiteClassFile): ReflectionClass { - $suiteClassName = basename($suiteClassFile, '.php'); - $loadedClasses = get_declared_classes(); + $suiteClassName = $this->classNameFromFileName($suiteClassFile); if (!class_exists($suiteClassName, false)) { (static function () use ($suiteClassFile) { include_once $suiteClassFile; + + TestSuite::getInstance()->tests->makeIfExists($suiteClassFile); })(); $loadedClasses = array_values( - array_diff(get_declared_classes(), $loadedClasses) + array_diff( + get_declared_classes(), + array_merge( + self::$declaredClasses, + self::$loadedClasses + ) + ) ); - if (empty($loadedClasses)) { - return new ReflectionClass(WarningTestCase::class); + self::$loadedClasses = array_merge($loadedClasses, self::$loadedClasses); + + if (empty(self::$loadedClasses)) { + return $this->exceptionFor($suiteClassName, $suiteClassFile); } } if (!class_exists($suiteClassName, false)) { + // this block will handle namespaced classes $offset = 0 - strlen($suiteClassName); - foreach ($loadedClasses as $loadedClass) { - + foreach (self::$loadedClasses as $loadedClass) { if (stripos(substr($loadedClass, $offset - 1), '\\' . $suiteClassName) === 0) { $suiteClassName = $loadedClass; @@ -89,18 +119,16 @@ final class TestSuiteLoader } if (!class_exists($suiteClassName, false)) { - return new ReflectionClass(WarningTestCase::class); + return $this->exceptionFor($suiteClassName, $suiteClassFile); } try { $class = new ReflectionClass($suiteClassName); + // @codeCoverageIgnoreStart } catch (ReflectionException $e) { - throw new Exception( - $e->getMessage(), - (int) $e->getCode(), - $e - ); + throw new Exception($e->getMessage(), (int) $e->getCode(), $e); } + // @codeCoverageIgnoreEnd if ($class->isSubclassOf(TestCase::class) && !$class->isAbstract()) { return $class; @@ -109,19 +137,39 @@ final class TestSuiteLoader if ($class->hasMethod('suite')) { try { $method = $class->getMethod('suite'); + // @codeCoverageIgnoreStart } catch (ReflectionException $e) { - throw new Exception( - $e->getMessage(), - (int) $e->getCode(), - $e - ); + throw new Exception($e->getMessage(), (int) $e->getCode(), $e); } + // @codeCoverageIgnoreEnd if (!$method->isAbstract() && $method->isPublic() && $method->isStatic()) { return $class; } } - return new ReflectionClass(WarningTestCase::class); + return $this->exceptionFor($suiteClassName, $suiteClassFile); + } + + public function reload(ReflectionClass $aClass): ReflectionClass + { + return $aClass; + } + + private function classNameFromFileName(string $suiteClassFile): string + { + $className = basename($suiteClassFile, '.php'); + $dotPos = strpos($className, '.'); + + if ($dotPos !== false) { + $className = substr($className, 0, $dotPos); + } + + return $className; + } + + private function exceptionFor(string $className, string $filename): ReflectionClass + { + return new ReflectionClass(IgnorableTestCase::class); } } diff --git a/src/Bootstrappers/BootEmitter.php b/src/Bootstrappers/BootEmitter.php deleted file mode 100644 index 0e389baf..00000000 --- a/src/Bootstrappers/BootEmitter.php +++ /dev/null @@ -1,29 +0,0 @@ -setStaticPropertyValue('emitter', new DispatchingEmitter( - $baseEmitter, - )); - } - } -} diff --git a/src/Bootstrappers/BootExceptionHandler.php b/src/Bootstrappers/BootExceptionHandler.php index 2494dc46..a504ee7e 100644 --- a/src/Bootstrappers/BootExceptionHandler.php +++ b/src/Bootstrappers/BootExceptionHandler.php @@ -16,6 +16,8 @@ final class BootExceptionHandler */ public function __invoke(): void { - (new Collision\Provider())->register(); + $handler = new Collision\Provider(); + + $handler->register(); } } diff --git a/src/Bootstrappers/BootFiles.php b/src/Bootstrappers/BootFiles.php index 09958263..51781ff2 100644 --- a/src/Bootstrappers/BootFiles.php +++ b/src/Bootstrappers/BootFiles.php @@ -35,8 +35,7 @@ final class BootFiles */ public function __invoke(): void { - $rootPath = TestSuite::getInstance()->rootPath; - + $rootPath = TestSuite::getInstance()->rootPath; $testsPath = $rootPath . DIRECTORY_SEPARATOR . testDirectory(); foreach (self::STRUCTURE as $filename) { diff --git a/src/Concerns/Testable.php b/src/Concerns/Testable.php index d90229cd..76e8bc88 100644 --- a/src/Concerns/Testable.php +++ b/src/Concerns/Testable.php @@ -5,11 +5,9 @@ declare(strict_types=1); namespace Pest\Concerns; use Closure; -use Pest\Support\Backtrace; use Pest\Support\ChainableClosure; use Pest\Support\ExceptionTrace; use Pest\TestSuite; -use PHPUnit\Framework\ExecutionOrderDependency; use Throwable; /** @@ -17,11 +15,6 @@ use Throwable; */ trait Testable { - /** - * The Test Case description. - */ - private string $__description; - /** * The Test Case "test" closure. */ @@ -47,47 +40,23 @@ trait Testable */ private static ?Closure $__afterAll = null; + /** + * Resets the test case static properties. + */ + public static function flush(): void + { + self::$__beforeAll = null; + self::$__afterAll = null; + } + /** * Creates a new Test Case instance. */ - public function __construct(Closure $test, string $description, array $data) + public function __construct(string $name) { - $this->__test = $test; - $this->__description = $description; - self::$__beforeAll = null; - self::$__afterAll = null; + parent::__construct($name); - parent::__construct('__test'); - - $this->setData($description, $data); - } - - /** - * Adds groups to the Test Case. - */ - public function addGroups(array $groups): void - { - $groups = array_unique(array_merge($this->groups(), $groups)); - - $this->setGroups($groups); - } - - /** - * Adds dependencies to the Test Case. - */ - public function addDependencies(array $tests): void - { - $className = $this::class; - - $tests = array_map(static function (string $test) use ($className): ExecutionOrderDependency { - if (!str_contains($test, '::')) { - $test = "{$className}::{$test}"; - } - - return new ExecutionOrderDependency($test, '__test'); - }, $tests); - - $this->setDependencies($tests); + $this->__test = TestSuite::getInstance()->tests->get(self::$__filename)->getMethod($name)->getClosure($this); } /** @@ -148,16 +117,6 @@ trait Testable : $hook; } - /** - * Gets the Test Case name. - */ - public function getName(bool $withDataSet = true): string - { - return (str_ends_with(Backtrace::file(), 'TestRunner.php') || Backtrace::line() === 277) - ? '__test' - : $this->__description; - } - /** * Gets the Test Case filename. */ @@ -234,26 +193,14 @@ trait Testable TestSuite::getInstance()->test = null; } - /** - * Gets the Test Case filename and description. - */ - public function toString(): string - { - return \sprintf( - '%s::%s', - self::$__filename, - $this->__description - ); - } - /** * Executes the Test Case current test. * * @throws Throwable */ - public function __test(): mixed + private function __runTest(Closure $closure, ...$args): mixed { - return $this->__callClosure($this->__test, $this->__resolveTestArguments(func_get_args())); + return $this->__callClosure($closure, $this->__resolveTestArguments($args)); } /** diff --git a/src/Datasets.php b/src/Datasets.php index 0a245079..38cc6662 100644 --- a/src/Datasets.php +++ b/src/Datasets.php @@ -22,6 +22,13 @@ final class Datasets */ private static array $datasets = []; + /** + * Holds the withs. + * + * @var array + */ + private static array $withs = []; + /** * Sets the given. * @@ -36,35 +43,43 @@ final class Datasets self::$datasets[$name] = $data; } + /** + * Sets the given. + * + * @param Closure|iterable $data + */ + public static function with(string $filename, string $description, Closure|iterable|string $with): void + { + self::$withs[$filename . '>>>' . $description] = $with; + } + /** * @return Closure|iterable */ - public static function get(string $name): Closure|iterable + public static function get(string $filename, string $description): Closure|iterable { - if (!array_key_exists($name, self::$datasets)) { - throw new DatasetDoesNotExist($name); - } + $dataset = self::$withs[$filename . '>>>' . $description]; - return self::$datasets[$name]; + return self::resolve($description, $dataset); } /** * Resolves the current dataset to an array value. * - * @param array|string> $datasets + * @param array|string> $dataset * - * @return array + * @return array|null */ - public static function resolve(string $description, array $datasets): array + public static function resolve(string $description, array $dataset): array|null { /* @phpstan-ignore-next-line */ - if (empty($datasets)) { - return [$description => []]; + if (empty($dataset)) { + return null; } - $datasets = self::processDatasets($datasets); + $dataset = self::processDatasets($dataset); - $datasetCombinations = self::getDataSetsCombinations($datasets); + $datasetCombinations = self::getDataSetsCombinations($dataset); $dataSetDescriptions = []; $dataSetValues = []; @@ -114,7 +129,11 @@ final class Datasets $processedDataset = []; if (is_string($data)) { - $datasets[$index] = self::get($data); + if (!isset(self::$datasets[$data])) { + throw new DatasetDoesNotExist($data); + } + + $datasets[$index] = self::$datasets[$data]; } if (is_callable($datasets[$index])) { diff --git a/src/Emitters/DispatchingEmitter.php b/src/Emitters/DispatchingEmitter.php deleted file mode 100644 index d8e82fda..00000000 --- a/src/Emitters/DispatchingEmitter.php +++ /dev/null @@ -1,251 +0,0 @@ -baseEmitter->eventFacadeSealed(...func_get_args()); - } - - public function testRunnerStarted(): void - { - $this->baseEmitter->testRunnerStarted(...func_get_args()); - } - - public function testRunnerConfigured(Configuration $configuration): void - { - $this->baseEmitter->testRunnerConfigured($configuration); - } - - public function testRunnerFinished(): void - { - $this->baseEmitter->testRunnerFinished(...func_get_args()); - } - - public function assertionMade(mixed $value, Constraint\Constraint $constraint, string $message, bool $hasFailed): void - { - $this->baseEmitter->assertionMade($value, $constraint, $message, $hasFailed); - } - - public function bootstrapFinished(string $filename): void - { - $this->baseEmitter->bootstrapFinished($filename); - } - - public function comparatorRegistered(string $className): void - { - $this->baseEmitter->comparatorRegistered($className); - } - - public function extensionLoaded(string $name, string $version): void - { - $this->baseEmitter->extensionLoaded($name, $version); - } - - public function globalStateCaptured(Snapshot $snapshot): void - { - $this->baseEmitter->globalStateCaptured($snapshot); - } - - public function globalStateModified(Snapshot $snapshotBefore, Snapshot $snapshotAfter, string $diff): void - { - $this->baseEmitter->globalStateModified($snapshotBefore, $snapshotAfter, $diff); - } - - public function globalStateRestored(Snapshot $snapshot): void - { - $this->baseEmitter->globalStateRestored($snapshot); - } - - public function testErrored(Code\Test $test, Throwable $throwable): void - { - $this->baseEmitter->testErrored(...func_get_args()); - } - - public function testFailed(Code\Test $test, Throwable $throwable): void - { - $this->baseEmitter->testFailed(...func_get_args()); - } - - public function testFinished(Code\Test $test): void - { - $this->baseEmitter->testFinished(...func_get_args()); - } - - public function testOutputPrinted(Code\Test $test, string $output): void - { - $this->baseEmitter->testOutputPrinted(...func_get_args()); - } - - public function testPassed(Code\Test $test): void - { - $this->baseEmitter->testPassed(...func_get_args()); - } - - public function testPassedWithWarning(Code\Test $test, Throwable $throwable): void - { - $this->baseEmitter->testPassedWithWarning(...func_get_args()); - } - - public function testConsideredRisky(Code\Test $test, Throwable $throwable): void - { - $this->baseEmitter->testConsideredRisky(...func_get_args()); - } - - public function testAborted(Code\Test $test, Throwable $throwable): void - { - $this->baseEmitter->testAborted(...func_get_args()); - } - - public function testSkipped(Code\Test $test, string $message): void - { - $this->baseEmitter->testSkipped(...func_get_args()); - } - - public function testPrepared(Code\Test $test): void - { - $this->baseEmitter->testPrepared(...func_get_args()); - } - - public function testAfterTestMethodFinished(string $testClassName, Code\ClassMethod ...$calledMethods): void - { - $this->baseEmitter->testAfterTestMethodFinished(...func_get_args()); - } - - public function testAfterLastTestMethodFinished(string $testClassName, Code\ClassMethod ...$calledMethods): void - { - $this->baseEmitter->testAfterLastTestMethodFinished(...func_get_args()); - } - - public function testBeforeFirstTestMethodCalled(string $testClassName, Code\ClassMethod $calledMethod): void - { - $this->baseEmitter->testBeforeFirstTestMethodCalled(...func_get_args()); - } - - public function testBeforeFirstTestMethodFinished(string $testClassName, Code\ClassMethod ...$calledMethods): void - { - $this->baseEmitter->testBeforeFirstTestMethodFinished(...func_get_args()); - } - - public function testBeforeTestMethodCalled(string $testClassName, Code\ClassMethod $calledMethod): void - { - $this->baseEmitter->testBeforeTestMethodCalled(...func_get_args()); - } - - public function testBeforeTestMethodFinished(string $testClassName, Code\ClassMethod ...$calledMethods): void - { - $this->baseEmitter->testBeforeTestMethodFinished(...func_get_args()); - } - - public function testPreConditionCalled(string $testClassName, Code\ClassMethod $calledMethod): void - { - $this->baseEmitter->testPreConditionCalled(...func_get_args()); - } - - public function testPreConditionFinished(string $testClassName, Code\ClassMethod ...$calledMethods): void - { - $this->baseEmitter->testPreConditionFinished(...func_get_args()); - } - - public function testPostConditionCalled(string $testClassName, Code\ClassMethod $calledMethod): void - { - $this->baseEmitter->testPostConditionCalled(...func_get_args()); - } - - public function testPostConditionFinished(string $testClassName, Code\ClassMethod ...$calledMethods): void - { - $this->baseEmitter->testPostConditionFinished(...func_get_args()); - } - - public function testAfterTestMethodCalled(string $testClassName, Code\ClassMethod $calledMethod): void - { - $this->baseEmitter->testAfterTestMethodCalled(...func_get_args()); - } - - public function testAfterLastTestMethodCalled(string $testClassName, Code\ClassMethod $calledMethod): void - { - $this->baseEmitter->testAfterLastTestMethodCalled(...func_get_args()); - } - - public function testMockObjectCreated(string $className): void - { - $this->baseEmitter->testMockObjectCreated(...func_get_args()); - } - - public function testMockObjectCreatedForTrait(string $traitName): void - { - $this->baseEmitter->testMockObjectCreatedForTrait(...func_get_args()); - } - - public function testMockObjectCreatedForAbstractClass(string $className): void - { - $this->baseEmitter->testMockObjectCreatedForAbstractClass(...func_get_args()); - } - - public function testMockObjectCreatedFromWsdl(string $wsdlFile, string $originalClassName, string $mockClassName, array $methods, bool $callOriginalConstructor, array $options): void - { - $this->baseEmitter->testMockObjectCreatedFromWsdl(...func_get_args()); - } - - public function testPartialMockObjectCreated(string $className, string ...$methodNames): void - { - $this->baseEmitter->testPartialMockObjectCreated(...func_get_args()); - } - - public function testTestProxyCreated(string $className, array $constructorArguments): void - { - $this->baseEmitter->testTestProxyCreated(...func_get_args()); - } - - public function testTestStubCreated(string $className): void - { - $this->baseEmitter->testTestStubCreated(...func_get_args()); - } - - public function testSuiteLoaded(TestSuite $testSuite): void - { - EnsureTestsAreLoaded::setTestSuite($testSuite); - - $this->baseEmitter->testSuiteLoaded(...func_get_args()); - } - - public function testSuiteSorted(int $executionOrder, int $executionOrderDefects, bool $resolveDependencies): void - { - $this->baseEmitter->testSuiteSorted(...func_get_args()); - } - - public function testSuiteStarted(TestSuite $testSuite): void - { - $this->baseEmitter->testSuiteStarted(...func_get_args()); - } - - public function testSuiteFinished(TestSuite $testSuite, TestResult $result): void - { - $this->baseEmitter->testSuiteFinished(...func_get_args()); - } -} diff --git a/src/Factories/Annotations/Depends.php b/src/Factories/Annotations/Depends.php new file mode 100644 index 00000000..15b29359 --- /dev/null +++ b/src/Factories/Annotations/Depends.php @@ -0,0 +1,28 @@ +depends as $depend) { + $depend = Str::evaluable($depend); + + $annotations[] = "@depends $depend"; + } + + return $annotations; + } +} diff --git a/src/Factories/Annotations/Groups.php b/src/Factories/Annotations/Groups.php new file mode 100644 index 00000000..96752d6e --- /dev/null +++ b/src/Factories/Annotations/Groups.php @@ -0,0 +1,25 @@ +groups as $group) { + $annotations[] = "@group $group"; + } + + return $annotations; + } +} diff --git a/src/Factories/Concerns/HigherOrderable.php b/src/Factories/Concerns/HigherOrderable.php new file mode 100644 index 00000000..160d8684 --- /dev/null +++ b/src/Factories/Concerns/HigherOrderable.php @@ -0,0 +1,35 @@ +chains = new HigherOrderMessageCollection(); + $this->factoryProxies = new HigherOrderMessageCollection(); + $this->proxies = new HigherOrderMessageCollection(); + } +} diff --git a/src/Factories/TestCaseFactory.php b/src/Factories/TestCaseFactory.php index 4863552a..8882a0da 100644 --- a/src/Factories/TestCaseFactory.php +++ b/src/Factories/TestCaseFactory.php @@ -4,16 +4,18 @@ declare(strict_types=1); namespace Pest\Factories; -use Closure; use ParseError; use Pest\Concerns; use Pest\Contracts\HasPrintableTestCaseName; use Pest\Datasets; +use Pest\Exceptions\DatasetMissing; use Pest\Exceptions\ShouldNotHappen; -use Pest\Support\HigherOrderMessageCollection; +use Pest\Exceptions\TestAlreadyExist; +use Pest\Factories\Concerns\HigherOrderable; +use Pest\Plugins\Environment; +use Pest\Support\Reflection; use Pest\Support\Str; use Pest\TestSuite; -use PHPUnit\Framework\Assert; use PHPUnit\Framework\TestCase; use RuntimeException; @@ -22,22 +24,17 @@ use RuntimeException; */ final class TestCaseFactory { - /** - * Determines if the Test Case will be the "only" being run. - */ - public bool $only = false; + use HigherOrderable; /** - * The Test Case closure. - */ - public Closure $test; - - /** - * The Test Case Dataset, if any. + * The list of annotations. * - * @var array|string> + * @var array */ - public array $datasets = []; + private static array $annotations = [ + Annotations\Depends::class, + Annotations\Groups::class, + ]; /** * The FQN of the Test Case class. @@ -47,7 +44,14 @@ final class TestCaseFactory public string $class = TestCase::class; /** - * An array of FQN of the Test Case traits. + * The list of class methods. + * + * @var array + */ + public array $methods = []; + + /** + * The list of class traits. * * @var array */ @@ -56,81 +60,48 @@ final class TestCaseFactory Concerns\Expectable::class, ]; - /** - * The higher order messages for the factory that are proxyable. - */ - public HigherOrderMessageCollection $factoryProxies; - - /** - * The higher order messages that are proxyable. - */ - public HigherOrderMessageCollection $proxies; - - /** - * The higher order messages that are chainable. - */ - public HigherOrderMessageCollection $chains; - /** * Creates a new Factory instance. */ public function __construct( - public string $filename, - public ?string $description, - Closure $closure = null) - { - $this->test = $closure ?? fn () => Assert::getCount() > 0 ?: self::markTestIncomplete(); + public string $filename + ) { + $this->bootHigherOrderable(); + } - $this->factoryProxies = new HigherOrderMessageCollection(); - $this->proxies = new HigherOrderMessageCollection(); - $this->chains = new HigherOrderMessageCollection(); + public function make(): void + { + $methods = array_filter($this->methods, function ($method) { + return count($onlyTestCases = $this->methodsUsingOnly()) === 0 || in_array($method, $onlyTestCases, true); + }); + + if (count($this->methods) > 0) { + $this->evaluate($this->filename, $methods); + } } /** - * Makes the Test Case classes. + * Returns all the "only" methods. * - * @return array + * @return array */ - public function make(): array + public function methodsUsingOnly(): array { - if ($this->description === null) { - throw ShouldNotHappen::fromMessage('Description can not be empty.'); + if (Environment::name() === Environment::CI) { + return []; } - $chains = $this->chains; - $proxies = $this->proxies; - $factoryTest = $this->test; - - $testClosure = function () use ($chains, $proxies, $factoryTest): mixed { - $proxies->proxy($this); - $chains->chain($this); - - /* @phpstan-ignore-next-line */ - return call_user_func(Closure::bind($factoryTest, $this, $this::class), ...func_get_args()); - }; - - $className = $this->makeClassFromFilename($this->filename); - - $createTest = function ($description, $data) use ($className, $testClosure) { - $testCase = new $className($testClosure, $description, $data); - $this->factoryProxies->proxy($testCase); - - return $testCase; - }; - - $datasets = Datasets::resolve($this->description, $this->datasets); - - return array_map($createTest, array_keys($datasets), $datasets); + return array_filter($this->methods, static fn ($method): bool => $method->only); } /** - * Makes a Fully Qualified Class Name from the given filename. + * Creates a Test Case class using a runtime evaluate. */ - public function makeClassFromFilename(string $filename): string + public function evaluate(string $filename, array $methods): string { if ('\\' === DIRECTORY_SEPARATOR) { // In case Windows, strtolower drive name, like in UsesCall. - $filename = (string) preg_replace_callback('~^(?P[a-z]+:\\\)~i', fn ($match): string => strtolower($match['drive']), $filename); + $filename = (string) preg_replace_callback('~^(?P[a-z]+:\\\)~i', static fn ($match): string => strtolower($match['drive']), $filename); } $filename = str_replace('\\\\', '\\', addslashes((string) realpath($filename))); @@ -152,7 +123,9 @@ final class TestCaseFactory } $hasPrintableTestCaseClassFQN = sprintf('\%s', HasPrintableTestCaseName::class); - $traitsCode = sprintf('use %s;', implode(', ', array_map(fn ($trait): string => sprintf('\%s', $trait), $this->traits))); + $traitsCode = sprintf('use %s;', implode(', ', array_map( + static fn ($trait): string => sprintf('\%s', $trait), $this->traits)) + ); $partsFQN = explode('\\', $classFQN); $className = array_pop($partsFQN); @@ -164,14 +137,65 @@ final class TestCaseFactory $classFQN .= $className; } + $methodsCode = implode('', array_map(static function (TestCaseMethodFactory $method): string { + $methodName = Str::evaluable($method->description); + + $datasetsCode = ''; + $annotations = ['@test']; + + foreach (self::$annotations as $annotation) { + $annotations = (new $annotation())->add($method, $annotations); + } + + if (!empty($method->datasets)) { + $dataProviderName = $methodName . '_dataset'; + $annotations[] = "@dataProvider $dataProviderName"; + + Datasets::with($method->filename, $methodName, $method->datasets); + + $datasetsCode = << sprintf("\n * %s", $annotation), $annotations, + )); + + return <<__runTest( + \$this->__test, + ...func_get_args(), + ); + } + + $datasetsCode +EOF; + }, $methods)); + try { eval(" namespace $namespace; + use Pest\Datasets as __PestDatasets; + use Pest\TestSuite as __PestTestSuite; + final class $className extends $baseClass implements $hasPrintableTestCaseClassFQN { $traitsCode private static \$__filename = '$filename'; + + $methodsCode } "); } catch (ParseError $caught) { @@ -182,11 +206,40 @@ final class TestCaseFactory } /** - * Determine if the test case will receive argument input from Pest, or not. + * Adds the given Method to the Test Case. */ - public function __receivesArguments(): bool + public function addMethod(TestCaseMethodFactory $method): void { - return count($this->datasets) > 0 - || $this->factoryProxies->count('addDependencies') > 0; + if ($method->description === null) { + throw ShouldNotHappen::fromMessage('The test description may not be empty.'); + } + + if (isset($this->methods[$method->description])) { + throw new TestAlreadyExist($method->filename, $method->description); + } + + if (!$method->receivesArguments()) { + $arguments = Reflection::getFunctionArguments($method->closure); + + if (count($arguments) > 0) { + throw new DatasetMissing($method->filename, $method->description, $arguments); + } + } + + $this->methods[$method->description] = $method; + } + + /** + * Gets a Method by the given name. + */ + public function getMethod(string $methodName): TestCaseMethodFactory + { + foreach ($this->methods as $method) { + if (Str::evaluable($method->description) === $methodName) { + return $method; + } + } + + throw ShouldNotHappen::fromMessage(sprintf('Method %s not found.', $methodName)); } } diff --git a/src/Factories/TestCaseMethodFactory.php b/src/Factories/TestCaseMethodFactory.php new file mode 100644 index 00000000..dd32fceb --- /dev/null +++ b/src/Factories/TestCaseMethodFactory.php @@ -0,0 +1,102 @@ +|string> + */ + public array $datasets = []; + + /** + * The Test Case depends, if any. + * + * @var array + */ + public array $depends = []; + + /** + * The Test Case groups, if any. + * + * @var array + */ + public array $groups = []; + + /** + * Creates a new Factory instance. + */ + public function __construct( + public string $filename, + public ?string $description, + public ?Closure $closure, + ) { + if ($this->closure === null) { + $this->closure = function () { + Assert::getCount() > 0 ?: self::markTestIncomplete(); + }; + } + + $this->bootHigherOrderable(); + } + + /** + * Makes the Test Case classes. + */ + public function getClosure(TestCase $concrete): Closure + { + $concrete::flush(); + + if ($this->description === null) { + throw ShouldNotHappen::fromMessage('Description can not be empty.'); + } + + $closure = $this->closure; + + $testCase = TestSuite::getInstance()->tests->get($this->filename); + + $testCase->factoryProxies->proxy($concrete); + $this->factoryProxies->proxy($concrete); + + $method = $this; + + return function () use ($testCase, $method, $closure): mixed { + $testCase->proxies->proxy($this); + $method->proxies->proxy($this); + + $testCase->chains->chain($this); + $method->chains->chain($this); + + return call_user_func(Closure::bind($closure, $this, $this::class), ...func_get_args()); + }; + } + + /** + * Determine if the test case will receive argument input from Pest, or not. + */ + public function receivesArguments(): bool + { + return count($this->datasets) > 0 || count($this->depends) > 0; + } +} diff --git a/src/IgnorableTestCase.php b/src/IgnorableTestCase.php new file mode 100644 index 00000000..ba4a4bf1 --- /dev/null +++ b/src/IgnorableTestCase.php @@ -0,0 +1,15 @@ +phpunitTeamCity = new BaseTeamCity($out, $verbose, $colors); diff --git a/src/PendingCalls/TestCall.php b/src/PendingCalls/TestCall.php index f6c1300b..25c6426e 100644 --- a/src/PendingCalls/TestCall.php +++ b/src/PendingCalls/TestCall.php @@ -5,7 +5,7 @@ declare(strict_types=1); namespace Pest\PendingCalls; use Closure; -use Pest\Factories\TestCaseFactory; +use Pest\Factories\TestCaseMethodFactory; use Pest\Support\Backtrace; use Pest\Support\HigherOrderCallables; use Pest\Support\NullClosure; @@ -22,7 +22,7 @@ final class TestCall /** * The Test Case Factory. */ - private TestCaseFactory $testCaseFactory; + private TestCaseMethodFactory $testCaseMethod; /** * If test call is descriptionLess. @@ -38,7 +38,7 @@ final class TestCall string $description = null, Closure $closure = null ) { - $this->testCaseFactory = new TestCaseFactory($filename, $description, $closure); + $this->testCaseMethod = new TestCaseMethodFactory($filename, $description, $closure); $this->descriptionLess = $description === null; } @@ -48,7 +48,7 @@ final class TestCall public function throws(string $exception, string $exceptionMessage = null): TestCall { if (class_exists($exception)) { - $this->testCaseFactory + $this->testCaseMethod ->proxies ->add(Backtrace::file(), Backtrace::line(), 'expectException', [$exception]); } else { @@ -56,7 +56,7 @@ final class TestCall } if (is_string($exceptionMessage)) { - $this->testCaseFactory + $this->testCaseMethod ->proxies ->add(Backtrace::file(), Backtrace::line(), 'expectExceptionMessage', [$exceptionMessage]); } @@ -90,10 +90,10 @@ final class TestCall * * @param array<\Closure|iterable|string> $data */ - public function with(...$data): TestCall + public function with(Closure|iterable|string ...$data): TestCall { foreach ($data as $dataset) { - $this->testCaseFactory->datasets[] = $dataset; + $this->testCaseMethod->datasets[] = $dataset; } return $this; @@ -102,11 +102,11 @@ final class TestCall /** * Sets the test depends. */ - public function depends(string ...$tests): TestCall + public function depends(string ...$depends): TestCall { - $this->testCaseFactory - ->factoryProxies - ->add(Backtrace::file(), Backtrace::line(), 'addDependencies', [$tests]); + foreach ($depends as $depend) { + $this->testCaseMethod->depends[] = $depend; + } return $this; } @@ -116,7 +116,7 @@ final class TestCall */ public function only(): TestCall { - $this->testCaseFactory->only = true; + $this->testCaseMethod->only = true; return $this; } @@ -126,9 +126,9 @@ final class TestCall */ public function group(string ...$groups): TestCall { - $this->testCaseFactory - ->factoryProxies - ->add(Backtrace::file(), Backtrace::line(), 'addGroups', [$groups]); + foreach ($groups as $group) { + $this->testCaseMethod->groups[] = $group; + } return $this; } @@ -153,7 +153,7 @@ final class TestCall /** @var callable(): bool $condition */ $condition = $condition->bindTo(null); - $this->testCaseFactory + $this->testCaseMethod ->chains ->addWhen($condition, Backtrace::file(), Backtrace::line(), 'markTestSkipped', [$message]); @@ -185,16 +185,16 @@ final class TestCall */ private function addChain(string $name, array $arguments = null): self { - $this->testCaseFactory + $this->testCaseMethod ->chains ->add(Backtrace::file(), Backtrace::line(), $name, $arguments); if ($this->descriptionLess) { $exporter = new Exporter(); - if ($this->testCaseFactory->description !== null) { - $this->testCaseFactory->description .= ' → '; + if ($this->testCaseMethod->description !== null) { + $this->testCaseMethod->description .= ' → '; } - $this->testCaseFactory->description .= $arguments === null + $this->testCaseMethod->description .= $arguments === null ? $name : sprintf('%s %s', $name, $exporter->shortenedRecursiveExport($arguments)); } @@ -207,6 +207,6 @@ final class TestCall */ public function __destruct() { - $this->testSuite->tests->set($this->testCaseFactory); + $this->testSuite->tests->set($this->testCaseMethod); } } diff --git a/src/Pest.php b/src/Pest.php index 56a43e84..e6b0e1f7 100644 --- a/src/Pest.php +++ b/src/Pest.php @@ -6,7 +6,7 @@ namespace Pest; function version(): string { - return '1.20.0'; + return '2.x-dev'; } function testDirectory(string $file = ''): string diff --git a/src/Repositories/TestRepository.php b/src/Repositories/TestRepository.php index 40c2972b..57d8e12c 100644 --- a/src/Repositories/TestRepository.php +++ b/src/Repositories/TestRepository.php @@ -5,16 +5,11 @@ declare(strict_types=1); namespace Pest\Repositories; use Closure; -use Pest\Exceptions\DatasetMissing; -use Pest\Exceptions\ShouldNotHappen; -use Pest\Exceptions\TestAlreadyExist; use Pest\Exceptions\TestCaseAlreadyInUse; use Pest\Exceptions\TestCaseClassOrTraitNotFound; use Pest\Factories\TestCaseFactory; -use Pest\Plugins\Environment; -use Pest\Support\Reflection; +use Pest\Factories\TestCaseMethodFactory; use Pest\Support\Str; -use Pest\TestSuite; use PHPUnit\Framework\TestCase; /** @@ -22,15 +17,10 @@ use PHPUnit\Framework\TestCase; */ final class TestRepository { - /** - * @var non-empty-string - */ - private const SEPARATOR = '>>>'; - /** * @var array */ - private array $state = []; + private array $testCases = []; /** * @var array>> @@ -42,7 +32,7 @@ final class TestRepository */ public function count(): int { - return count($this->state); + return count($this->testCases); } /** @@ -52,74 +42,13 @@ final class TestRepository */ public function getFilenames(): array { - $testsWithOnly = $this->testsUsingOnly(); + $testCases = array_filter($this->testCases, static fn (TestCaseFactory $testCase) => count($testCase->methodsUsingOnly()) > 0); - return array_values(array_map(fn (TestCaseFactory $factory): string => $factory->filename, count($testsWithOnly) > 0 ? $testsWithOnly : $this->state)); - } - - /** - * Calls the given callable foreach test case. - */ - public function build(TestSuite $testSuite, callable $each): void - { - $startsWith = fn (string $target, string $directory): bool => Str::startsWith($target, $directory . DIRECTORY_SEPARATOR); - - foreach ($this->uses as $path => $uses) { - [$classOrTraits, $groups, $hooks] = $uses; - - $setClassName = function (TestCaseFactory $testCase, string $key) use ($path, $classOrTraits, $groups, $startsWith, $hooks): void { - [$filename] = explode(self::SEPARATOR, $key); - - if ((!is_dir($path) && $filename === $path) || (is_dir($path) && $startsWith($filename, $path))) { - foreach ($classOrTraits as $class) { /** @var string $class */ - if (class_exists($class)) { - if ($testCase->class !== TestCase::class) { - throw new TestCaseAlreadyInUse($testCase->class, $class, $filename); - } - $testCase->class = $class; - } elseif (trait_exists($class)) { - $testCase->traits[] = $class; - } - } - - $testCase->factoryProxies->add($filename, 0, 'addGroups', [$groups]); - $testCase->factoryProxies->add($filename, 0, '__addBeforeAll', [$hooks[0] ?? null]); - $testCase->factoryProxies->add($filename, 0, '__addBeforeEach', [$hooks[1] ?? null]); - $testCase->factoryProxies->add($filename, 0, '__addAfterEach', [$hooks[2] ?? null]); - $testCase->factoryProxies->add($filename, 0, '__addAfterAll', [$hooks[3] ?? null]); - } - }; - - foreach ($this->state as $key => $test) { - $setClassName($test, $key); - } + if (count($testCases) === 0) { + $testCases = $this->testCases; } - $onlyState = $this->testsUsingOnly(); - - $state = count($onlyState) > 0 ? $onlyState : $this->state; - - foreach ($state as $testFactory) { - /** @var TestCaseFactory $testFactory */ - $tests = $testFactory->make($testSuite); - foreach ($tests as $test) { - $each($test); - } - } - } - - /** - * Return all tests that have called the only method. - * - * @return array - */ - private function testsUsingOnly(): array - { - if (Environment::name() === Environment::CI) { - return []; - } - - return array_filter($this->state, fn ($testFactory): bool => $testFactory->only); + return array_values(array_map(static fn (TestCaseFactory $factory): string => $factory->filename, $testCases)); } /** @@ -151,27 +80,73 @@ final class TestRepository } } - /** - * Sets a test case by the given filename and description. - */ - public function set(TestCaseFactory $test): void + public function get($filename): TestCaseFactory { - if ($test->description === null) { - throw ShouldNotHappen::fromMessage('Trying to create a test without description.'); + return $this->testCases[$filename]; + } + + /** + * Sets a new test case method. + */ + public function set(TestCaseMethodFactory $method): void + { + if (!isset($this->testCases[$method->filename])) { + $this->testCases[$method->filename] = new TestCaseFactory($method->filename); } - if (array_key_exists(sprintf('%s%s%s', $test->filename, self::SEPARATOR, $test->description), $this->state)) { - throw new TestAlreadyExist($test->filename, $test->description); + $this->testCases[$method->filename]->addMethod($method); + } + + /** + * Makes a Test Case from the given filename, if exists. + */ + public function makeIfExists(string $filename): void + { + if (isset($this->testCases[$filename])) { + $this->make($this->testCases[$filename]); } + } - if (!$test->__receivesArguments()) { - $arguments = Reflection::getFunctionArguments($test->test); + /** + * Makes a Test Case using the given factory. + */ + private function make(TestCaseFactory $testCase): void + { + $startsWith = static fn (string $target, string $directory): bool => Str::startsWith($target, $directory . DIRECTORY_SEPARATOR); - if (count($arguments) > 0) { - throw new DatasetMissing($test->filename, $test->description, $arguments); + foreach ($this->uses as $path => $uses) { + [$classOrTraits, $groups, $hooks] = $uses; + + if ((!is_dir($path) && $testCase->filename === $path) || (is_dir($path) && $startsWith($testCase->filename, $path))) { + foreach ($classOrTraits as $class) { + /** @var string $class */ + if (class_exists($class)) { + if ($testCase->class !== TestCase::class) { + throw new TestCaseAlreadyInUse($testCase->class, $class, $testCase->filename); + } + $testCase->class = $class; + } elseif (trait_exists($class)) { + $testCase->traits[] = $class; + } + } + + foreach ($testCase->methods as $method) { + foreach ($groups as $group) { + $method->groups[] = $group; + } + } + + foreach ($testCase->methods as $method) { + $method->groups = array_merge($groups, $method->groups); + } + + $testCase->factoryProxies->add($testCase->filename, 0, '__addBeforeAll', [$hooks[0] ?? null]); + $testCase->factoryProxies->add($testCase->filename, 0, '__addBeforeEach', [$hooks[1] ?? null]); + $testCase->factoryProxies->add($testCase->filename, 0, '__addAfterEach', [$hooks[2] ?? null]); + $testCase->factoryProxies->add($testCase->filename, 0, '__addAfterAll', [$hooks[3] ?? null]); } } - $this->state[sprintf('%s%s%s', $test->filename, self::SEPARATOR, $test->description)] = $test; + $testCase->make(); } } diff --git a/src/Subscribers/EnsureTestsAreLoaded.php b/src/Subscribers/EnsureTestsAreLoaded.php index 12396941..23954c24 100644 --- a/src/Subscribers/EnsureTestsAreLoaded.php +++ b/src/Subscribers/EnsureTestsAreLoaded.php @@ -25,6 +25,8 @@ final class EnsureTestsAreLoaded implements LoadedSubscriber */ public function notify(Loaded $event): void { + /* + $this->removeWarnings(self::$testSuite); $testSuites = []; @@ -47,6 +49,7 @@ final class EnsureTestsAreLoaded implements LoadedSubscriber } self::$testSuite->addTestSuite($testTestSuite); } + */ } /** diff --git a/src/Support/HigherOrderMessage.php b/src/Support/HigherOrderMessage.php index 99f444f0..1df45e4e 100644 --- a/src/Support/HigherOrderMessage.php +++ b/src/Support/HigherOrderMessage.php @@ -54,8 +54,7 @@ final class HigherOrderMessage try { return is_array($this->arguments) ? Reflection::call($target, $this->name, $this->arguments) - : $target->{$this->name}; - /* @phpstan-ignore-line */ + : $target->{$this->name}; /* @phpstan-ignore-line */ } catch (Throwable $throwable) { Reflection::setPropertyValue($throwable, 'file', $this->filename); Reflection::setPropertyValue($throwable, 'line', $this->line); diff --git a/src/Support/Str.php b/src/Support/Str.php index a3b7a3ab..a7217704 100644 --- a/src/Support/Str.php +++ b/src/Support/Str.php @@ -48,4 +48,14 @@ final class Str return substr($target, -$length) === $search; } + + /** + * Makes the given string evaluable by an `eval`. + */ + public static function evaluable(string $code): string + { + $code = str_replace(' ', '_', $code); + + return (string) preg_replace('/[^A-Z_a-z0-9\\\\]/', '', $code); + } } diff --git a/tests/Features/Datasets.php b/tests/Features/Datasets.php index be94e596..753c4eaf 100644 --- a/tests/Features/Datasets.php +++ b/tests/Features/Datasets.php @@ -12,7 +12,8 @@ beforeEach(function () { it('throws exception if dataset does not exist', function () { $this->expectException(DatasetDoesNotExist::class); $this->expectExceptionMessage("A dataset with the name `first` does not exist. You can create it using `dataset('first', ['a', 'b']);`."); - Datasets::get('first'); + + Datasets::resolve('foo', ['first']); }); it('throws exception if dataset already exist', function () { @@ -27,13 +28,13 @@ it('sets closures', function () { yield [1]; }); - expect(iterator_to_array(Datasets::get('foo')()))->toBe([[1]]); + expect(Datasets::resolve('foo', ['foo']))->toBe(['foo with (1)' => [1]]); }); it('sets arrays', function () { Datasets::set('bar', [[2]]); - expect(Datasets::get('bar'))->toBe([[2]]); + expect(Datasets::resolve('bar', ['bar']))->toBe(['bar with (2)' => [2]]); }); it('gets bound to test case object', function () { @@ -52,6 +53,7 @@ $datasets = [[1], [2]]; test('lazy datasets', function ($text) use ($state, $datasets) { $state->text .= $text; + expect(in_array([$text], $datasets))->toBe(true); })->with($datasets); diff --git a/tests/PHPUnit/CustomTestCase/CustomTestCase.php b/tests/PHPUnit/CustomTestCase/CustomTestCase.php index 2eb0ad4e..8a71327b 100644 --- a/tests/PHPUnit/CustomTestCase/CustomTestCase.php +++ b/tests/PHPUnit/CustomTestCase/CustomTestCase.php @@ -7,7 +7,7 @@ namespace Tests\CustomTestCase; use function PHPUnit\Framework\assertTrue; use PHPUnit\Framework\TestCase; -class CustomTestCase extends TestCase +abstract class CustomTestCase extends TestCase { public function assertCustomTrue() { diff --git a/tests/Unit/TestSuite.php b/tests/Unit/TestSuite.php index 84212879..a15ad631 100644 --- a/tests/Unit/TestSuite.php +++ b/tests/Unit/TestSuite.php @@ -2,53 +2,55 @@ use Pest\Exceptions\DatasetMissing; use Pest\Exceptions\TestAlreadyExist; -use Pest\Factories\TestCaseFactory; +use Pest\Factories\TestCaseMethodFactory; use Pest\Plugins\Environment; use Pest\TestSuite; it('does not allow to add the same test description twice', function () { $testSuite = new TestSuite(getcwd(), 'tests'); - $test = function () {}; - $testSuite->tests->set(new TestCaseFactory(__FILE__, 'foo', $test)); - $testSuite->tests->set(new TestCaseFactory(__FILE__, 'foo', $test)); + $method = new TestCaseMethodFactory('foo', 'bar', null); + + $testSuite->tests->set($method); + $testSuite->tests->set($method); })->throws( TestAlreadyExist::class, - sprintf('A test with the description `%s` already exist in the filename `%s`.', 'foo', __FILE__), + sprintf('A test with the description `%s` already exist in the filename `%s`.', 'bar', 'foo'), ); it('alerts users about tests with arguments but no input', function () { $testSuite = new TestSuite(getcwd(), 'tests'); - $test = function (int $arg) {}; - $testSuite->tests->set(new TestCaseFactory(__FILE__, 'foo', $test)); + + $method = new TestCaseMethodFactory('foo', 'bar', function (int $arg) {}); + + $testSuite->tests->set($method); })->throws( DatasetMissing::class, - sprintf("A test with the description '%s' has %d argument(s) ([%s]) and no dataset(s) provided in %s", 'foo', 1, 'int $arg', __FILE__), + sprintf("A test with the description '%s' has %d argument(s) ([%s]) and no dataset(s) provided in %s", 'bar', 1, 'int $arg', 'foo'), ); it('can return an array of all test suite filenames', function () { $testSuite = TestSuite::getInstance(getcwd(), 'tests'); - $test = function () {}; - $testSuite->tests->set(new TestCaseFactory(__FILE__, 'foo', $test)); - $testSuite->tests->set(new TestCaseFactory(__FILE__, 'bar', $test)); + + $testSuite->tests->set(new TestCaseMethodFactory('a', 'b', null)); + $testSuite->tests->set(new TestCaseMethodFactory('c', 'd', null)); expect($testSuite->tests->getFilenames())->toEqual([ - __FILE__, - __FILE__, + 'a', + 'c', ]); }); it('can filter the test suite filenames to those with the only method', function () { $testSuite = new TestSuite(getcwd(), 'tests'); - $test = function () {}; - $testWithOnly = new TestCaseFactory(__FILE__, 'foo', $test); + $testWithOnly = new TestCaseMethodFactory('a', 'b', null); $testWithOnly->only = true; $testSuite->tests->set($testWithOnly); - $testSuite->tests->set(new TestCaseFactory('Baz/Bar/Boo.php', 'bar', $test)); + $testSuite->tests->set(new TestCaseMethodFactory('c', 'd', null)); expect($testSuite->tests->getFilenames())->toEqual([ - __FILE__, + 'a', ]); }); @@ -59,15 +61,15 @@ it('does not filter the test suite filenames to those with the only method when $test = function () {}; - $testWithOnly = new TestCaseFactory(__FILE__, 'foo', $test); + $testWithOnly = new TestCaseMethodFactory('a', 'b', null); $testWithOnly->only = true; $testSuite->tests->set($testWithOnly); - $testSuite->tests->set(new TestCaseFactory('Baz/Bar/Boo.php', 'bar', $test)); + $testSuite->tests->set(new TestCaseMethodFactory('c', 'd', null)); expect($testSuite->tests->getFilenames())->toEqual([ - __FILE__, - 'Baz/Bar/Boo.php', + 'a', + 'c', ]); Environment::name($previousEnvironment);