From 7660517f7c4b58e6a6f128cd9a179d2a75fdcbf4 Mon Sep 17 00:00:00 2001 From: danilopolani Date: Fri, 4 Mar 2022 22:28:37 +0100 Subject: [PATCH 01/20] start covers attribute implementation --- src/Factories/Attributes/Covers.php | 35 +++++++++++++++++++++++++ src/Factories/TestCaseMethodFactory.php | 20 +++++++++++++- src/PendingCalls/TestCall.php | 20 ++++++++++++++ 3 files changed, 74 insertions(+), 1 deletion(-) create mode 100644 src/Factories/Attributes/Covers.php diff --git a/src/Factories/Attributes/Covers.php b/src/Factories/Attributes/Covers.php new file mode 100644 index 00000000..2c6234f3 --- /dev/null +++ b/src/Factories/Attributes/Covers.php @@ -0,0 +1,35 @@ + $attributes + * + * @return array + */ + public function __invoke(TestCaseMethodFactory $method, array $attributes): array + { + foreach ($method->covers as $covering) { + if (is_array($covering)) { + $attributes[] = "#[\PHPUnit\Framework\Attributes\CoversClass({$covering[0]}]"; + $attributes[] = "#[\PHPUnit\Framework\Attributes\CoversFunction({$covering[1]}]"; + } else { + $attributes[] = "#[\PHPUnit\Framework\Attributes\CoversClass($covering)]"; + } + } + + return $attributes; + } +} diff --git a/src/Factories/TestCaseMethodFactory.php b/src/Factories/TestCaseMethodFactory.php index 987a2d27..2c029162 100644 --- a/src/Factories/TestCaseMethodFactory.php +++ b/src/Factories/TestCaseMethodFactory.php @@ -47,6 +47,13 @@ final class TestCaseMethodFactory */ public array $groups = []; + /** + * The covered classes and methods, if any. + * + * @var array + */ + public array $covers = []; + /** * Creates a new Factory instance. */ @@ -108,7 +115,7 @@ final class TestCaseMethodFactory * * @param array $annotationsToUse */ - public function buildForEvaluation(string $classFQN, array $annotationsToUse): string + public function buildForEvaluation(string $classFQN, array $annotationsToUse, array $attributesToUse): string { if ($this->description === null) { throw ShouldNotHappen::fromMessage('The test description may not be empty.'); @@ -122,12 +129,18 @@ final class TestCaseMethodFactory $datasetsCode = ''; $annotations = ['@test']; + $attributes = []; foreach ($annotationsToUse as $annotation) { /** @phpstan-ignore-next-line */ $annotations = (new $annotation())->__invoke($this, $annotations); } + foreach ($attributesToUse as $attribute) { + /** @phpstan-ignore-next-line */ + $attributes = (new $attribute())->__invoke($this, $attributes); + } + if (count($this->datasets) > 0) { $dataProviderName = $methodName . '_dataset'; $annotations[] = "@dataProvider $dataProviderName"; @@ -138,10 +151,15 @@ final class TestCaseMethodFactory static fn ($annotation) => sprintf("\n * %s", $annotation), $annotations, )); + $attributes = implode('', array_map( + static fn ($attribute) => sprintf("\n %s", $attribute), $attributes, + )); + return <<__runTest( diff --git a/src/PendingCalls/TestCall.php b/src/PendingCalls/TestCall.php index f9e786c1..53a0cd2f 100644 --- a/src/PendingCalls/TestCall.php +++ b/src/PendingCalls/TestCall.php @@ -5,6 +5,7 @@ declare(strict_types=1); namespace Pest\PendingCalls; use Closure; +use InvalidArgumentException; use Pest\Factories\TestCaseMethodFactory; use Pest\Support\Backtrace; use Pest\Support\HigherOrderCallables; @@ -168,6 +169,25 @@ final class TestCall return $this; } + /** + * Sets the covered class and method. + */ + public function covers(string|array ...$classes): TestCall + { + foreach ($classes as $i => $class) { + if (is_array($class) && count($class) !== 2) { + throw new InvalidArgumentException(sprintf( + 'The #%s covered class must be an array with exactly 2 items: class and method name.', + $i + )); + } + + $this->testCaseMethod->covers[] = $class; + } + + return $this; + } + /** * Saves the property accessors to be used on the target. */ From 2465b884622197688e6b2e97c9190c44f19a5951 Mon Sep 17 00:00:00 2001 From: danilopolani Date: Sat, 5 Mar 2022 16:23:05 +0100 Subject: [PATCH 02/20] add covers list and attributes mutator --- src/Factories/Attributes/Covers.php | 15 +++++++--- src/Factories/Covers/CoversClass.php | 16 ++++++++++ src/Factories/Covers/CoversFunction.php | 16 ++++++++++ src/Factories/Covers/CoversNothing.php | 13 ++++++++ src/Factories/TestCaseFactory.php | 11 ++++++- src/Factories/TestCaseMethodFactory.php | 2 +- src/PendingCalls/TestCall.php | 40 ++++++++++++++++++------- 7 files changed, 96 insertions(+), 17 deletions(-) create mode 100644 src/Factories/Covers/CoversClass.php create mode 100644 src/Factories/Covers/CoversFunction.php create mode 100644 src/Factories/Covers/CoversNothing.php diff --git a/src/Factories/Attributes/Covers.php b/src/Factories/Attributes/Covers.php index 2c6234f3..946bd1fd 100644 --- a/src/Factories/Attributes/Covers.php +++ b/src/Factories/Attributes/Covers.php @@ -4,6 +4,8 @@ declare(strict_types=1); namespace Pest\Factories\Attributes; +use Pest\Factories\Covers\CoversClass; +use Pest\Factories\Covers\CoversFunction; use Pest\Factories\TestCaseMethodFactory; /** @@ -22,11 +24,16 @@ final class Covers public function __invoke(TestCaseMethodFactory $method, array $attributes): array { foreach ($method->covers as $covering) { - if (is_array($covering)) { - $attributes[] = "#[\PHPUnit\Framework\Attributes\CoversClass({$covering[0]}]"; - $attributes[] = "#[\PHPUnit\Framework\Attributes\CoversFunction({$covering[1]}]"; + if ($covering instanceof CoversClass) { + $attributes[] = "#[\PHPUnit\Framework\Attributes\CoversClass({$covering->class}]"; + + if (!is_null($covering->method)) { + $attributes[] = "#[\PHPUnit\Framework\Attributes\CoversFunction({$covering->method}]"; + } + } else if ($covering instanceof CoversFunction) { + $attributes[] = "#[\PHPUnit\Framework\Attributes\CoversFunction({$covering->function}]"; } else { - $attributes[] = "#[\PHPUnit\Framework\Attributes\CoversClass($covering)]"; + $attributes[] = "#[\PHPUnit\Framework\Attributes\CoversNothing]"; } } diff --git a/src/Factories/Covers/CoversClass.php b/src/Factories/Covers/CoversClass.php new file mode 100644 index 00000000..934660fd --- /dev/null +++ b/src/Factories/Covers/CoversClass.php @@ -0,0 +1,16 @@ + + */ + private static array $attributes = [ + Attributes\Covers::class, + ]; + /** * The FQN of the Test Case class. * @@ -142,7 +151,7 @@ final class TestCaseFactory } $methodsCode = implode('', array_map( - fn (TestCaseMethodFactory $methodFactory) => $methodFactory->buildForEvaluation($classFQN, self::$annotations), + fn (TestCaseMethodFactory $methodFactory) => $methodFactory->buildForEvaluation($classFQN, self::$annotations, self::$attributes), $methods )); diff --git a/src/Factories/TestCaseMethodFactory.php b/src/Factories/TestCaseMethodFactory.php index 2c029162..aac6c8dc 100644 --- a/src/Factories/TestCaseMethodFactory.php +++ b/src/Factories/TestCaseMethodFactory.php @@ -50,7 +50,7 @@ final class TestCaseMethodFactory /** * The covered classes and methods, if any. * - * @var array + * @var array */ public array $covers = []; diff --git a/src/PendingCalls/TestCall.php b/src/PendingCalls/TestCall.php index 53a0cd2f..a7c1621e 100644 --- a/src/PendingCalls/TestCall.php +++ b/src/PendingCalls/TestCall.php @@ -5,7 +5,9 @@ declare(strict_types=1); namespace Pest\PendingCalls; use Closure; -use InvalidArgumentException; +use Pest\Factories\Covers\CoversClass; +use Pest\Factories\Covers\CoversFunction; +use Pest\Factories\Covers\CoversNothing; use Pest\Factories\TestCaseMethodFactory; use Pest\Support\Backtrace; use Pest\Support\HigherOrderCallables; @@ -171,19 +173,35 @@ final class TestCall /** * Sets the covered class and method. + * + * @param class-string $class + * @param string|null $method */ - public function covers(string|array ...$classes): TestCall + public function covers(string $class, ?string $method = null): TestCall { - foreach ($classes as $i => $class) { - if (is_array($class) && count($class) !== 2) { - throw new InvalidArgumentException(sprintf( - 'The #%s covered class must be an array with exactly 2 items: class and method name.', - $i - )); - } + $this->testCaseMethod->covers[] = new CoversClass(...func_get_args()); - $this->testCaseMethod->covers[] = $class; - } + return $this; + } + + /** + * Sets the covered function. + * + * @param string $method + */ + public function coversFunction(string $method): TestCall + { + $this->testCaseMethod->covers[] = new CoversFunction(...func_get_args()); + + return $this; + } + + /** + * Sets that the current test covers nothing. + */ + public function coversNothing(): TestCall + { + $this->testCaseMethod->covers[] = new CoversNothing(); return $this; } From a894386b49d1b02e12b54d5788db16ecd0987e6d Mon Sep 17 00:00:00 2001 From: danilopolani Date: Sat, 5 Mar 2022 16:51:12 +0100 Subject: [PATCH 03/20] pass methods name to attribute surrounded by quotes --- src/Factories/Attributes/Covers.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Factories/Attributes/Covers.php b/src/Factories/Attributes/Covers.php index 946bd1fd..a965ca21 100644 --- a/src/Factories/Attributes/Covers.php +++ b/src/Factories/Attributes/Covers.php @@ -28,10 +28,10 @@ final class Covers $attributes[] = "#[\PHPUnit\Framework\Attributes\CoversClass({$covering->class}]"; if (!is_null($covering->method)) { - $attributes[] = "#[\PHPUnit\Framework\Attributes\CoversFunction({$covering->method}]"; + $attributes[] = "#[\PHPUnit\Framework\Attributes\CoversFunction('{$covering->method}']"; } } else if ($covering instanceof CoversFunction) { - $attributes[] = "#[\PHPUnit\Framework\Attributes\CoversFunction({$covering->function}]"; + $attributes[] = "#[\PHPUnit\Framework\Attributes\CoversFunction('{$covering->function}']"; } else { $attributes[] = "#[\PHPUnit\Framework\Attributes\CoversNothing]"; } From 27baad82d03fbe397d7a7a94d132e7506ba52fa2 Mon Sep 17 00:00:00 2001 From: danilopolani Date: Sat, 5 Mar 2022 17:03:45 +0100 Subject: [PATCH 04/20] remove method name on coversClass --- src/Factories/Attributes/Covers.php | 4 ---- src/Factories/Covers/CoversClass.php | 2 +- src/PendingCalls/TestCall.php | 3 +-- 3 files changed, 2 insertions(+), 7 deletions(-) diff --git a/src/Factories/Attributes/Covers.php b/src/Factories/Attributes/Covers.php index a965ca21..136dd432 100644 --- a/src/Factories/Attributes/Covers.php +++ b/src/Factories/Attributes/Covers.php @@ -26,10 +26,6 @@ final class Covers foreach ($method->covers as $covering) { if ($covering instanceof CoversClass) { $attributes[] = "#[\PHPUnit\Framework\Attributes\CoversClass({$covering->class}]"; - - if (!is_null($covering->method)) { - $attributes[] = "#[\PHPUnit\Framework\Attributes\CoversFunction('{$covering->method}']"; - } } else if ($covering instanceof CoversFunction) { $attributes[] = "#[\PHPUnit\Framework\Attributes\CoversFunction('{$covering->function}']"; } else { diff --git a/src/Factories/Covers/CoversClass.php b/src/Factories/Covers/CoversClass.php index 934660fd..dbc3fb86 100644 --- a/src/Factories/Covers/CoversClass.php +++ b/src/Factories/Covers/CoversClass.php @@ -9,7 +9,7 @@ namespace Pest\Factories\Covers; */ final class CoversClass { - public function __construct(public string $class, public ?string $method = null) + public function __construct(public string $class) { // } diff --git a/src/PendingCalls/TestCall.php b/src/PendingCalls/TestCall.php index a7c1621e..3ac00ff1 100644 --- a/src/PendingCalls/TestCall.php +++ b/src/PendingCalls/TestCall.php @@ -175,9 +175,8 @@ final class TestCall * Sets the covered class and method. * * @param class-string $class - * @param string|null $method */ - public function covers(string $class, ?string $method = null): TestCall + public function covers(string $class): TestCall { $this->testCaseMethod->covers[] = new CoversClass(...func_get_args()); From 50d8688b79f02994581013f6ac8062a4c426087b Mon Sep 17 00:00:00 2001 From: danilopolani Date: Sat, 5 Mar 2022 17:06:00 +0100 Subject: [PATCH 05/20] allow multiple values on coversClass and coversFunction --- src/PendingCalls/TestCall.php | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src/PendingCalls/TestCall.php b/src/PendingCalls/TestCall.php index 3ac00ff1..b745ff4c 100644 --- a/src/PendingCalls/TestCall.php +++ b/src/PendingCalls/TestCall.php @@ -172,25 +172,29 @@ final class TestCall } /** - * Sets the covered class and method. + * Sets the covered classes. * - * @param class-string $class + * @param class-string..., $classes */ - public function covers(string $class): TestCall + public function coversClass(string ...$classes): TestCall { - $this->testCaseMethod->covers[] = new CoversClass(...func_get_args()); + foreach ($classes as $class) { + $this->testCaseMethod->covers[] = new CoversClass($class); + } return $this; } /** - * Sets the covered function. + * Sets the covered functions. * - * @param string $method + * @param string..., $functions */ - public function coversFunction(string $method): TestCall + public function coversFunction(string ...$functions): TestCall { - $this->testCaseMethod->covers[] = new CoversFunction(...func_get_args()); + foreach ($functions as $function) { + $this->testCaseMethod->covers[] = new CoversFunction($function); + } return $this; } From 21364779f994f3e96ff81bdfd207430bd4e73c26 Mon Sep 17 00:00:00 2001 From: danilopolani Date: Sat, 5 Mar 2022 17:23:03 +0100 Subject: [PATCH 06/20] move covers attribute above the class --- src/Factories/Attributes/Attribute.php | 18 ++++++++++++++++++ src/Factories/Attributes/Covers.php | 9 ++++++++- src/Factories/TestCaseFactory.php | 16 +++++++++++++++- src/Factories/TestCaseMethodFactory.php | 11 ----------- 4 files changed, 41 insertions(+), 13 deletions(-) create mode 100644 src/Factories/Attributes/Attribute.php diff --git a/src/Factories/Attributes/Attribute.php b/src/Factories/Attributes/Attribute.php new file mode 100644 index 00000000..2eaf8dbf --- /dev/null +++ b/src/Factories/Attributes/Attribute.php @@ -0,0 +1,18 @@ + + * @var array */ private static array $attributes = [ Attributes\Covers::class, @@ -155,6 +155,19 @@ final class TestCaseFactory $methods )); + $classAttributes = []; + + foreach (self::$attributes as $attribute) { + if ($attribute::ABOVE_CLASS) { + /** @phpstan-ignore-next-line */ + $classAttributes = (new $attribute())->__invoke($this, $classAttributes); + } + } + + $classAttributes = implode('', array_map( + static fn ($attribute) => sprintf("\n %s", $attribute), $classAttributes, + )); + try { eval(" namespace $namespace; @@ -162,6 +175,7 @@ final class TestCaseFactory use Pest\Repositories\DatasetsRepository as __PestDatasets; use Pest\TestSuite as __PestTestSuite; + $classAttributes final class $className extends $baseClass implements $hasPrintableTestCaseClassFQN { $traitsCode diff --git a/src/Factories/TestCaseMethodFactory.php b/src/Factories/TestCaseMethodFactory.php index aac6c8dc..bb9e6721 100644 --- a/src/Factories/TestCaseMethodFactory.php +++ b/src/Factories/TestCaseMethodFactory.php @@ -129,18 +129,12 @@ final class TestCaseMethodFactory $datasetsCode = ''; $annotations = ['@test']; - $attributes = []; foreach ($annotationsToUse as $annotation) { /** @phpstan-ignore-next-line */ $annotations = (new $annotation())->__invoke($this, $annotations); } - foreach ($attributesToUse as $attribute) { - /** @phpstan-ignore-next-line */ - $attributes = (new $attribute())->__invoke($this, $attributes); - } - if (count($this->datasets) > 0) { $dataProviderName = $methodName . '_dataset'; $annotations[] = "@dataProvider $dataProviderName"; @@ -151,15 +145,10 @@ final class TestCaseMethodFactory static fn ($annotation) => sprintf("\n * %s", $annotation), $annotations, )); - $attributes = implode('', array_map( - static fn ($attribute) => sprintf("\n %s", $attribute), $attributes, - )); - return <<__runTest( From 1079793ccf3a6a8218f13c9afeac26c410cd9b86 Mon Sep 17 00:00:00 2001 From: danilopolani Date: Sat, 5 Mar 2022 17:25:23 +0100 Subject: [PATCH 07/20] cleanup --- src/Factories/TestCaseFactory.php | 2 +- src/Factories/TestCaseMethodFactory.php | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Factories/TestCaseFactory.php b/src/Factories/TestCaseFactory.php index f9152b49..5f51389c 100644 --- a/src/Factories/TestCaseFactory.php +++ b/src/Factories/TestCaseFactory.php @@ -151,7 +151,7 @@ final class TestCaseFactory } $methodsCode = implode('', array_map( - fn (TestCaseMethodFactory $methodFactory) => $methodFactory->buildForEvaluation($classFQN, self::$annotations, self::$attributes), + fn (TestCaseMethodFactory $methodFactory) => $methodFactory->buildForEvaluation($classFQN, self::$annotations), $methods )); diff --git a/src/Factories/TestCaseMethodFactory.php b/src/Factories/TestCaseMethodFactory.php index bb9e6721..21118b8f 100644 --- a/src/Factories/TestCaseMethodFactory.php +++ b/src/Factories/TestCaseMethodFactory.php @@ -48,7 +48,7 @@ final class TestCaseMethodFactory public array $groups = []; /** - * The covered classes and methods, if any. + * The covered classes and functions, if any. * * @var array */ @@ -115,7 +115,7 @@ final class TestCaseMethodFactory * * @param array $annotationsToUse */ - public function buildForEvaluation(string $classFQN, array $annotationsToUse, array $attributesToUse): string + public function buildForEvaluation(string $classFQN, array $annotationsToUse): string { if ($this->description === null) { throw ShouldNotHappen::fromMessage('The test description may not be empty.'); From 1dc33070fe6b7db23189507cacdb3ebe262186b0 Mon Sep 17 00:00:00 2001 From: danilopolani Date: Sun, 6 Mar 2022 19:02:02 +0100 Subject: [PATCH 08/20] fix phpdoc --- src/Factories/TestCaseFactory.php | 2 +- src/PendingCalls/TestCall.php | 4 ---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/src/Factories/TestCaseFactory.php b/src/Factories/TestCaseFactory.php index 5f51389c..76014818 100644 --- a/src/Factories/TestCaseFactory.php +++ b/src/Factories/TestCaseFactory.php @@ -38,7 +38,7 @@ final class TestCaseFactory /** * The list of annotations. * - * @var array + * @var array */ private static array $attributes = [ Attributes\Covers::class, diff --git a/src/PendingCalls/TestCall.php b/src/PendingCalls/TestCall.php index b745ff4c..7dca121b 100644 --- a/src/PendingCalls/TestCall.php +++ b/src/PendingCalls/TestCall.php @@ -173,8 +173,6 @@ final class TestCall /** * Sets the covered classes. - * - * @param class-string..., $classes */ public function coversClass(string ...$classes): TestCall { @@ -187,8 +185,6 @@ final class TestCall /** * Sets the covered functions. - * - * @param string..., $functions */ public function coversFunction(string ...$functions): TestCall { From 32dbac87c8927c22a7116de31182c334f0409913 Mon Sep 17 00:00:00 2001 From: danilopolani Date: Mon, 7 Mar 2022 16:18:55 +0100 Subject: [PATCH 09/20] fix fqn on coversClass attribute and array evaluation --- src/Factories/Attributes/Covers.php | 4 ++-- src/Factories/TestCaseFactory.php | 8 +++++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/Factories/Attributes/Covers.php b/src/Factories/Attributes/Covers.php index e474e67e..67cf44ad 100644 --- a/src/Factories/Attributes/Covers.php +++ b/src/Factories/Attributes/Covers.php @@ -32,9 +32,9 @@ final class Covers extends Attribute { foreach ($method->covers as $covering) { if ($covering instanceof CoversClass) { - $attributes[] = "#[\PHPUnit\Framework\Attributes\CoversClass({$covering->class}]"; + $attributes[] = "#[\PHPUnit\Framework\Attributes\CoversClass({$covering->class}::class)]"; } else if ($covering instanceof CoversFunction) { - $attributes[] = "#[\PHPUnit\Framework\Attributes\CoversFunction('{$covering->function}']"; + $attributes[] = "#[\PHPUnit\Framework\Attributes\CoversFunction('{$covering->function}')]"; } else { $attributes[] = "#[\PHPUnit\Framework\Attributes\CoversNothing]"; } diff --git a/src/Factories/TestCaseFactory.php b/src/Factories/TestCaseFactory.php index 76014818..d568ee3e 100644 --- a/src/Factories/TestCaseFactory.php +++ b/src/Factories/TestCaseFactory.php @@ -159,13 +159,15 @@ final class TestCaseFactory foreach (self::$attributes as $attribute) { if ($attribute::ABOVE_CLASS) { - /** @phpstan-ignore-next-line */ - $classAttributes = (new $attribute())->__invoke($this, $classAttributes); + foreach ($methods as $methodFactory) { + $classAttributes = (new $attribute())->__invoke($methodFactory, $classAttributes); + } } } $classAttributes = implode('', array_map( - static fn ($attribute) => sprintf("\n %s", $attribute), $classAttributes, + static fn ($attribute) => sprintf("\n %s", $attribute), + array_unique($classAttributes), )); try { From 443f8483864c59526d4655805754004e8469258b Mon Sep 17 00:00:00 2001 From: danilopolani Date: Mon, 7 Mar 2022 17:40:29 +0100 Subject: [PATCH 10/20] fix fqn for coversClass --- src/Factories/Attributes/Covers.php | 5 +++++ src/Factories/TestCaseFactory.php | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Factories/Attributes/Covers.php b/src/Factories/Attributes/Covers.php index 67cf44ad..1d0e6991 100644 --- a/src/Factories/Attributes/Covers.php +++ b/src/Factories/Attributes/Covers.php @@ -32,6 +32,11 @@ final class Covers extends Attribute { foreach ($method->covers as $covering) { if ($covering instanceof CoversClass) { + // Prepend a backslash for FQN classes + if (str_contains($covering->class, '\\')) { + $covering->class = '\\' . $covering->class; + } + $attributes[] = "#[\PHPUnit\Framework\Attributes\CoversClass({$covering->class}::class)]"; } else if ($covering instanceof CoversFunction) { $attributes[] = "#[\PHPUnit\Framework\Attributes\CoversFunction('{$covering->function}')]"; diff --git a/src/Factories/TestCaseFactory.php b/src/Factories/TestCaseFactory.php index d568ee3e..2fb6d429 100644 --- a/src/Factories/TestCaseFactory.php +++ b/src/Factories/TestCaseFactory.php @@ -166,7 +166,7 @@ final class TestCaseFactory } $classAttributes = implode('', array_map( - static fn ($attribute) => sprintf("\n %s", $attribute), + static fn (string $attribute) => sprintf("\n %s", $attribute), array_unique($classAttributes), )); From 985bbf4ea57bbf4b3b9344625b95ff183482245a Mon Sep 17 00:00:00 2001 From: danilopolani Date: Mon, 7 Mar 2022 17:40:43 +0100 Subject: [PATCH 11/20] add tests for covers attribute --- tests/Features/Covers.php | 46 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 tests/Features/Covers.php diff --git a/tests/Features/Covers.php b/tests/Features/Covers.php new file mode 100644 index 00000000..704168c3 --- /dev/null +++ b/tests/Features/Covers.php @@ -0,0 +1,46 @@ +getAttributes(); + + expect($attributes[0]->getName())->toBe('PHPUnit\Framework\Attributes\CoversClass'); + expect($attributes[0]->getArguments()[0])->toBe('P\Tests\Features\TestCoversClass1'); +})->coversClass(TestCoversClass1::class); + +it('uses the correct PHPUnit attribute for function', function () { + $attributes = (new ReflectionClass($this))->getAttributes(); + + expect($attributes[1]->getName())->toBe('PHPUnit\Framework\Attributes\CoversFunction'); + expect($attributes[1]->getArguments()[0])->toBe('foo'); +})->coversFunction('foo'); + +it('uses the correct PHPUnit attribute for nothing', function () { + $attributes = (new ReflectionClass($this))->getAttributes(); + + expect($attributes[2]->getName())->toBe('PHPUnit\Framework\Attributes\CoversNothing'); +})->coversNothing(); + +it('removes duplicated attributes', function () { + $attributes = (new ReflectionClass($this))->getAttributes(); + + expect($attributes)->toHaveCount(7); // 3 classes, 3 functions, 1 nothing + + expect($attributes[3]->getName())->toBe('PHPUnit\Framework\Attributes\CoversClass'); + expect($attributes[3]->getArguments()[0])->toBe('P\Tests\Features\TestCoversClass2'); + expect($attributes[4]->getName())->toBe('PHPUnit\Framework\Attributes\CoversClass'); + expect($attributes[4]->getArguments()[0])->toBe('Pest\Factories\Attributes\Covers'); + expect($attributes[5]->getName())->toBe('PHPUnit\Framework\Attributes\CoversFunction'); + expect($attributes[5]->getArguments()[0])->toBe('bar'); + expect($attributes[6]->getName())->toBe('PHPUnit\Framework\Attributes\CoversFunction'); + expect($attributes[6]->getArguments()[0])->toBe('baz'); +}) + ->coversClass(TestCoversClass2::class, TestCoversClass1::class, Covers::class) + ->coversNothing() + ->coversFunction('bar', 'foo', 'baz'); From edd1d890ca10d6d553a85835e49e63bb1f3be51f Mon Sep 17 00:00:00 2001 From: danilopolani Date: Mon, 7 Mar 2022 17:51:39 +0100 Subject: [PATCH 12/20] replace double foreach with a filter and reduce --- src/Factories/TestCaseFactory.php | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/Factories/TestCaseFactory.php b/src/Factories/TestCaseFactory.php index 2fb6d429..81d11aa6 100644 --- a/src/Factories/TestCaseFactory.php +++ b/src/Factories/TestCaseFactory.php @@ -155,19 +155,20 @@ final class TestCaseFactory $methods )); - $classAttributes = []; + $classAttributesCode = []; + $classAvailableAttributes = array_filter(self::$attributes, fn (string $attribute) => $attribute::ABOVE_CLASS); - foreach (self::$attributes as $attribute) { - if ($attribute::ABOVE_CLASS) { - foreach ($methods as $methodFactory) { - $classAttributes = (new $attribute())->__invoke($methodFactory, $classAttributes); - } - } + foreach ($classAvailableAttributes as $attribute) { + $classAttributesCode = array_reduce( + $methods, + fn (array $carry, TestCaseMethodFactory $methodFactory) => (new $attribute())->__invoke($methodFactory, $carry), + $classAttributesCode + ); } - $classAttributes = implode('', array_map( + $classAttributesCode = implode('', array_map( static fn (string $attribute) => sprintf("\n %s", $attribute), - array_unique($classAttributes), + array_unique($classAttributesCode), )); try { @@ -177,7 +178,7 @@ final class TestCaseFactory use Pest\Repositories\DatasetsRepository as __PestDatasets; use Pest\TestSuite as __PestTestSuite; - $classAttributes + $classAttributesCode final class $className extends $baseClass implements $hasPrintableTestCaseClassFQN { $traitsCode From a5cbdea868f7e311aef06bf9465613b2000da96d Mon Sep 17 00:00:00 2001 From: danilopolani Date: Mon, 7 Mar 2022 17:51:47 +0100 Subject: [PATCH 13/20] fix phpstan issues --- src/Factories/Attributes/Covers.php | 3 +-- src/Factories/Covers/CoversClass.php | 1 - src/Factories/Covers/CoversFunction.php | 1 - src/Factories/Covers/CoversNothing.php | 1 - tests/Features/Covers.php | 10 ++++++++-- 5 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/Factories/Attributes/Covers.php b/src/Factories/Attributes/Covers.php index 1d0e6991..1c41608b 100644 --- a/src/Factories/Attributes/Covers.php +++ b/src/Factories/Attributes/Covers.php @@ -23,7 +23,6 @@ final class Covers extends Attribute /** * Adds attributes regarding the "covers" feature. * - * @param \Pest\Factories\TestCaseMethodFactory $method * @param array $attributes * * @return array @@ -38,7 +37,7 @@ final class Covers extends Attribute } $attributes[] = "#[\PHPUnit\Framework\Attributes\CoversClass({$covering->class}::class)]"; - } else if ($covering instanceof CoversFunction) { + } elseif ($covering instanceof CoversFunction) { $attributes[] = "#[\PHPUnit\Framework\Attributes\CoversFunction('{$covering->function}')]"; } else { $attributes[] = "#[\PHPUnit\Framework\Attributes\CoversNothing]"; diff --git a/src/Factories/Covers/CoversClass.php b/src/Factories/Covers/CoversClass.php index dbc3fb86..44f58487 100644 --- a/src/Factories/Covers/CoversClass.php +++ b/src/Factories/Covers/CoversClass.php @@ -11,6 +11,5 @@ final class CoversClass { public function __construct(public string $class) { - // } } diff --git a/src/Factories/Covers/CoversFunction.php b/src/Factories/Covers/CoversFunction.php index 5fddce9c..5759bbc7 100644 --- a/src/Factories/Covers/CoversFunction.php +++ b/src/Factories/Covers/CoversFunction.php @@ -11,6 +11,5 @@ final class CoversFunction { public function __construct(public string $function) { - // } } diff --git a/src/Factories/Covers/CoversNothing.php b/src/Factories/Covers/CoversNothing.php index 183f5b74..31b3d310 100644 --- a/src/Factories/Covers/CoversNothing.php +++ b/src/Factories/Covers/CoversNothing.php @@ -9,5 +9,4 @@ namespace Pest\Factories\Covers; */ final class CoversNothing { - // } diff --git a/tests/Features/Covers.php b/tests/Features/Covers.php index 704168c3..f52d0740 100644 --- a/tests/Features/Covers.php +++ b/tests/Features/Covers.php @@ -4,8 +4,14 @@ use Pest\Factories\Attributes\Covers; $runCounter = 0; -class TestCoversClass1 {} -class TestCoversClass2 {} +class TestCoversClass1 +{ + +} +class TestCoversClass2 +{ + +} it('uses the correct PHPUnit attribute for class', function () { $attributes = (new ReflectionClass($this))->getAttributes(); From 00029c15ef64dcdcf95fdcd1aa9fc6eb6dd1b603 Mon Sep 17 00:00:00 2001 From: danilopolani Date: Mon, 7 Mar 2022 18:22:30 +0100 Subject: [PATCH 14/20] add generic covers method to accept both classes and functions --- src/PendingCalls/TestCall.php | 26 ++++++++++++++++++++++++++ tests/Features/Covers.php | 27 +++++++++++++++++++++++---- 2 files changed, 49 insertions(+), 4 deletions(-) diff --git a/src/PendingCalls/TestCall.php b/src/PendingCalls/TestCall.php index 7dca121b..82dd4b65 100644 --- a/src/PendingCalls/TestCall.php +++ b/src/PendingCalls/TestCall.php @@ -5,6 +5,7 @@ declare(strict_types=1); namespace Pest\PendingCalls; use Closure; +use InvalidArgumentException; use Pest\Factories\Covers\CoversClass; use Pest\Factories\Covers\CoversFunction; use Pest\Factories\Covers\CoversNothing; @@ -171,6 +172,31 @@ final class TestCall return $this; } + /** + * Sets the covered classes or methods. + */ + public function covers(string ...$classesOrFunctions): TestCall + { + foreach ($classesOrFunctions as $classOrFunction) { + $isClass = class_exists($classOrFunction); + $isMethod = function_exists($classOrFunction); + + if (!$isClass && !$isMethod) { + throw new InvalidArgumentException( + sprintf('No class or method named "%s" has been found.', $classOrFunction) + ); + } + + if ($isClass) { + $this->coversClass($classOrFunction); + } else { + $this->coversFunction($classOrFunction); + } + } + + return $this; + } + /** * Sets the covered classes. */ diff --git a/tests/Features/Covers.php b/tests/Features/Covers.php index f52d0740..b41b3f8a 100644 --- a/tests/Features/Covers.php +++ b/tests/Features/Covers.php @@ -1,18 +1,24 @@ getAttributes(); @@ -36,8 +42,6 @@ it('uses the correct PHPUnit attribute for nothing', function () { it('removes duplicated attributes', function () { $attributes = (new ReflectionClass($this))->getAttributes(); - expect($attributes)->toHaveCount(7); // 3 classes, 3 functions, 1 nothing - expect($attributes[3]->getName())->toBe('PHPUnit\Framework\Attributes\CoversClass'); expect($attributes[3]->getArguments()[0])->toBe('P\Tests\Features\TestCoversClass2'); expect($attributes[4]->getName())->toBe('PHPUnit\Framework\Attributes\CoversClass'); @@ -50,3 +54,18 @@ it('removes duplicated attributes', function () { ->coversClass(TestCoversClass2::class, TestCoversClass1::class, Covers::class) ->coversNothing() ->coversFunction('bar', 'foo', 'baz'); + +it('guesses if the given argument is a class or function', function () { + $attributes = (new ReflectionClass($this))->getAttributes(); + + expect($attributes[7]->getName())->toBe('PHPUnit\Framework\Attributes\CoversClass'); + expect($attributes[7]->getArguments()[0])->toBe('P\Tests\Features\TestCoversClass3'); + expect($attributes[8]->getName())->toBe('PHPUnit\Framework\Attributes\CoversFunction'); + expect($attributes[8]->getArguments()[0])->toBe('testCoversFunction'); +})->covers(TestCoversClass3::class, 'testCoversFunction'); + +it('throws exception if no class nor method has been found', function () { + $testCall = new TestCall(TestSuite::getInstance(), 'filename', 'description', fn () => 'closure'); + + $testCall->covers('fakeName'); +})->throws(InvalidArgumentException::class, 'No class or method named "fakeName" has been found.'); From d0136b63d47b03126e5cbc39a384494f98ad03a7 Mon Sep 17 00:00:00 2001 From: danilopolani Date: Mon, 7 Mar 2022 18:23:06 +0100 Subject: [PATCH 15/20] fix linting --- src/PendingCalls/TestCall.php | 6 ++---- tests/Features/Covers.php | 4 +++- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/PendingCalls/TestCall.php b/src/PendingCalls/TestCall.php index 82dd4b65..bc125599 100644 --- a/src/PendingCalls/TestCall.php +++ b/src/PendingCalls/TestCall.php @@ -178,13 +178,11 @@ final class TestCall public function covers(string ...$classesOrFunctions): TestCall { foreach ($classesOrFunctions as $classOrFunction) { - $isClass = class_exists($classOrFunction); + $isClass = class_exists($classOrFunction); $isMethod = function_exists($classOrFunction); if (!$isClass && !$isMethod) { - throw new InvalidArgumentException( - sprintf('No class or method named "%s" has been found.', $classOrFunction) - ); + throw new InvalidArgumentException(sprintf('No class or method named "%s" has been found.', $classOrFunction)); } if ($isClass) { diff --git a/tests/Features/Covers.php b/tests/Features/Covers.php index b41b3f8a..3b9d6809 100644 --- a/tests/Features/Covers.php +++ b/tests/Features/Covers.php @@ -17,7 +17,9 @@ class TestCoversClass3 { } -function testCoversFunction() { } +function testCoversFunction() +{ +} it('uses the correct PHPUnit attribute for class', function () { $attributes = (new ReflectionClass($this))->getAttributes(); From 15e2e1711bf1ceeed0545cce5a5004d384163e20 Mon Sep 17 00:00:00 2001 From: danilopolani Date: Tue, 8 Mar 2022 14:57:17 +0100 Subject: [PATCH 16/20] enforce class-string for attributes --- src/Factories/TestCaseFactory.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Factories/TestCaseFactory.php b/src/Factories/TestCaseFactory.php index 81d11aa6..ed3d70e8 100644 --- a/src/Factories/TestCaseFactory.php +++ b/src/Factories/TestCaseFactory.php @@ -38,7 +38,7 @@ final class TestCaseFactory /** * The list of annotations. * - * @var array + * @var array> */ private static array $attributes = [ Attributes\Covers::class, From a027e24e3cd14050f2f18e0bef4ebd56fcdec764 Mon Sep 17 00:00:00 2001 From: danilopolani Date: Tue, 8 Mar 2022 15:02:30 +0100 Subject: [PATCH 17/20] fix typo --- src/Factories/Attributes/Attribute.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Factories/Attributes/Attribute.php b/src/Factories/Attributes/Attribute.php index 2eaf8dbf..22a08968 100644 --- a/src/Factories/Attributes/Attribute.php +++ b/src/Factories/Attributes/Attribute.php @@ -10,7 +10,7 @@ namespace Pest\Factories\Attributes; abstract class Attribute { /** - * Determine if the attribute should be placed above the classe instead of above the method. + * Determine if the attribute should be placed above the class instead of above the method. * * @var bool */ From 3795870150de8183c11fba1b9cfd4068bf4ea614 Mon Sep 17 00:00:00 2001 From: danilopolani Date: Wed, 9 Mar 2022 11:05:10 +0100 Subject: [PATCH 18/20] move coversNothing to method annotations --- src/Factories/Annotations/CoversNothing.php | 30 ++++++++++++++++ src/Factories/Attributes/Covers.php | 2 -- src/Factories/TestCaseFactory.php | 27 ++++++++------ src/Factories/TestCaseMethodFactory.php | 14 +++++++- src/PendingCalls/TestCall.php | 2 +- tests/Features/Covers.php | 39 ++++++++++++--------- 6 files changed, 83 insertions(+), 31 deletions(-) create mode 100644 src/Factories/Annotations/CoversNothing.php diff --git a/src/Factories/Annotations/CoversNothing.php b/src/Factories/Annotations/CoversNothing.php new file mode 100644 index 00000000..8faaca1f --- /dev/null +++ b/src/Factories/Annotations/CoversNothing.php @@ -0,0 +1,30 @@ + $annotations + * + * @return array + */ + public function __invoke(TestCaseMethodFactory $method, array $annotations): array + { + if (($method->covers[0] ?? null) instanceof CoversNothingFactory) { + $annotations[] = '@coversNothing'; + } + + return $annotations; + } +} diff --git a/src/Factories/Attributes/Covers.php b/src/Factories/Attributes/Covers.php index 1c41608b..d6d41c4a 100644 --- a/src/Factories/Attributes/Covers.php +++ b/src/Factories/Attributes/Covers.php @@ -39,8 +39,6 @@ final class Covers extends Attribute $attributes[] = "#[\PHPUnit\Framework\Attributes\CoversClass({$covering->class}::class)]"; } elseif ($covering instanceof CoversFunction) { $attributes[] = "#[\PHPUnit\Framework\Attributes\CoversFunction('{$covering->function}')]"; - } else { - $attributes[] = "#[\PHPUnit\Framework\Attributes\CoversNothing]"; } } diff --git a/src/Factories/TestCaseFactory.php b/src/Factories/TestCaseFactory.php index ed3d70e8..7e250eed 100644 --- a/src/Factories/TestCaseFactory.php +++ b/src/Factories/TestCaseFactory.php @@ -33,6 +33,7 @@ final class TestCaseFactory private static array $annotations = [ Annotations\Depends::class, Annotations\Groups::class, + Annotations\CoversNothing::class, ]; /** @@ -150,25 +151,31 @@ final class TestCaseFactory $classFQN .= $className; } - $methodsCode = implode('', array_map( - fn (TestCaseMethodFactory $methodFactory) => $methodFactory->buildForEvaluation($classFQN, self::$annotations), - $methods - )); + $classAvailableAttributes = array_filter(self::$attributes, fn (string $attribute) => $attribute::ABOVE_CLASS); + $methodAvailableAttributes = array_filter(self::$attributes, fn (string $attribute) => !$attribute::ABOVE_CLASS); - $classAttributesCode = []; - $classAvailableAttributes = array_filter(self::$attributes, fn (string $attribute) => $attribute::ABOVE_CLASS); + $classAttributes = []; foreach ($classAvailableAttributes as $attribute) { - $classAttributesCode = array_reduce( + $classAttributes = array_reduce( $methods, fn (array $carry, TestCaseMethodFactory $methodFactory) => (new $attribute())->__invoke($methodFactory, $carry), - $classAttributesCode + $classAttributes ); } + $methodsCode = implode('', array_map( + fn (TestCaseMethodFactory $methodFactory) => $methodFactory->buildForEvaluation( + $classFQN, + self::$annotations, + $methodAvailableAttributes + ), + $methods + )); + $classAttributesCode = implode('', array_map( - static fn (string $attribute) => sprintf("\n %s", $attribute), - array_unique($classAttributesCode), + static fn (string $attribute) => sprintf("\n %s", $attribute), + array_unique($classAttributes), )); try { diff --git a/src/Factories/TestCaseMethodFactory.php b/src/Factories/TestCaseMethodFactory.php index 21118b8f..83c6678d 100644 --- a/src/Factories/TestCaseMethodFactory.php +++ b/src/Factories/TestCaseMethodFactory.php @@ -114,8 +114,9 @@ final class TestCaseMethodFactory * Creates a PHPUnit method as a string ready for evaluation. * * @param array $annotationsToUse + * @param array> $attributesToUse */ - public function buildForEvaluation(string $classFQN, array $annotationsToUse): string + public function buildForEvaluation(string $classFQN, array $annotationsToUse, array $attributesToUse): string { if ($this->description === null) { throw ShouldNotHappen::fromMessage('The test description may not be empty.'); @@ -129,12 +130,18 @@ final class TestCaseMethodFactory $datasetsCode = ''; $annotations = ['@test']; + $attributes = []; foreach ($annotationsToUse as $annotation) { /** @phpstan-ignore-next-line */ $annotations = (new $annotation())->__invoke($this, $annotations); } + foreach ($attributesToUse as $attribute) { + /** @phpstan-ignore-next-line */ + $attributes = (new $attribute())->__invoke($this, $attributes); + } + if (count($this->datasets) > 0) { $dataProviderName = $methodName . '_dataset'; $annotations[] = "@dataProvider $dataProviderName"; @@ -145,10 +152,15 @@ final class TestCaseMethodFactory static fn ($annotation) => sprintf("\n * %s", $annotation), $annotations, )); + $attributes = implode('', array_map( + static fn ($attribute) => sprintf("\n %s", $attribute), $attributes, + )); + return <<__runTest( diff --git a/src/PendingCalls/TestCall.php b/src/PendingCalls/TestCall.php index bc125599..48f612b8 100644 --- a/src/PendingCalls/TestCall.php +++ b/src/PendingCalls/TestCall.php @@ -224,7 +224,7 @@ final class TestCall */ public function coversNothing(): TestCall { - $this->testCaseMethod->covers[] = new CoversNothing(); + $this->testCaseMethod->covers = [new CoversNothing()]; return $this; } diff --git a/tests/Features/Covers.php b/tests/Features/Covers.php index 3b9d6809..63c3d8a1 100644 --- a/tests/Features/Covers.php +++ b/tests/Features/Covers.php @@ -35,37 +35,42 @@ it('uses the correct PHPUnit attribute for function', function () { expect($attributes[1]->getArguments()[0])->toBe('foo'); })->coversFunction('foo'); -it('uses the correct PHPUnit attribute for nothing', function () { - $attributes = (new ReflectionClass($this))->getAttributes(); - - expect($attributes[2]->getName())->toBe('PHPUnit\Framework\Attributes\CoversNothing'); -})->coversNothing(); - it('removes duplicated attributes', function () { $attributes = (new ReflectionClass($this))->getAttributes(); + expect($attributes[2]->getName())->toBe('PHPUnit\Framework\Attributes\CoversClass'); + expect($attributes[2]->getArguments()[0])->toBe('P\Tests\Features\TestCoversClass2'); expect($attributes[3]->getName())->toBe('PHPUnit\Framework\Attributes\CoversClass'); - expect($attributes[3]->getArguments()[0])->toBe('P\Tests\Features\TestCoversClass2'); - expect($attributes[4]->getName())->toBe('PHPUnit\Framework\Attributes\CoversClass'); - expect($attributes[4]->getArguments()[0])->toBe('Pest\Factories\Attributes\Covers'); + expect($attributes[3]->getArguments()[0])->toBe('Pest\Factories\Attributes\Covers'); + expect($attributes[4]->getName())->toBe('PHPUnit\Framework\Attributes\CoversFunction'); + expect($attributes[4]->getArguments()[0])->toBe('bar'); expect($attributes[5]->getName())->toBe('PHPUnit\Framework\Attributes\CoversFunction'); - expect($attributes[5]->getArguments()[0])->toBe('bar'); - expect($attributes[6]->getName())->toBe('PHPUnit\Framework\Attributes\CoversFunction'); - expect($attributes[6]->getArguments()[0])->toBe('baz'); + expect($attributes[5]->getArguments()[0])->toBe('baz'); }) ->coversClass(TestCoversClass2::class, TestCoversClass1::class, Covers::class) - ->coversNothing() ->coversFunction('bar', 'foo', 'baz'); it('guesses if the given argument is a class or function', function () { $attributes = (new ReflectionClass($this))->getAttributes(); - expect($attributes[7]->getName())->toBe('PHPUnit\Framework\Attributes\CoversClass'); - expect($attributes[7]->getArguments()[0])->toBe('P\Tests\Features\TestCoversClass3'); - expect($attributes[8]->getName())->toBe('PHPUnit\Framework\Attributes\CoversFunction'); - expect($attributes[8]->getArguments()[0])->toBe('testCoversFunction'); + expect($attributes[6]->getName())->toBe('PHPUnit\Framework\Attributes\CoversClass'); + expect($attributes[6]->getArguments()[0])->toBe('P\Tests\Features\TestCoversClass3'); + expect($attributes[7]->getName())->toBe('PHPUnit\Framework\Attributes\CoversFunction'); + expect($attributes[7]->getArguments()[0])->toBe('testCoversFunction'); })->covers(TestCoversClass3::class, 'testCoversFunction'); +it('appends CoversNothing to method attributes', function () { + $phpDoc = (new ReflectionClass($this))->getMethod($this->getName()); + + expect(str_contains($phpDoc->getDocComment(), '* @coversNothing'))->toBeTrue(); +})->coversNothing(); + +it('does not append CoversNothing to other methods', function () { + $phpDoc = (new ReflectionClass($this))->getMethod($this->getName()); + + expect(str_contains($phpDoc->getDocComment(), '* @coversNothing'))->toBeFalse(); +}); + it('throws exception if no class nor method has been found', function () { $testCall = new TestCall(TestSuite::getInstance(), 'filename', 'description', fn () => 'closure'); From 3dc451cf44682df6f7ddcb53fbb6de0f6a921a6b Mon Sep 17 00:00:00 2001 From: danilopolani Date: Wed, 9 Mar 2022 11:08:11 +0100 Subject: [PATCH 19/20] fix typo --- src/Factories/TestCaseFactory.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Factories/TestCaseFactory.php b/src/Factories/TestCaseFactory.php index 7e250eed..a1ff1cd6 100644 --- a/src/Factories/TestCaseFactory.php +++ b/src/Factories/TestCaseFactory.php @@ -37,7 +37,7 @@ final class TestCaseFactory ]; /** - * The list of annotations. + * The list of attributes. * * @var array> */ From 09e2a26b7d117b3557601512856260f591ff673e Mon Sep 17 00:00:00 2001 From: danilopolani Date: Wed, 9 Mar 2022 11:09:03 +0100 Subject: [PATCH 20/20] fix linting --- src/Factories/TestCaseMethodFactory.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Factories/TestCaseMethodFactory.php b/src/Factories/TestCaseMethodFactory.php index 83c6678d..7830b693 100644 --- a/src/Factories/TestCaseMethodFactory.php +++ b/src/Factories/TestCaseMethodFactory.php @@ -113,7 +113,7 @@ final class TestCaseMethodFactory /** * Creates a PHPUnit method as a string ready for evaluation. * - * @param array $annotationsToUse + * @param array $annotationsToUse * @param array> $attributesToUse */ public function buildForEvaluation(string $classFQN, array $annotationsToUse, array $attributesToUse): string