From 8a6d3ed3d3315eaae67d6a327c4918b04638f104 Mon Sep 17 00:00:00 2001 From: Maarten Paauw Date: Sat, 24 Aug 2024 12:14:42 +0200 Subject: [PATCH] feat: add constructor property assertions --- composer.json | 3 ++- src/AndSpecification.php | 5 ++++- src/OrSpecification.php | 5 ++++- src/XorSpecification.php | 5 ++++- tests/AndSpecificationTest.php | 9 +++++++++ tests/OrSpecificationTest.php | 9 +++++++++ tests/XorSpecificationTest.php | 9 +++++++++ 7 files changed, 41 insertions(+), 4 deletions(-) diff --git a/composer.json b/composer.json index f2d4f0b..015ff0c 100644 --- a/composer.json +++ b/composer.json @@ -20,7 +20,8 @@ "illuminate/console": "^10.0|^11.0", "illuminate/support": "^10.0|^11.0", "spatie/laravel-package-tools": "^1.16.2", - "symfony/polyfill-php83": "^1.30" + "symfony/polyfill-php83": "^1.30", + "webmozart/assert": "^1.11" }, "require-dev": { "illuminate/testing": "^10.0|^11.0", diff --git a/src/AndSpecification.php b/src/AndSpecification.php index e37068d..842c60d 100644 --- a/src/AndSpecification.php +++ b/src/AndSpecification.php @@ -5,6 +5,7 @@ namespace Maartenpaauw\Specifications; use Override; +use Webmozart\Assert\Assert; /** * @template TCandidate @@ -18,7 +19,9 @@ final class AndSpecification extends CompositeSpecification */ public function __construct( private readonly array $specifications, - ) {} + ) { + Assert::allIsInstanceOf($specifications, Specification::class); + } #[Override] public function isSatisfiedBy(mixed $candidate): bool diff --git a/src/OrSpecification.php b/src/OrSpecification.php index aa4d2f1..ab8c8d5 100644 --- a/src/OrSpecification.php +++ b/src/OrSpecification.php @@ -5,6 +5,7 @@ namespace Maartenpaauw\Specifications; use Override; +use Webmozart\Assert\Assert; /** * @template TCandidate @@ -18,7 +19,9 @@ final class OrSpecification extends CompositeSpecification */ public function __construct( private readonly array $specifications, - ) {} + ) { + Assert::allIsInstanceOf($this->specifications, Specification::class); + } #[Override] public function isSatisfiedBy(mixed $candidate): bool diff --git a/src/XorSpecification.php b/src/XorSpecification.php index 596da9f..a4ce277 100644 --- a/src/XorSpecification.php +++ b/src/XorSpecification.php @@ -5,6 +5,7 @@ namespace Maartenpaauw\Specifications; use Override; +use Webmozart\Assert\Assert; /** * @template TCandidate @@ -18,7 +19,9 @@ final class XorSpecification extends CompositeSpecification */ public function __construct( private readonly array $specifications, - ) {} + ) { + Assert::allIsInstanceOf($specifications, Specification::class); + } #[Override] public function isSatisfiedBy(mixed $candidate): bool diff --git a/tests/AndSpecificationTest.php b/tests/AndSpecificationTest.php index 4e2383f..8ba9a33 100644 --- a/tests/AndSpecificationTest.php +++ b/tests/AndSpecificationTest.php @@ -4,6 +4,7 @@ namespace Maartenpaauw\Specifications\Tests; +use InvalidArgumentException; use Maartenpaauw\Specifications\AndSpecification; use Workbench\App\LengthSpecification; use Workbench\App\UppercaseSpecification; @@ -30,6 +31,14 @@ protected function setUp(): void ]); } + public function test_it_should_throw_an_invalid_argument_exception_when_the_specification_array_does_contain_invalid_data(): void + { + self::expectException(InvalidArgumentException::class); + + // @phpstan-ignore-next-line + new AndSpecification(['invalid']); + } + public function test_it_should_return_true_when_the_candidate_matches_all_specifications(): void { // Act diff --git a/tests/OrSpecificationTest.php b/tests/OrSpecificationTest.php index 5269296..a3b1af1 100644 --- a/tests/OrSpecificationTest.php +++ b/tests/OrSpecificationTest.php @@ -4,6 +4,7 @@ namespace Maartenpaauw\Specifications\Tests; +use InvalidArgumentException; use Maartenpaauw\Specifications\OrSpecification; use Workbench\App\LengthSpecification; use Workbench\App\UppercaseSpecification; @@ -30,6 +31,14 @@ protected function setUp(): void ]); } + public function test_it_should_throw_an_invalid_argument_exception_when_the_specification_array_does_contain_invalid_data(): void + { + self::expectException(InvalidArgumentException::class); + + // @phpstan-ignore-next-line + new OrSpecification(['invalid']); + } + public function test_it_should_return_true_when_the_candidate_matches_all_specifications(): void { // Act diff --git a/tests/XorSpecificationTest.php b/tests/XorSpecificationTest.php index 96fef84..c15e31f 100644 --- a/tests/XorSpecificationTest.php +++ b/tests/XorSpecificationTest.php @@ -4,6 +4,7 @@ namespace Maartenpaauw\Specifications\Tests; +use InvalidArgumentException; use Maartenpaauw\Specifications\XorSpecification; use PHPUnit\Framework\TestCase; use Workbench\App\LengthSpecification; @@ -31,6 +32,14 @@ protected function setUp(): void ]); } + public function test_it_should_throw_an_invalid_argument_exception_when_the_specification_array_does_contain_invalid_data(): void + { + self::expectException(InvalidArgumentException::class); + + // @phpstan-ignore-next-line + new XorSpecification(['invalid']); + } + public function test_it_should_only_return_true_when_one_specification_is_satisfied(): void { $this->assertTrue($this->specification->isSatisfiedBy('HELLO'));