Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
99 / 99
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 Phexium\Plugin\Authorization\Adapter\RbacAuthorizationService;
13use Phexium\Plugin\Authorization\Adapter\StringSubject;
14
15beforeEach(function (): void {
16    $permissionsConfig = [
17        'admin' => [
18            'can.sing',
19            'can.dance',
20            'can.dance', // Duplicated permission to test that get(All)Permissions returns unique values
21            'can.fly',
22        ],
23        'user' => [
24            'can.sing',
25            '', // Empty permission to test that can() returns false for empty strings
26        ],
27        'guest' => [],
28    ];
29
30    $this->service = new RbacAuthorizationService($permissionsConfig);
31
32    $this->adminSubject = StringSubject::fromString('admin');
33    $this->userSubject = StringSubject::fromString('user');
34    $this->guestSubject = StringSubject::fromString('guest');
35    $this->unknownSubject = StringSubject::fromString('unknown');
36});
37
38describe('Single permission', function (): void {
39    it('returns true when subject has the required permission', function (): void {
40        $can = $this->service->can($this->adminSubject, 'can.dance');
41
42        expect($can)->toBeTrue();
43    });
44
45    it('returns false when subject does not have the required permission', function (): void {
46        $can = $this->service->can($this->userSubject, 'can.dance');
47
48        expect($can)->toBeFalse();
49    });
50
51    it('returns false when checking empty permission string', function (): void {
52        $can = $this->service->can($this->adminSubject, '');
53
54        expect($can)->toBeFalse();
55    });
56
57    it('returns false for empty permission even if empty string exists in subject permissions', function (): void {
58        $can = $this->service->can($this->userSubject, '');
59
60        expect($can)->toBeFalse();
61    });
62
63    it('returns false when subject identifier is not in configuration', function (): void {
64        $can = $this->service->can($this->unknownSubject, 'can.fly');
65
66        expect($can)->toBeFalse();
67    });
68
69    it('checks permission case-sensitively', function (): void {
70        $can = $this->service->can($this->adminSubject, 'CAN.FLY');
71
72        expect($can)->toBeFalse();
73    });
74});
75
76describe('Multiple permissions', function (): void {
77    it('returns true when subject has at least one of the required permissions', function (): void {
78        $result = $this->service->canAny($this->userSubject, ['can.dance', 'can.sing']);
79
80        expect($result)->toBeTrue();
81    });
82
83    it('returns false when subject has none of the required permissions', function (): void {
84        $result = $this->service->canAny($this->userSubject, ['can.dance', 'can.fly']);
85
86        expect($result)->toBeFalse();
87    });
88
89    it('returns false when checking empty permissions array with canAny', function (): void {
90        $result = $this->service->canAny($this->adminSubject, []);
91
92        expect($result)->toBeFalse();
93    });
94
95    it('returns true when subject has all required permissions', function (): void {
96        $result = $this->service->canAll($this->adminSubject, ['can.dance', 'can.sing', 'can.fly']);
97
98        expect($result)->toBeTrue();
99    });
100
101    it('returns false when subject is missing at least one required permission', function (): void {
102        $result = $this->service->canAll($this->userSubject, ['can.dance', 'can.sing']);
103
104        expect($result)->toBeFalse();
105    });
106
107    it('returns true when checking empty permissions array with canAll', function (): void {
108        $result = $this->service->canAll($this->adminSubject, []);
109
110        expect($result)->toBeTrue();
111    });
112});
113
114describe('Permission retrieval', function (): void {
115    it('returns all permissions for a given subject', function (): void {
116        $permissions = $this->service->getPermissions($this->adminSubject);
117
118        expect($permissions)->toBe(['can.sing', 'can.dance', 'can.fly']);
119    });
120
121    it('returns empty array for subject with no permissions', function (): void {
122        $permissions = $this->service->getPermissions($this->guestSubject);
123
124        expect($permissions)->toBeEmpty();
125    });
126
127    it('returns empty array for unknown subject', function (): void {
128        $unknownSubject = StringSubject::fromString('unknown');
129
130        $permissions = $this->service->getPermissions($unknownSubject);
131
132        expect($permissions)->toBeEmpty();
133    });
134
135    it('returns all unique permissions across all subjects', function (): void {
136        $allPermissions = $this->service->getAllPermissions();
137
138        expect($allPermissions)->toBe(['can.sing', 'can.dance', 'can.fly', '']);
139    });
140
141    it('returns all subject identifiers from configuration', function (): void {
142        $subjects = $this->service->getAllSubjects();
143
144        expect($subjects)->toHaveCount(3);
145        expect($subjects)->toContain('admin');
146        expect($subjects)->toContain('user');
147        expect($subjects)->toContain('guest');
148    });
149});