Failed Conditions
Push — master ( 4252f4...9d8e13 )
by Adrien
07:13
created

UserTest::testToken()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 45
Code Lines 32

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 32
nc 1
nop 0
dl 0
loc 45
rs 9.408
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace ApplicationTest\Model;
6
7
use Application\Model\Booking;
8
use Application\Model\User;
9
use Cake\Chronos\Chronos;
10
use PHPUnit\Framework\TestCase;
11
12
class UserTest extends TestCase
13
{
14
    public function tearDown(): void
15
    {
16
        User::setCurrent(null);
17
    }
18
19
    public function testGetGlobalPermissions(): void
20
    {
21
        $user = new User();
22
        $actual = $user->getGlobalPermissions();
23
        $expected = [
24
            'account' => [
25
                'create' => true,
26
            ],
27
            'accountingDocument' => [
28
                'create' => true,
29
            ],
30
            'bookable' => [
31
                'create' => false,
32
            ],
33
            'bookableMetadata' => [
34
                'create' => false,
35
            ],
36
            'bookableTag' => [
37
                'create' => false,
38
            ],
39
            'booking' => [
40
                'create' => true,
41
            ],
42
            'category' => [
43
                'create' => false,
44
            ],
45
            'country' => [
46
                'create' => false,
47
            ],
48
            'expenseClaim' => [
49
                'create' => true,
50
            ],
51
            'image' => [
52
                'create' => false,
53
            ],
54
            'license' => [
55
                'create' => false,
56
            ],
57
            'message' => [
58
                'create' => false,
59
            ],
60
            'user' => [
61
                'create' => true,
62
            ],
63
            'userTag' => [
64
                'create' => false,
65
            ],
66
67
        ];
68
        self::assertEquals($expected, $actual);
69
70
        $expectedForAdmin = [
71
            'account' => [
72
                'create' => true,
73
            ],
74
            'accountingDocument' => [
75
                'create' => true,
76
            ],
77
            'bookable' => [
78
                'create' => true,
79
            ],
80
            'bookableMetadata' => [
81
                'create' => true,
82
            ],
83
            'bookableTag' => [
84
                'create' => true,
85
            ],
86
            'booking' => [
87
                'create' => true,
88
            ],
89
            'category' => [
90
                'create' => true,
91
            ],
92
            'country' => [
93
                'create' => false,
94
            ],
95
            'expenseClaim' => [
96
                'create' => true,
97
            ],
98
            'image' => [
99
                'create' => true,
100
            ],
101
            'license' => [
102
                'create' => true,
103
            ],
104
            'message' => [
105
                'create' => false,
106
            ],
107
            'user' => [
108
                'create' => true,
109
            ],
110
            'userTag' => [
111
                'create' => true,
112
            ],
113
114
        ];
115
116
        User::setCurrent($user);
117
        self::assertSame($user, User::getCurrent());
118
119
        $admin = new User(User::ROLE_ADMINISTRATOR);
120
        $actualForAdmin = $admin->getGlobalPermissions();
121
122
        self::assertEquals($expectedForAdmin, $actualForAdmin);
123
        self::assertSame($user, User::getCurrent());
124
        self::assertNotEquals($expectedForAdmin, $expected);
125
    }
126
127
    /**
128
     * @dataProvider providerSetRole
129
     *
130
     * @param string $currentRole
131
     * @param string $oldRole
132
     * @param string $newRole
133
     * @param null|string $exception
134
     */
135
    public function testSetRole(string $currentRole, string $oldRole, string $newRole, ?string $exception): void
136
    {
137
        if ($currentRole !== User::ROLE_ANONYMOUS) {
138
            $currentUser = new User($currentRole);
139
            User::setCurrent($currentUser);
140
        }
141
142
        $user2 = new User($oldRole);
143
144
        if ($exception) {
145
            $this->expectExceptionMessage($exception);
146
        }
147
148
        $user2->setRole($newRole);
149
        self::assertSame($newRole, $user2->getRole());
150
    }
151
152
    public function providerSetRole(): array
153
    {
154
        return [
155
            [User::ROLE_ANONYMOUS, User::ROLE_ADMINISTRATOR, User::ROLE_MEMBER, 'anonymous is not allowed to change role to member'],
156
            [User::ROLE_ANONYMOUS, User::ROLE_MEMBER, User::ROLE_ADMINISTRATOR, 'anonymous is not allowed to change role to administrator'],
157
158
            [User::ROLE_MEMBER, User::ROLE_MEMBER, User::ROLE_MEMBER, null],
159
            [User::ROLE_MEMBER, User::ROLE_MEMBER, User::ROLE_ADMINISTRATOR, 'member is not allowed to change role to administrator'],
160
161
            [User::ROLE_ADMINISTRATOR, User::ROLE_MEMBER, User::ROLE_ADMINISTRATOR, null],
162
            [User::ROLE_ADMINISTRATOR, User::ROLE_ADMINISTRATOR, User::ROLE_MEMBER, null],
163
        ];
164
    }
165
166
    public function testSetPassword(): void
167
    {
168
        $user = new User();
169
        self::assertNull($user->getPassword(), 'should have no password at first');
170
171
        $user->setPassword('12345');
172
        $actual1 = $user->getPassword();
173
        self::assertNotSame('', $actual1, 'should be able to change password ');
174
        self::assertTrue(password_verify('12345', $actual1), 'password must have been hashed');
175
176
        $user->setPassword('money');
177
        $actual2 = $user->getPassword();
178
        self::assertNotSame($actual1, $actual2, 'should be able to change to something else');
179
        self::assertTrue(password_verify('money', $actual2), 'password must have been hashed again');
180
    }
181
182
    /**
183
     * @dataProvider providerSetOwner
184
     */
185
    public function testSetOwner(?User $currentUser, ?User $originalOwner, ?User $newOwner, ?string $exception = null): void
186
    {
187
        User::setCurrent($currentUser);
188
189
        $subject = new Booking();
190
        self::assertNull($subject->getOwner());
191
192
        $subject->setOwner($originalOwner);
193
        self::assertSame($originalOwner, $subject->getOwner());
194
195
        if ($exception) {
196
            $this->expectExceptionMessage($exception);
197
        }
198
199
        $subject->setOwner($newOwner);
200
        self::assertSame($newOwner, $subject->getOwner());
201
    }
202
203
    public function providerSetOwner(): array
204
    {
205
        $u1 = new User();
206
        $u1->setLogin('u1');
207
        $u2 = new User();
208
        $u2->setLogin('u2');
209
        $u3 = new User();
210
        $u3->setLogin('u3');
211
        $admin = new User(User::ROLE_ADMINISTRATOR);
212
        $admin->setLogin('admin');
213
214
        return [
215
            'can change nothing' => [null, null, null],
216
            'can set owner for first time' => [null, null, $u3],
217
            'can set owner for first time to myself' => [$u1, null, $u1],
218
            'can set owner for first time even if it is not myself' => [$u1, null, $u3],
219
            'can donate my stuff' => [$u1, $u1, $u3],
220
            'cannot donate stuff that are not mine' => [$u1, $u2, $u3, 'u1 is not allowed to change owner to u3 because it belongs to u2'],
221
            'admin cannot donate stuff that are not mine' => [$admin, $u2, $u3],
222
        ];
223
    }
224
225
    public function testIndividualCannotOwnUsers(): void
226
    {
227
        $u1 = new User();
228
        $u2 = new User();
229
        $u3 = new User();
230
231
        $u1->setOwner($u1);
232
        $u2->setOwner($u1);
233
234
        $this->expectExceptionMessage('This user cannot be owned by a user who is himself owned by somebody else');
235
        $u3->setOwner($u2);
236
    }
237
238
    public function testIndividualCannotOwnUsers2(): void
239
    {
240
        $u1 = new User();
241
        $u2 = new User();
242
        $u3 = new User();
243
244
        $u1->setOwner($u1);
245
        $u3->setOwner($u2);
246
247
        $this->expectExceptionMessage('This user owns other users, so he cannot himself be owned by somebody else');
248
        $u2->setOwner($u1);
249
    }
250
251
    public function testSetStatus(): void
252
    {
253
        $u1 = new User();
254
        $u2 = new User();
255
256
        // Initial status
257
        self::assertSame(User::STATUS_NEW, $u1->getStatus());
258
        self::assertSame(User::STATUS_NEW, $u2->getStatus());
259
260
        $u1->setOwner($u1);
261
        $u2->setOwner($u1);
262
        $u1->setStatus(User::STATUS_INACTIVE);
263
264
        // Status is propagated to existing users
265
        self::assertSame(User::STATUS_INACTIVE, $u1->getStatus());
266
        self::assertSame(User::STATUS_INACTIVE, $u2->getStatus());
267
268
        $u1->setStatus(user::STATUS_ACTIVE);
269
        self::assertSame(User::STATUS_ACTIVE, $u1->getStatus());
270
        self::assertSame(User::STATUS_ACTIVE, $u2->getStatus());
271
272
        // Status is propagated on new users too
273
        $u3 = new User();
274
        self::assertSame(User::STATUS_NEW, $u3->getStatus());
275
        $u3->setOwner($u1);
276
        self::assertSame(User::STATUS_ACTIVE, $u3->getStatus());
277
    }
278
279
    public function testToken(): void
280
    {
281
        $user = new User();
282
        self::assertFalse($user->isTokenValid(), 'new user should not be valid');
283
284
        $token1 = $user->createToken();
285
        self::assertEquals(32, mb_strlen($token1), 'must be exactly the length of DB field');
286
        self::assertTrue($user->isTokenValid(), 'brand new token is valid');
287
288
        $token2 = $user->createToken();
289
        self::assertEquals(32, mb_strlen($token2), 'must be exactly the length of DB field');
290
        self::assertTrue($user->isTokenValid(), 'second created token is valid');
291
292
        $user->setLastLogin(new Chronos());
293
        self::assertFalse($user->isTokenValid(), 'once user is logged in token is invalid');
294
295
        $token3 = $user->createToken();
296
        self::assertEquals(32, mb_strlen($token3), 'must be exactly the length of DB field');
297
        self::assertTrue($user->isTokenValid(), 'third created token is valid');
298
299
        $user->setStatus(User::STATUS_ACTIVE);
300
        self::assertFalse($user->isTokenValid(), 'once user is activated token is invalid');
301
302
        $token4 = $user->createToken();
303
        self::assertEquals(32, mb_strlen($token4), 'must be exactly the length of DB field');
304
        self::assertTrue($user->isTokenValid(), 'third created token is valid');
305
306
        $user->setPassword('money');
307
        self::assertFalse($user->isTokenValid(), 'after password change token is invalid');
308
309
        Chronos::setTestNow((new Chronos())->subDay(1));
310
        $token5 = $user->createToken();
311
        Chronos::setTestNow(null);
312
        self::assertEquals(32, mb_strlen($token5), 'must be exactly the length of DB field');
313
        self::assertFalse($user->isTokenValid(), 'too old token is invalid');
314
315
        $allTokens = [
316
            $token1,
317
            $token2,
318
            $token3,
319
            $token4,
320
            $token5,
321
        ];
322
323
        self::assertCount(5, array_unique($allTokens), 'all tokens must be unique');
324
    }
325
}
326