1<?php
2
3// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the GNU Affero General Public License v3.0.
4// See the LICENCE file in the repository root for full licence text.
5
6namespace Tests\Libraries;
7
8use App\Exceptions\ChangeUsernameException;
9use App\Libraries\ChangeUsername;
10use App\Models\User;
11use Carbon\Carbon;
12use Tests\TestCase;
13
14// FIXME: need more tests
15class ChangeUsernameTest extends TestCase
16{
17 public function testUserCannotBeRenamed()
18 {
19 $user = $this->createUser(['user_id' => 1]);
20
21 $errors = $user->validateChangeUsername('newusername')->all();
22 $this->assertArrayHasKey('user_id', $errors);
23 }
24
25 public function testUserIsRestricted()
26 {
27 $user = $this->createUser(['user_warnings' => 1]);
28
29 $errors = $user->validateChangeUsername('newusername')->all();
30 $expected = [osu_trans('model_validation.user.change_username.restricted')];
31
32 $this->assertArrayHasKey('username', $errors);
33 $this->assertArraySubset($expected, $errors['username'], true);
34 }
35
36 public function testSupportCanChangeEvenIfUserIsRestricted()
37 {
38 $user = $this->createUser(['user_warnings' => 1]);
39
40 $errors = $user->validateChangeUsername('newusername', 'support')->all();
41
42 $this->assertEmpty($errors);
43 }
44
45 public function testUserHasNeverSupported()
46 {
47 $user = $this->createUser(['osu_subscriptionexpiry' => null]);
48
49 $errors = $user->validateChangeUsername('newusername')->all();
50 $expected = [ChangeUsername::requireSupportedMessage()];
51
52 $this->assertArrayHasKey('username', $errors);
53 $this->assertArraySubset($expected, $errors['username'], true);
54 }
55
56 public function testSupportCanChangeEvenIfUserHasNeverSupported()
57 {
58 $user = $this->createUser(['osu_subscriptionexpiry' => null]);
59
60 $errors = $user->validateChangeUsername('newusername', 'support')->all();
61
62 $this->assertEmpty($errors);
63 }
64
65 public function testUsernameIsSame()
66 {
67 $user = $this->createUser();
68
69 $errors = $user->validateChangeUsername('iamuser')->all();
70 $expected = [osu_trans('model_validation.user.change_username.username_is_same')];
71
72 $this->assertArrayHasKey('username', $errors);
73 $this->assertArraySubset($expected, $errors['username'], true);
74 }
75
76 public function testUsernameWithDifferentCasingIsSame()
77 {
78 $user = $this->createUser();
79
80 $errors = $user->validateChangeUsername('iAmUser')->all();
81 $expected = [osu_trans('model_validation.user.change_username.username_is_same')];
82
83 $this->assertArrayHasKey('username', $errors);
84 $this->assertArraySubset($expected, $errors['username'], true);
85 }
86
87 public function testUserHasSupportedButExpired()
88 {
89 $user = $this->createUser(['osu_subscriptionexpiry' => Carbon::now()->subMonths()]);
90
91 $errors = $user->validateChangeUsername('newusername');
92
93 $this->assertTrue($errors->isEmpty());
94 }
95
96 public function testUsernameTakenButInactive()
97 {
98 $user = $this->createUser();
99 $existing = $this->createUser([
100 'username' => 'newusername',
101 'username_clean' => 'newusername',
102 'osu_subscriptionexpiry' => null,
103 'user_lastvisit' => Carbon::now()->subYears(),
104 ]);
105
106 $user->changeUsername('newusername', 'paid');
107
108 $user->refresh();
109 $existing->refresh();
110 $historyExists = $existing->usernameChangeHistory()
111 ->where('username_last', 'newusername')
112 ->where('type', 'inactive')
113 ->exists();
114
115 $this->assertSame('newusername', $user->username);
116 $this->assertSame('newusername_old', $existing->username);
117 $this->assertTrue($historyExists);
118 }
119
120 public function testUsernameTakenButInactiveAndNeedsMoreRenames()
121 {
122 $user = $this->createUser();
123 $existing = $this->createUser([
124 'username' => 'newusername',
125 'username_clean' => 'newusername',
126 'osu_subscriptionexpiry' => null,
127 'user_lastvisit' => Carbon::now()->subYears(),
128 ]);
129 $this->createUser([
130 'username' => 'newusername_old',
131 'username_clean' => 'newusername_old',
132 'osu_subscriptionexpiry' => null,
133 'user_lastvisit' => Carbon::now()->subYears(),
134 ]);
135
136 $user->changeUsername('newusername', 'paid');
137
138 $user->refresh();
139 $existing->refresh();
140 $historyExists = $existing->usernameChangeHistory()
141 ->where('username_last', 'newusername')
142 ->where('type', 'inactive')
143 ->exists();
144
145 $this->assertSame('newusername', $user->username);
146 $this->assertSame('newusername_old_1', $existing->username);
147 $this->assertTrue($historyExists);
148 }
149
150 public function testPreviousUserHasBadge()
151 {
152 $newUsername = 'newusername';
153
154 $user = $this->createUser();
155 $existing = $this->createUser([
156 'username' => 'existing_now',
157 'username_clean' => 'existing_now',
158 'osu_subscriptionexpiry' => null,
159 ]);
160
161 $existing->usernameChangeHistory()->create([
162 'username' => 'existing_now',
163 'username_last' => $newUsername,
164 'timestamp' => Carbon::now()->subYears(),
165 'type' => 'paid',
166 ]);
167
168 $existing->badges()->create(['image' => 'test', 'description' => 'test', 'awarded' => now()]);
169
170 $this->expectException(ChangeUsernameException::class);
171 $user->changeUsername($newUsername, 'paid');
172 }
173
174 public function testPreviousUserHasNoBadge()
175 {
176 $newUsername = 'newusername';
177
178 $user = $this->createUser();
179 $existing = $this->createUser([
180 'username' => 'existing_now',
181 'username_clean' => 'existing_now',
182 'osu_subscriptionexpiry' => null,
183 ]);
184
185 $existing->usernameChangeHistory()->create([
186 'username' => 'existing_now',
187 'username_last' => $newUsername,
188 'timestamp' => Carbon::now()->subYears(),
189 'type' => 'paid',
190 ]);
191
192 $user->changeUsername($newUsername, 'paid');
193 $user->refresh();
194
195 $this->assertSame($newUsername, $user->username);
196 }
197
198 public function testInactiveUserHasBadge()
199 {
200 $newUsername = 'newusername';
201
202 $user = $this->createUser();
203 $existing = $this->createUser([
204 'username' => 'newusername',
205 'username_clean' => 'newusername',
206 'osu_subscriptionexpiry' => null,
207 'user_lastvisit' => Carbon::now()->subYears(),
208 ]);
209
210 $existing->badges()->create(['image' => 'test', 'description' => 'test', 'awarded' => now()]);
211
212 $this->expectException(ChangeUsernameException::class);
213 $user->changeUsername($newUsername, 'paid');
214 }
215
216 private function createUser(array $attribs = []): User
217 {
218 return User::factory()->create(array_merge([
219 'username' => 'iamuser',
220 'username_clean' => 'iamuser',
221 'user_lastvisit' => Carbon::now(),
222 'osu_subscriptionexpiry' => Carbon::now()->addMonths(),
223 ], $attribs));
224 }
225}