Passed
Push — master ( 337c4b...c11f33 )
by
unknown
06:59
created

UserTest::providerCanOpenDoor()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 32
Code Lines 25

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 25
nc 1
nop 0
dl 0
loc 32
rs 9.52
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
    /**
20
     * @dataProvider providerSetRole
21
     *
22
     * @param string $currentRole
23
     * @param string $oldRole
24
     * @param string $newRole
25
     * @param null|string $exception
26
     */
27
    public function testSetRole(string $currentRole, string $oldRole, string $newRole, ?string $exception): void
28
    {
29
        User::setCurrent(null);
30
        if ($currentRole !== User::ROLE_ANONYMOUS) {
31
            $currentUser = new User($currentRole);
32
            User::setCurrent($currentUser);
33
        }
34
35
        $user2 = new User($oldRole);
36
37
        if ($exception) {
38
            $this->expectExceptionMessage($exception);
39
        }
40
41
        $user2->setRole($newRole);
42
        self::assertSame($newRole, $user2->getRole());
43
    }
44
45
    public function providerSetRole(): array
46
    {
47
        return [
48
            [User::ROLE_ANONYMOUS, User::ROLE_ADMINISTRATOR, User::ROLE_MEMBER, 'anonymous is not allowed to change role from administrator to member'],
49
            [User::ROLE_ANONYMOUS, User::ROLE_MEMBER, User::ROLE_ADMINISTRATOR, 'anonymous is not allowed to change role from member to administrator'],
50
51
            [User::ROLE_MEMBER, User::ROLE_MEMBER, User::ROLE_MEMBER, null],
52
            [User::ROLE_MEMBER, User::ROLE_MEMBER, User::ROLE_ADMINISTRATOR, 'member is not allowed to change role from member to administrator'],
53
54
            [User::ROLE_ADMINISTRATOR, User::ROLE_MEMBER, User::ROLE_ADMINISTRATOR, null],
55
            [User::ROLE_ADMINISTRATOR, User::ROLE_ADMINISTRATOR, User::ROLE_MEMBER, null],
56
        ];
57
    }
58
59
    public function testSetPassword(): void
60
    {
61
        $user = new User();
62
        self::assertSame('', $user->getPassword(), 'should have no password at first');
63
64
        $user->setPassword('12345');
65
        $actual1 = $user->getPassword();
66
        self::assertNotSame('', $actual1, 'should be able to change password ');
67
        self::assertTrue(password_verify('12345', $actual1), 'password must have been hashed');
68
69
        $user->setPassword('');
70
        $actual2 = $user->getPassword();
71
        self::assertSame($actual1, $actual2, 'should ignore empty password');
72
73
        $user->setPassword('money');
74
        $actual3 = $user->getPassword();
75
        self::assertNotSame($actual1, $actual3, 'should be able to change to something else');
76
        self::assertTrue(password_verify('money', $actual3), 'password must have been hashed again');
77
    }
78
79
    /**
80
     * @dataProvider providerSetOwner
81
     */
82
    public function testSetOwner(?User $currentUser, ?User $originalOwner, ?User $newOwner, ?string $exception = null): void
83
    {
84
        User::setCurrent($currentUser);
85
86
        $subject = new Booking();
87
        self::assertNull($subject->getOwner());
88
89
        $subject->setOwner($originalOwner);
90
        self::assertSame($originalOwner, $subject->getOwner());
91
92
        if ($exception) {
93
            $this->expectExceptionMessage($exception);
94
        }
95
96
        $subject->setOwner($newOwner);
97
        self::assertSame($newOwner, $subject->getOwner());
98
    }
99
100
    public function providerSetOwner(): array
101
    {
102
        $u1 = new User();
103
        $u1->setLogin('u1');
104
        $u2 = new User();
105
        $u2->setLogin('u2');
106
        $u3 = new User();
107
        $u3->setLogin('u3');
108
        $admin = new User(User::ROLE_ADMINISTRATOR);
109
        $admin->setLogin('admin');
110
111
        return [
112
            'can change nothing' => [null, null, null],
113
            'can set owner for first time' => [null, null, $u3],
114
            'can set owner for first time to myself' => [$u1, null, $u1],
115
            'can set owner for first time even if it is not myself' => [$u1, null, $u3],
116
            'can donate my stuff' => [$u1, $u1, $u3],
117
            'cannot donate stuff that are not mine' => [$u1, $u2, $u3, 'u1 is not allowed to change owner to u3 because it belongs to u2'],
118
            'admin cannot donate stuff that are not mine' => [$admin, $u2, $u3],
119
        ];
120
    }
121
122
    public function testIndividualCannotOwnUsers(): void
123
    {
124
        $u1 = new User();
125
        $u2 = new User();
126
        $u3 = new User();
127
128
        $u1->setOwner($u1);
129
        $u2->setOwner($u1);
130
131
        $this->expectExceptionMessage('This user cannot be owned by a user who is himself owned by somebody else');
132
        $u3->setOwner($u2);
133
    }
134
135
    public function testIndividualCannotOwnUsers2(): void
136
    {
137
        $u1 = new User();
138
        $u2 = new User();
139
        $u3 = new User();
140
141
        $u1->setOwner($u1);
142
        $u3->setOwner($u2);
143
144
        $this->expectExceptionMessage('This user owns other users, so he cannot himself be owned by somebody else');
145
        $u2->setOwner($u1);
146
    }
147
148
    public function testSetStatus(): void
149
    {
150
        $u1 = new User();
151
        $u2 = new User();
152
153
        // Initial status
154
        self::assertSame(User::STATUS_NEW, $u1->getStatus());
155
        self::assertSame(User::STATUS_NEW, $u2->getStatus());
156
157
        $u1->setOwner($u1);
158
        $u2->setOwner($u1);
159
        $u1->setStatus(User::STATUS_INACTIVE);
160
161
        // Status is propagated to existing users
162
        self::assertSame(User::STATUS_INACTIVE, $u1->getStatus());
163
        self::assertSame(User::STATUS_INACTIVE, $u2->getStatus());
164
165
        $u1->setStatus(user::STATUS_ACTIVE);
166
        self::assertSame(User::STATUS_ACTIVE, $u1->getStatus());
167
        self::assertSame(User::STATUS_ACTIVE, $u2->getStatus());
168
169
        // Status is propagated on new users too
170
        $u3 = new User();
171
        self::assertSame(User::STATUS_NEW, $u3->getStatus());
172
        $u3->setOwner($u1);
173
        self::assertSame(User::STATUS_ACTIVE, $u3->getStatus());
174
    }
175
176
    public function testToken(): void
177
    {
178
        $user = new User();
179
        self::assertFalse($user->isTokenValid(), 'new user should not be valid');
180
181
        $token1 = $user->createToken();
182
        self::assertEquals(32, mb_strlen($token1), 'must be exactly the length of DB field');
183
        self::assertTrue($user->isTokenValid(), 'brand new token is valid');
184
185
        $token2 = $user->createToken();
186
        self::assertEquals(32, mb_strlen($token2), 'must be exactly the length of DB field');
187
        self::assertTrue($user->isTokenValid(), 'second created token is valid');
188
189
        $user->setLastLogin(new Chronos());
190
        self::assertFalse($user->isTokenValid(), 'once user is logged in token is invalid');
191
192
        $token3 = $user->createToken();
193
        self::assertEquals(32, mb_strlen($token3), 'must be exactly the length of DB field');
194
        self::assertTrue($user->isTokenValid(), 'third created token is valid');
195
196
        $user->setStatus(User::STATUS_ACTIVE);
197
        self::assertFalse($user->isTokenValid(), 'once user is activated token is invalid');
198
199
        $token4 = $user->createToken();
200
        self::assertEquals(32, mb_strlen($token4), 'must be exactly the length of DB field');
201
        self::assertTrue($user->isTokenValid(), 'third created token is valid');
202
203
        $user->setPassword('money');
204
        self::assertFalse($user->isTokenValid(), 'after password change token is invalid');
205
206
        Chronos::setTestNow((new Chronos())->subDay(1));
207
        $token5 = $user->createToken();
208
        Chronos::setTestNow(null);
209
        self::assertEquals(32, mb_strlen($token5), 'must be exactly the length of DB field');
210
        self::assertFalse($user->isTokenValid(), 'too old token is invalid');
211
212
        $allTokens = [
213
            $token1,
214
            $token2,
215
            $token3,
216
            $token4,
217
            $token5,
218
        ];
219
220
        self::assertCount(5, array_unique($allTokens), 'all tokens must be unique');
221
    }
222
223
    public function providerCanOpenDoor(): array
224
    {
225
        return [
226
            'anonymous cannot open' => [User::ROLE_ANONYMOUS, User::STATUS_ACTIVE,
227
                ['door1' => true, 'door2' => true, 'door3' => true, 'door4' => true],
228
                '127.0.0.1',
229
                ['door1' => false, 'door2' => false, 'door3' => false, 'door4' => false],
230
            ],
231
            'active member can open from premise' => [User::ROLE_MEMBER, User::STATUS_ACTIVE,
232
                ['door1' => true, 'door2' => true, 'door3' => true, 'door4' => false],
233
                '127.0.0.1',
234
                ['door1' => true, 'door2' => true, 'door3' => true, 'door4' => false],
235
            ],
236
            'active member not at premise cannot open' => [User::ROLE_MEMBER, User::STATUS_ACTIVE,
237
                ['door1' => true, 'door2' => true, 'door3' => true, 'door4' => false],
238
                '192.168.1.1',
239
                ['door1' => false, 'door2' => false, 'door3' => false, 'door4' => false],
240
            ],
241
            'inactive member cannot open' => [User::ROLE_MEMBER, User::STATUS_INACTIVE,
242
                ['door1' => true, 'door2' => true, 'door3' => true, 'door4' => false],
243
                '127.0.0.1',
244
                ['door1' => false, 'door2' => false, 'door3' => false, 'door4' => false],
245
            ],
246
            'responsible can open' => [User::ROLE_RESPONSIBLE, User::STATUS_ACTIVE,
247
                ['door1' => true, 'door2' => true, 'door3' => true, 'door4' => true],
248
                '127.0.0.1',
249
                ['door1' => true, 'door2' => true, 'door3' => true, 'door4' => true],
250
            ],
251
            'administrator can open' => [User::ROLE_ADMINISTRATOR, User::STATUS_ACTIVE,
252
                ['door1' => true, 'door2' => true, 'door3' => true, 'door4' => true],
253
                '127.0.0.1',
254
                ['door1' => true, 'door2' => true, 'door3' => true, 'door4' => true],
255
            ],
256
        ];
257
    }
258
259
    /**
260
     * @dataProvider providerCanOpenDoor,
261
     *
262
     * @param string $role
263
     * @param string $status
264
     * @param array $doors
265
     * @param string $remoteHost
266
     * @param array $result
267
     */
268
    public function testCanOpenDoor(string $role, string $status, array $doors, string $remoteHost, array $result): void
269
    {
270
        $_SERVER['REMOTE_ADDR'] = $remoteHost;
271
        $user = new User($role);
272
        $user->setStatus($status);
273
        foreach ($doors as $door => $value) {
274
            $setter = 'set' . ucfirst($door);
275
            $user->$setter($value);
276
        }
277
        foreach ($result as $door => $canOpen) {
278
            self::assertSame($canOpen, $user->getCanOpenDoor($door));
279
        }
280
    }
281
}
282