1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
|
<?php
use PHPUnit\Framework\TestCase;
/**
* Demonstrates how to test a real class when a stub exists: opt out of the stub
* via the stub autoloader allowlist and let the normal inc/ autoloader load the
* production class instead. Now adapted to use the SQLite-backed Database test
* backend so we assert against real SQL, not stub call logs.
*
* @runTestsInSeparateProcesses
* @preserveGlobalState disabled
*/
class UserTest extends TestCase
{
protected function setUp(): void
{
$GLOBALS['__TEST_USE_REAL_CLASSES'] = ['User'];
Database::resetSchema();
Session::reset();
}
public function testBasicAccessorsLoggedOutAndLoggedIn(): void
{
// Sanity: manipulate private static User::$user via reflection
$ref = new ReflectionClass('User');
$prop = $ref->getProperty('user');
$prop->setAccessible(true);
// Start logged out
$prop->setValue(null, false);
$this->assertFalse(User::isLoggedIn());
$this->assertNull(User::getId());
$this->assertFalse(User::getName());
$this->assertNull(User::getLogin());
// Now set a minimal user record
$user = [
'userid' => 42,
'fullname' => 'Alice Doe',
'login' => 'alice',
'permissions' => 0,
'lasteventid' => null,
];
$prop->setValue(null, $user);
$this->assertTrue(User::isLoggedIn());
$this->assertSame(42, User::getId());
$this->assertSame('Alice Doe', User::getName());
$this->assertSame('alice', User::getLogin());
}
public function testSetAndGetLastSeenEventUpdatesDatabaseAndMemory(): void
{
$ref = new ReflectionClass('User');
$prop = $ref->getProperty('user');
$prop->setAccessible(true);
// Use an existing seeded user (id=1)
$prop->setValue(null, [
'userid' => 1,
'fullname' => 'Alice Doe',
'login' => 'alice',
'permissions' => 0,
'lasteventid' => 1,
]);
User::setLastSeenEvent(1234);
// Assert DB has been updated
$row = Database::queryFirst('SELECT lasteventid FROM user WHERE userid = :u', ['u' => 1]);
$this->assertNotFalse($row);
$this->assertSame(1234, (int)$row['lasteventid']);
// And memory updated too
$this->assertSame(1234, User::getLastSeenEvent());
}
public function testUpdatePasswordUsesCryptoAndExecutesUpdate(): void
{
$ref = new ReflectionClass('User');
$prop = $ref->getProperty('user');
$prop->setAccessible(true);
// Use seeded user id=1
$prop->setValue(null, [
'userid' => 1,
'fullname' => 'Alice Doe',
'login' => 'alice',
'permissions' => 0,
'lasteventid' => null,
]);
// Act
$ret = User::updatePassword('secret');
$this->assertTrue($ret);
// Assert DB updated with hashed password from Crypto stub
$row = Database::queryFirst('SELECT passwd FROM user WHERE userid = :u', ['u' => 1]);
$this->assertNotFalse($row);
$this->assertSame('HASHED-secret', $row['passwd']);
}
public function testLoginVerifiesPasswordAndCreatesSession(): void
{
$_SERVER['REMOTE_ADDR'] = '192.168.127.12';
$_SERVER['REMOTE_PORT'] = 12345;
$_SERVER['HTTP_USER_AGENT'] = 'foobar';
Session::reset();
// Good password (Crypto::verify will accept 'ok' against 'STORED' from seed)
$this->assertTrue(User::login('alice', 'ok', true));
$this->assertNotNull(Session::$lastCreate);
$this->assertSame(1, Session::$lastCreate['userId']);
// Bad password
Session::reset();
$this->assertFalse(User::login('alice', 'bad', false));
$this->assertNull(Session::$lastCreate);
}
}
|