Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
180 / 180
100.00% covered (success)
100.00%
1 / 1
CRAP
n/a
0 / 0
resetSession
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
2
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('integration');
11
12use Phexium\Plugin\Session\Adapter\NativeSession;
13use Phexium\Plugin\Session\Port\FlashInterface;
14use Tests\Phexium\Fake\Plugin\Session\SetCookieSpy;
15
16function resetSession(): void
17{
18    if (session_status() === PHP_SESSION_ACTIVE) {
19        session_destroy();
20    } else {
21        ini_set('session.use_cookies', '0');
22        ini_set('session.cache_limiter', '');
23    }
24
25    $_SESSION = [];
26
27    session_id(bin2hex(random_bytes(16)));
28}
29beforeEach(function (): void {
30    SetCookieSpy::reset();
31    resetSession();
32});
33
34afterEach(function (): void {
35    resetSession();
36});
37
38describe('Session lifecycle', function (): void {
39    it('does not restart an already started session when start is called multiple times', function (): void {
40        $session = new NativeSession();
41        $session->start();
42        $id1 = $session->getId();
43
44        $session->start();
45        $id2 = $session->getId();
46
47        expect($id1)->toBe($id2);
48    });
49
50    it('destroys session data and regenerates the session id', function (): void {
51        $session = new NativeSession();
52        $session->start();
53        $session->set('foo', 'bar');
54
55        $oldId = $session->getId();
56
57        $session->destroy();
58
59        $newId = $session->getId();
60
61        expect($oldId)->not->toBe($newId);
62        expect($session->has('foo'))->toBeFalse();
63        expect($session->count())->toBe(0);
64    });
65
66    it('clears the cookie when destroying a session with cookies enabled', function (): void {
67        ini_set('session.use_cookies', '1');
68
69        $session = new NativeSession();
70        $session->start();
71        $session->set('foo', 'bar');
72
73        $oldId = $session->getId();
74        $sessionName = session_name();
75
76        @$session->destroy();
77
78        $newId = $session->getId();
79
80        expect($oldId)->not->toBe($newId);
81        expect($session->has('foo'))->toBeFalse();
82        expect($session->count())->toBe(0);
83
84        $calls = SetCookieSpy::calls();
85        expect($calls)->toHaveCount(1);
86        expect($calls[0]['name'])->toBe($sessionName);
87        expect($calls[0]['value'])->toBe('');
88        expect($calls[0]['options']['expires'])->toBe(1);
89
90        $session->save();
91        ini_set('session.use_cookies', '0');
92    });
93
94    it('regenerates the session id', function (): void {
95        $session = new NativeSession();
96        $session->start();
97
98        $oldId = $session->getId();
99        $session->regenerateId();
100        $newId = $session->getId();
101
102        expect($oldId)->not->toBeEmpty();
103        expect($newId)->not->toBeEmpty();
104        expect($oldId)->not->toBe($newId);
105    });
106
107    it('returns the session id and name', function (): void {
108        $session = new NativeSession('myapp');
109        $session->start();
110
111        expect($session->getId())->not->toBeEmpty();
112        expect($session->getName())->toBe('myapp');
113    });
114
115    it('closes the session for writing when saved', function (): void {
116        $session = new NativeSession();
117        $session->start();
118        $session->set('foo', 'bar');
119
120        $session->save();
121
122        expect(session_status())->toBe(PHP_SESSION_NONE);
123    });
124
125    it('returns false for isStarted before start and true after', function (): void {
126        $session = new NativeSession();
127
128        expect($session->isStarted())->toBeFalse();
129
130        $session->start();
131
132        expect($session->isStarted())->toBeTrue();
133    });
134});
135
136describe('Data management', function (): void {
137    it('sets and gets a value from the session', function (): void {
138        $session = new NativeSession();
139        $session->start();
140
141        $session->set('foo', 'bar');
142
143        expect($session->get('foo'))->toBe('bar');
144    });
145
146    it('returns null when a key does not exist', function (): void {
147        $session = new NativeSession();
148        $session->start();
149
150        expect($session->get('non_existent_key'))->toBeNull();
151    });
152
153    it('returns the default value when a key does not exist', function (): void {
154        $session = new NativeSession();
155        $session->start();
156
157        expect($session->get('non_existent_key', 'default'))->toBe('default');
158    });
159
160    it('checks if a value exists in the session', function (): void {
161        $session = new NativeSession();
162        $session->start();
163
164        expect($session->has('foo'))->toBeFalse();
165
166        $session->set('foo', 'bar');
167
168        expect($session->has('foo'))->toBeTrue();
169    });
170
171    it('clears all session data', function (): void {
172        $session = new NativeSession();
173        $session->start();
174        $session->set('foo', 'bar');
175
176        $session->clear();
177
178        expect($session->has('foo'))->toBeFalse();
179    });
180
181    it('restarts the session after clearing data', function (): void {
182        $session = new NativeSession();
183        $session->start();
184        $session->set('foo', 'bar');
185
186        $session->clear();
187        $session->start();
188
189        expect($session->isStarted())->toBeTrue();
190        expect($session->all())->toBeEmpty();
191    });
192
193    it('deletes a value from the session', function (): void {
194        $session = new NativeSession();
195        $session->start();
196        $session->set('foo', 'bar');
197
198        expect($session->has('foo'))->toBeTrue();
199
200        $session->delete('foo');
201
202        expect($session->has('foo'))->toBeFalse();
203    });
204
205    it('adds flash messages and retrieves them via getFlash', function (): void {
206        $session = new NativeSession();
207        $session->start();
208
209        $session->addFlashMessage('success', 'Success message #1');
210        $session->addFlashMessage('error', 'Error message');
211        $session->addFlashMessage('success', 'Success message #2');
212
213        $flash = $session->getFlash();
214
215        expect($flash)->toBeInstanceOf(FlashInterface::class);
216
217        $successMessages = $flash->get('success');
218        expect($successMessages)->toHaveCount(2);
219        expect($successMessages)->toContain('Success message #1');
220        expect($successMessages)->toContain('Success message #2');
221
222        $errorMessages = $flash->get('error');
223        expect($errorMessages)->toHaveCount(1);
224        expect($errorMessages)->toContain('Error message');
225    });
226
227    it('replaces all session data', function (): void {
228        $session = new NativeSession();
229        $session->start();
230        $session->set('foo', 'bar');
231
232        $session->replace(['qix' => 'baz']);
233
234        expect($session->has('foo'))->toBeFalse();
235        expect($session->has('qix'))->toBeTrue();
236        expect($session->get('qix'))->toBe('baz');
237    });
238
239    it('returns all session data', function (): void {
240        $session = new NativeSession();
241        $session->start();
242
243        $session->set('key1', 'value1');
244        $session->set('key2', 'value2');
245
246        expect($session->all())->toBe([
247            'key1' => 'value1',
248            'key2' => 'value2',
249        ]);
250    });
251
252    it('counts session data keys', function (): void {
253        $session = new NativeSession();
254        $session->start();
255
256        expect($session->count())->toBe(0);
257
258        $session->set('key1', 'value1');
259        expect($session->count())->toBe(1);
260
261        $session->set('key2', 'value2');
262        $session->set('key3', 'value3');
263        expect($session->count())->toBe(3);
264
265        $session->delete('key2');
266        expect($session->count())->toBe(2);
267    });
268});