Skip to content

Commit b04d046

Browse files
committed
feat: add verbose specification
This decorator will throw an exception when the origin specification is dissatisfied.
1 parent cc0581d commit b04d046

File tree

3 files changed

+112
-0
lines changed

3 files changed

+112
-0
lines changed

src/SpecificationException.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Maartenpaauw\Specifications;
6+
7+
use Exception;
8+
9+
class SpecificationException extends Exception
10+
{
11+
}

src/VerboseSpecification.php

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Maartenpaauw\Specifications;
6+
7+
/**
8+
* @template TCandidate
9+
* @extends CompositeSpecification<TCandidate>
10+
*/
11+
class VerboseSpecification extends CompositeSpecification
12+
{
13+
public function __construct(
14+
private Specification $origin,
15+
private string $message = '',
16+
) {
17+
}
18+
19+
/**
20+
* @return VerboseSpecification<TCandidate>
21+
*/
22+
public function withMessage(string $message): self
23+
{
24+
return new self(
25+
$this->origin,
26+
$message,
27+
);
28+
}
29+
30+
/**
31+
* @param TCandidate $candidate
32+
*
33+
* @throws SpecificationException
34+
*/
35+
public function isSatisfiedBy(mixed $candidate): bool
36+
{
37+
if ($this->origin->isSatisfiedBy($candidate)) {
38+
return true;
39+
}
40+
41+
throw new SpecificationException($this->message);
42+
}
43+
}

tests/VerboseExceptionTest.php

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Maartenpaauw\Specifications\Tests;
6+
7+
use Maartenpaauw\Specifications\SpecificationException;
8+
use Maartenpaauw\Specifications\Tests\Dummy\LengthSpecification;
9+
use Maartenpaauw\Specifications\VerboseSpecification;
10+
11+
class VerboseExceptionTest extends TestCase
12+
{
13+
/** @var VerboseSpecification<string> */
14+
private VerboseSpecification $specification;
15+
16+
protected function setUp(): void
17+
{
18+
parent::setUp();
19+
20+
$this->specification = new VerboseSpecification(
21+
new LengthSpecification(12),
22+
);
23+
}
24+
25+
/** @test */
26+
public function it_should_throw_an_exception_with_an_empty_message_when_the_specification_is_not_satisfied(): void
27+
{
28+
// Assert
29+
$this->expectException(SpecificationException::class);
30+
$this->expectExceptionMessage('');
31+
32+
// Act
33+
$this->specification->isSatisfiedBy('Hello Laravel!');
34+
}
35+
36+
/** @test */
37+
public function it_should_be_possible_to_customize_the_exception_message(): void
38+
{
39+
// Assert
40+
$this->expectException(SpecificationException::class);
41+
$this->expectExceptionMessage('The given string is longer than 12 characters!');
42+
43+
// Act
44+
$this->specification
45+
->withMessage('The given string is longer than 12 characters!')
46+
->isSatisfiedBy('Hello Laravel!');
47+
}
48+
49+
/** @test */
50+
public function it_should_return_true_when_the_specification_is_satisfied_with_the_given_candidate(): void
51+
{
52+
// Act
53+
$satisfied = $this->specification->isSatisfiedBy('Hello world!');
54+
55+
// Assert
56+
$this->assertTrue($satisfied);
57+
}
58+
}

0 commit comments

Comments
 (0)