Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
45 / 45
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
10use Phexium\Plugin\PasswordHasher\Adapter\Argon2iPasswordHasher;
11
12beforeEach(function (): void {
13    $this->hasher = new Argon2iPasswordHasher(memoryCost: 1024, timeCost: 1, threads: 1);
14});
15
16test('Can hash a plain password using Argon2i', function (): void {
17    $plainPassword = 'SecurePassword123';
18
19    $hash = $this->hasher->hash($plainPassword);
20
21    expect($hash)->toBeString();
22    expect($hash)->not->toBe($plainPassword);
23    expect($hash)->toStartWith('$argon2i$');
24});
25
26test('Verify returns true for correct password', function (): void {
27    $plainPassword = 'SecurePassword123';
28    $hash = $this->hasher->hash($plainPassword);
29
30    expect($this->hasher->verify($plainPassword, $hash))->toBeTrue();
31});
32
33test('Verify returns false for incorrect password', function (): void {
34    $wrongPassword = 'WrongPassword456';
35    $plainPassword = 'SecurePassword123';
36    $hash = $this->hasher->hash($plainPassword);
37
38    expect($this->hasher->verify($wrongPassword, $hash))->toBeFalse();
39});
40
41test('Verify is case sensitive', function (): void {
42    $wrongPassword = 'securepassword123';
43    $plainPassword = 'SecurePassword123';
44    $hash = $this->hasher->hash($plainPassword);
45
46    expect($this->hasher->verify($wrongPassword, $hash))->toBeFalse();
47});
48
49test('Hash is non deterministic - same password produces different hash', function (): void {
50    $plainPassword = 'SecurePassword123';
51
52    $hash1 = $this->hasher->hash($plainPassword);
53    $hash2 = $this->hasher->hash($plainPassword);
54
55    expect($hash1)->not->toBe($hash2);
56    expect($this->hasher->verify($plainPassword, $hash1))->toBeTrue();
57    expect($this->hasher->verify($plainPassword, $hash2))->toBeTrue();
58});
59
60test('Default options are used when not specified', function (): void {
61    $hasher = new Argon2iPasswordHasher();
62    $hash = $hasher->hash('test');
63
64    expect($hash)->toStartWith('$argon2i$v=19$m=65536,t=4,p=1$');
65});
66
67test('Custom options are applied', function (): void {
68    $hasher = new Argon2iPasswordHasher(memoryCost: 2048, timeCost: 2, threads: 1);
69    $hash = $hasher->hash('test');
70
71    expect($hash)->toStartWith('$argon2i$v=19$m=2048,t=2,p=1$');
72});