Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
55 / 55
100.00% covered (success)
100.00%
2 / 2
CRAP
n/a
0 / 0
givenBookExists
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
registerBaseBookRepositoryTests
100.00% covered (success)
100.00%
52 / 52
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2
3// ╔════════════════════════════════════════════════════════════╗
4// ║ MIT Licence (#Expat) - https://opensource.org/licenses/MIT ║
5// ║ Copyright 2026 Frederic Poeydomenge <dyno@phexium.com>     ║
6// ╚════════════════════════════════════════════════════════════╝
7
8declare(strict_types=1);
9
10use AppDemo\Library\Domain\Book;
11use Phexium\Domain\Id\TimestampId;
12use Phexium\Domain\Specification\AlwaysFalseSpecification;
13use Phexium\Domain\Specification\AlwaysTrueSpecification;
14use Tests\AppDemo\Fixture\BookMother;
15
16function givenBookExists(object $repository, int $id, string $isbn): void
17{
18    $repository->save(
19        BookMother::create(id: $id, title: 'Title#'.$id, author: 'Author#'.$id, isbn: $isbn)
20    );
21}
22
23function registerBaseBookRepositoryTests(): void
24{
25    test('saves and retrieves a book', closure: function (): void {
26        $bookId = 12345;
27        givenBookExists($this->repository, $bookId, '9780134494166');
28
29        $foundBook = $this->repository->getById(new TimestampId($bookId));
30
31        expect($foundBook)->not->toBeNull()
32            ->and($foundBook->getId()->getValue())->toBe($bookId)
33        ;
34    });
35
36    test('getById throws exception for non-existing id', function (): void {
37        expect(fn () => $this->repository->getById(new TimestampId(99999)))->toThrow(InvalidArgumentException::class);
38    });
39
40    test('checks for book existence', function (): void {
41        givenBookExists($this->repository, 12345, '9780134494166');
42
43        expect($this->repository->exists(new TimestampId(12345)))->toBeTrue();
44        expect($this->repository->exists(new TimestampId(99999)))->toBeFalse();
45    });
46
47    test('findAll returns all books', function (): void {
48        givenBookExists($this->repository, 1, '9780134494166');
49        givenBookExists($this->repository, 2, '9780201633610');
50
51        expect($this->repository->findAll())->toHaveCount(2);
52    });
53
54    test('findBy returns matching books', function (): void {
55        givenBookExists($this->repository, 1, '9780134494166');
56        givenBookExists($this->repository, 2, '9780201633610');
57
58        expect($this->repository->findBy(new AlwaysTrueSpecification()))->toHaveCount(2);
59        expect($this->repository->findBy(new AlwaysFalseSpecification()))->toHaveCount(0);
60    });
61
62    test('findById returns book or null', function (): void {
63        givenBookExists($this->repository, 12345, '9780134494166');
64
65        expect($this->repository->findById(new TimestampId(12345)))->toBeInstanceOf(Book::class);
66        expect($this->repository->findById(new TimestampId(99999)))->toBeNull();
67    });
68
69    test('findOneBy returns first matching book or null', function (): void {
70        givenBookExists($this->repository, 12345, '9780134494166');
71
72        expect($this->repository->findOneBy(new AlwaysTrueSpecification()))->toBeInstanceOf(Book::class);
73        expect($this->repository->findOneBy(new AlwaysFalseSpecification()))->toBeNull();
74    });
75
76    test('delete removes book and returns affected rows', function (): void {
77        givenBookExists($this->repository, 12345, '9780134494166');
78        $book = $this->repository->getById(new TimestampId(12345));
79
80        $affectedRows = $this->repository->delete($book);
81
82        expect($affectedRows)->toBe(1)
83            ->and($this->repository->exists(new TimestampId(12345)))->toBeFalse()
84        ;
85    });
86
87    test('deleteById removes book and returns affected rows', function (): void {
88        givenBookExists($this->repository, 12345, '9780134494166');
89
90        $affectedRows = $this->repository->deleteById(new TimestampId(12345));
91
92        expect($affectedRows)->toBe(1)
93            ->and($this->repository->exists(new TimestampId(12345)))->toBeFalse()
94        ;
95    });
96}