Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
52 / 52
n/a
0 / 0
CRAP
n/a
0 / 0
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
10pest()->group('unit');
11
12use AppDemo\User\Domain\Exception\InvalidPasswordException;
13use AppDemo\User\Domain\Password;
14use Tests\Phexium\Fake\Domain\StringValueObject as FakeValueObject;
15
16describe('Creation', function (): void {
17    it('creates a password using the static factory method', function (): void {
18        $password = Password::fromString('securePassword123');
19
20        expect($password->getValue())->toBe('securePassword123')
21            ->and($password->jsonSerialize())->toBe('securePassword123')
22            ->and((string) $password)->toBe('securePassword123')
23        ;
24    });
25
26    it('preserves whitespace without normalization', function (): void {
27        $password = Password::fromString('  securePassword123  ');
28
29        expect($password->getValue())->toBe('  securePassword123  ');
30    });
31});
32
33describe('Equality', function (): void {
34    it('considers two passwords with same value as equal', function (): void {
35        $password1 = Password::fromString('securePassword123');
36        $password2 = Password::fromString('securePassword123');
37
38        expect($password1->equals($password2))->toBeTrue();
39    });
40
41    it('considers two passwords with different values as not equal', function (): void {
42        $password1 = Password::fromString('securePassword123');
43        $password2 = Password::fromString('differentPassword456');
44
45        expect($password1->equals($password2))->toBeFalse();
46    });
47
48    it('considers a password and another value object as not equal', function (): void {
49        $password = Password::fromString('securePassword123');
50        $object = FakeValueObject::fromString('securePassword123');
51
52        expect($password->equals($object))->toBeFalse();
53    });
54});
55
56describe('Validation', function (): void {
57    it('throws exception for empty password', function (): void {
58        expect(fn (): Password => Password::fromString(''))
59            ->toThrow(InvalidPasswordException::class, 'Password cannot be empty')
60        ;
61    });
62
63    it('throws exception for password shorter than 8 characters', function (): void {
64        $min = Password::fromString(str_repeat('a', 8));
65        expect($min)->toBeInstanceOf(Password::class);
66
67        expect(fn (): Password => Password::fromString(str_repeat('a', 7)))
68            ->toThrow(InvalidPasswordException::class, 'Password must be at least 8 characters long')
69        ;
70    });
71
72    it('throws exception for password exceeding 255 characters', function (): void {
73        $max = Password::fromString(str_repeat('a', 255));
74        expect($max)->toBeInstanceOf(Password::class);
75
76        expect(fn (): Password => Password::fromString(str_repeat('a', 256)))
77            ->toThrow(InvalidPasswordException::class, 'Password cannot exceed 255 characters')
78        ;
79    });
80});