|string> */ public array $datasets = []; /** * The test's dependencies. * * @var array */ public array $depends = []; /** * The test's groups. * * @var array */ public array $groups = []; /** * The covered classes and functions. * * @var array */ public array $covers = []; /** * Creates a new test case method factory instance. */ public function __construct( public string $filename, public ?string $description, public ?Closure $closure, ) { $this->closure ??= function (): void { Assert::getCount() > 0 ?: self::markTestIncomplete(); // @phpstan-ignore-line }; $this->bootHigherOrderable(); } /** * Creates the test's closure. */ public function getClosure(TestCase $concrete): Closure { $concrete::flush(); // @phpstan-ignore-line 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 { // @phpstan-ignore-line /* @var TestCase $this */ $testCase->proxies->proxy($this); $method->proxies->proxy($this); $testCase->chains->chain($this); $method->chains->chain($this); return \Pest\Support\Closure::bind($closure, $this, self::class)(...func_get_args()); }; } /** * Determine if the test case will receive argument input from Pest, or not. */ public function receivesArguments(): bool { return $this->datasets !== [] || $this->depends !== []; } /** * Creates a PHPUnit method as a string ready for evaluation. * * @param array> $annotationsToUse * @param array> $attributesToUse */ public function buildForEvaluation(array $annotationsToUse, array $attributesToUse): string { if ($this->description === null) { throw ShouldNotHappen::fromMessage('The test description may not be empty.'); } $methodName = Str::evaluable($this->description); $datasetsCode = ''; $annotations = ['@test']; $attributes = []; foreach ($annotationsToUse as $annotation) { $annotations = (new $annotation())->__invoke($this, $annotations); } foreach ($attributesToUse as $attribute) { $attributes = (new $attribute())->__invoke($this, $attributes); } if ($this->datasets !== [] || $this->repetitions > 1) { $dataProviderName = $methodName.'_dataset'; $annotations[] = "@dataProvider $dataProviderName"; $datasetsCode = $this->buildDatasetForEvaluation($methodName, $dataProviderName); } $annotations = implode('', array_map( static fn (string $annotation): string => sprintf("\n * %s", $annotation), $annotations, )); $attributes = implode('', array_map( static fn (string $attribute): string => sprintf("\n %s", $attribute), $attributes, )); return <<tests->get(self::\$__filename)->getMethod(\$this->name())->getClosure(\$this); return \$this->__runTest( \$test, ...func_get_args(), ); } $datasetsCode PHP; } /** * Creates a PHPUnit Data Provider as a string ready for evaluation. */ private function buildDatasetForEvaluation(string $methodName, string $dataProviderName): string { $datasets = $this->datasets; if ($this->repetitions > 1) { $datasets = [range(1, $this->repetitions), ...$datasets]; } DatasetsRepository::with($this->filename, $methodName, $datasets); return <<