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'));