Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
69 / 69
100.00% covered (success)
100.00%
2 / 2
CRAP
n/a
0 / 0
givenUserExists
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
registerBaseUserRepositoryTests
100.00% covered (success)
100.00%
66 / 66
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\User\Domain\Email;
11use AppDemo\User\Domain\User;
12use AppDemo\User\Domain\UserGroup;
13use Phexium\Domain\Id\TimestampId;
14use Phexium\Domain\Specification\AlwaysFalseSpecification;
15use Phexium\Domain\Specification\AlwaysTrueSpecification;
16use Tests\AppDemo\Fixture\UserMother;
17
18function givenUserExists(object $repository, int $id, string $email): void
19{
20    $repository->save(
21        UserMother::create(id: $id, email: $email)
22    );
23}
24
25function registerBaseUserRepositoryTests(): void
26{
27    test('saves and retrieves a user', function (): void {
28        $userId = 12345;
29        givenUserExists($this->repository, $userId, 'john.doe@example.com');
30
31        $foundUser = $this->repository->getById(new TimestampId($userId));
32
33        expect($foundUser)->not->toBeNull()
34            ->and($foundUser->getId()->getValue())->toBe($userId)
35        ;
36    });
37
38    test('getById throws exception for non-existing id', function (): void {
39        expect(fn () => $this->repository->getById(new TimestampId(99999)))->toThrow(InvalidArgumentException::class);
40    });
41
42    test('checks for user existence', function (): void {
43        givenUserExists($this->repository, 12345, 'john.doe@example.com');
44
45        expect($this->repository->exists(new TimestampId(12345)))->toBeTrue();
46        expect($this->repository->exists(new TimestampId(99999)))->toBeFalse();
47    });
48
49    test('findAll returns matching users', function (): void {
50        givenUserExists($this->repository, 1, 'john.doe@example.com');
51        givenUserExists($this->repository, 2, 'jane.doe@example.com');
52
53        expect($this->repository->findAll())->toHaveCount(2);
54    });
55
56    test('findBy returns matching users', function (): void {
57        givenUserExists($this->repository, 1, 'john.doe@example.com');
58        givenUserExists($this->repository, 2, 'jane.doe@example.com');
59
60        expect($this->repository->findBy(new AlwaysTrueSpecification()))->toHaveCount(2);
61        expect($this->repository->findBy(new AlwaysFalseSpecification()))->toHaveCount(0);
62    });
63
64    test('findById returns user or null', function (): void {
65        givenUserExists($this->repository, 12345, 'john.doe@example.com');
66
67        expect($this->repository->findById(new TimestampId(12345)))->toBeInstanceOf(User::class);
68        expect($this->repository->findById(new TimestampId(99999)))->toBeNull();
69    });
70
71    test('findOneBy returns first matching user or null', function (): void {
72        givenUserExists($this->repository, 12345, 'john.doe@example.com');
73
74        expect($this->repository->findOneBy(new AlwaysTrueSpecification()))->toBeInstanceOf(User::class);
75        expect($this->repository->findOneBy(new AlwaysFalseSpecification()))->toBeNull();
76    });
77
78    test('delete removes user and returns affected rows', function (): void {
79        givenUserExists($this->repository, 12345, 'john.doe@example.com');
80        $user = $this->repository->getById(new TimestampId(12345));
81
82        $affectedRows = $this->repository->delete($user);
83
84        expect($affectedRows)->toBe(1)
85            ->and($this->repository->exists(new TimestampId(12345)))->toBeFalse()
86        ;
87    });
88
89    test('deleteById removes user and returns affected rows', function (): void {
90        givenUserExists($this->repository, 12345, 'john.doe@example.com');
91
92        $affectedRows = $this->repository->deleteById(new TimestampId(12345));
93
94        expect($affectedRows)->toBe(1)
95            ->and($this->repository->exists(new TimestampId(12345)))->toBeFalse()
96        ;
97    });
98
99    test('findByEmail returns user by email', function (): void {
100        $email = 'john.doe@example.com';
101        givenUserExists($this->repository, 12345, $email);
102
103        $user = $this->repository->findByEmail(Email::fromString($email));
104
105        expect($user)->not->toBeNull()
106            ->and($user->getId()->getValue())->toBe(12345)
107            ->and($user->getEmail()->getValue())->toBe($email)
108            ->and($user->getGroup())->toBe(UserGroup::User)
109        ;
110    });
111
112    test('findByEmail returns null for non-existing email', function (): void {
113        $user = $this->repository->findByEmail(Email::fromString('not.found@example.com'));
114
115        expect($user)->toBeNull();
116    });
117}