the browser-facing portion of osu!
at master 13 kB view raw
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\Controllers; 7 8use App\Models\Beatmap; 9use App\Models\Beatmapset; 10use App\Models\BeatmapsetEvent; 11use App\Models\Genre; 12use App\Models\Language; 13use App\Models\User; 14use Tests\TestCase; 15 16class BeatmapsetsControllerTest extends TestCase 17{ 18 public function testBeatmapsetIsActive() 19 { 20 $beatmap = Beatmap::factory()->create(); 21 22 $this->get(route('beatmapsets.show', ['beatmapset' => $beatmap->beatmapset_id])) 23 ->assertStatus(200); 24 } 25 26 public function testBeatmapsetIsNotActive() 27 { 28 $beatmap = Beatmap::factory()->create([ 29 'beatmapset_id' => Beatmapset::factory()->inactive(), 30 ]); 31 32 $this->get(route('beatmapsets.show', ['beatmapset' => $beatmap->beatmapset_id])) 33 ->assertStatus(404); 34 } 35 36 public function testBeatmapsetWithDeletedBeatmap() 37 { 38 $beatmap = Beatmap::factory()->create([ 39 'beatmapset_id' => Beatmapset::factory(), 40 'deleted_at' => now(), 41 ]); 42 43 $this->get(route('beatmapsets.show', ['beatmapset' => $beatmap->beatmapset_id])) 44 ->assertStatus(404); 45 } 46 47 public function testBeatmapsetWithNoBeatmaps() 48 { 49 $beatmapset = Beatmapset::factory()->create(); 50 51 $this->get(route('beatmapsets.show', ['beatmapset' => $beatmapset->getKey()])) 52 ->assertStatus(404); 53 } 54 55 public function testBeatmapsetNominate() 56 { 57 $beatmapset = Beatmapset::factory()->create([ 58 'approved' => Beatmapset::STATES['pending'], 59 ]); 60 $beatmap = Beatmap::factory()->create(['beatmapset_id' => $beatmapset->getKey()]); 61 $nominator = User::factory()->withGroup('bng', [$beatmap->mode])->create(); 62 63 $this->actingAsVerified($nominator) 64 ->put(route('beatmapsets.nominate', ['beatmapset' => $beatmapset->getKey(), 'playmodes' => [$beatmap->mode]])) 65 ->assertSuccessful(); 66 67 $this->assertSame(1, $beatmapset->beatmapsetNominations()->current()->count()); 68 } 69 70 public function testBeatmapsetNominateOwnBeatmapset() 71 { 72 $beatmapset = Beatmapset::factory()->create([ 73 'approved' => Beatmapset::STATES['pending'], 74 ]); 75 $beatmap = Beatmap::factory()->create(['beatmapset_id' => $beatmapset->getKey()]); 76 $nominator = User::factory()->withGroup('bng', [$beatmap->mode])->create(); 77 78 $beatmapset->update(['user_id' => $nominator->getKey()]); 79 80 $this->actingAsVerified($nominator) 81 ->put(route('beatmapsets.nominate', ['beatmapset' => $beatmapset->getKey(), 'playmodes' => [$beatmap->mode]])) 82 ->assertStatus(403); 83 84 $this->assertSame(0, $beatmapset->beatmapsetNominations()->current()->count()); 85 } 86 87 public function testBeatmapsetNominateOwnBeatmap() 88 { 89 $beatmapset = Beatmapset::factory()->create([ 90 'approved' => Beatmapset::STATES['pending'], 91 ]); 92 $beatmap = Beatmap::factory()->create(['beatmapset_id' => $beatmapset->getKey()]); 93 $nominator = User::factory()->withGroup('bng', [$beatmap->mode])->create(); 94 95 $beatmap->update(['user_id' => $nominator->getKey()]); 96 97 $this->actingAsVerified($nominator) 98 ->put(route('beatmapsets.nominate', ['beatmapset' => $beatmapset->getKey(), 'playmodes' => [$beatmap->mode]])) 99 ->assertStatus(403); 100 101 $this->assertSame(0, $beatmapset->beatmapsetNominations()->current()->count()); 102 } 103 104 /** 105 * @dataProvider beatmapsetStatesDataProvider 106 */ 107 public function testBeatmapsetUpdateMetadataAsModerator($state) 108 { 109 $owner = User::factory()->create(); 110 $beatmapset = Beatmapset::factory()->create([ 111 'approved' => Beatmapset::STATES[$state], 112 'user_id' => $owner, 113 ]); 114 $newGenre = Genre::factory()->create(); 115 $newLanguage = Language::factory()->create(); 116 117 $moderator = User::factory()->withGroup('nat')->create(); 118 119 $resultGenreId = $newGenre->getKey(); 120 $resultLanguageId = $newLanguage->getKey(); 121 122 $this->expectCountChange(fn () => BeatmapsetEvent::count(), 2); 123 124 $this->actingAsVerified($moderator) 125 ->put(route('beatmapsets.update', ['beatmapset' => $beatmapset->getKey()]), [ 126 'beatmapset' => [ 127 'genre_id' => $newGenre->getKey(), 128 'language_id' => $newLanguage->getKey(), 129 ], 130 ])->assertSuccessful(); 131 132 $beatmapset->refresh(); 133 134 $this->assertSame($resultGenreId, $beatmapset->genre_id); 135 $this->assertSame($resultLanguageId, $beatmapset->language_id); 136 } 137 138 /** 139 * @dataProvider beatmapsetStatesDataProvider 140 */ 141 public function testBeatmapsetUpdateMetadataAsOtherUser($state) 142 { 143 $owner = User::factory()->create(); 144 $beatmapset = Beatmapset::factory()->create([ 145 'approved' => Beatmapset::STATES[$state], 146 'user_id' => $owner, 147 ]); 148 $newGenre = Genre::factory()->create(); 149 $newLanguage = Language::factory()->create(); 150 151 $resultGenreId = $beatmapset->genre_id; 152 $resultLanguageId = $beatmapset->language_id; 153 154 $this->expectCountChange(fn () => BeatmapsetEvent::count(), 0); 155 156 $user = User::factory()->create(); 157 158 $this->actingAsVerified($user) 159 ->put(route('beatmapsets.update', ['beatmapset' => $beatmapset->getKey()]), [ 160 'beatmapset' => [ 161 'genre_id' => $newGenre->getKey(), 162 'language_id' => $newLanguage->getKey(), 163 ], 164 ])->assertStatus(403); 165 166 $beatmapset->refresh(); 167 168 $this->assertSame($resultGenreId, $beatmapset->genre_id); 169 $this->assertSame($resultLanguageId, $beatmapset->language_id); 170 } 171 172 /** 173 * @dataProvider dataProviderForTestBeatmapsetUpdateDescriptionAsOwner 174 */ 175 public function testBeatmapsetUpdateDescriptionAsOwner(bool $downloadDisabled, ?string $downloadDisabledUrl, bool $ok) 176 { 177 $beatmapset = Beatmapset::factory()->owner()->withDescription()->create([ 178 'download_disabled' => $downloadDisabled, 179 'download_disabled_url' => $downloadDisabledUrl, 180 ]); 181 $owner = $beatmapset->user; 182 $beatmapset->updateDescription('old description', $owner); 183 184 $newDescription = 'new description'; 185 $expectedDescription = $ok ? $newDescription : $beatmapset->editableDescription(); 186 187 $this->actingAsVerified($owner) 188 ->put(route('beatmapsets.update', ['beatmapset' => $beatmapset->getKey()]), [ 189 'description' => $newDescription, 190 ])->assertStatus($ok ? 200 : 403); 191 192 $beatmapset->refresh(); 193 194 $this->assertSame($expectedDescription, $beatmapset->editableDescription()); 195 } 196 197 /** 198 * @dataProvider beatmapsetStatesDataProvider 199 */ 200 public function testBeatmapsetUpdateMetadataAsOwner($state) 201 { 202 $ok = in_array($state, ['graveyard', 'wip', 'pending'], true); 203 204 $owner = User::factory()->create(); 205 $beatmapset = Beatmapset::factory()->create([ 206 'approved' => Beatmapset::STATES[$state], 207 'user_id' => $owner, 208 ]); 209 $newGenre = Genre::factory()->create(); 210 $newLanguage = Language::factory()->create(); 211 212 $resultGenreId = $ok ? $newGenre->getKey() : $beatmapset->genre_id; 213 $resultLanguageId = $ok ? $newLanguage->getKey() : $beatmapset->language_id; 214 215 $this->expectCountChange(fn () => BeatmapsetEvent::count(), $ok ? 2 : 0); 216 217 $this->actingAsVerified($owner) 218 ->put(route('beatmapsets.update', ['beatmapset' => $beatmapset->getKey()]), [ 219 'beatmapset' => [ 220 'genre_id' => $newGenre->getKey(), 221 'language_id' => $newLanguage->getKey(), 222 ], 223 ])->assertStatus($ok ? 200 : 403); 224 225 $beatmapset->refresh(); 226 227 $this->assertSame($resultGenreId, $beatmapset->genre_id); 228 $this->assertSame($resultLanguageId, $beatmapset->language_id); 229 } 230 231 /** 232 * @dataProvider beatmapsetStatesDataProvider 233 */ 234 public function testBeatmapsetUpdateMetadataAsProjectLoved(string $state): void 235 { 236 $beatmapset = Beatmapset::factory()->create([ 237 'approved' => Beatmapset::STATES[$state], 238 'user_id' => User::factory(), 239 ]); 240 $owner = $beatmapset->user; 241 $newGenre = Genre::factory()->create(); 242 $newLanguage = Language::factory()->create(); 243 244 if (in_array($state, ['graveyard', 'loved'], true)) { 245 $countChange = 2; 246 $status = 200; 247 $resultGenreId = $newGenre->getKey(); 248 $resultLanguageId = $newLanguage->getKey(); 249 } else { 250 $countChange = 0; 251 $status = 403; 252 $resultGenreId = $beatmapset->genre_id; 253 $resultLanguageId = $beatmapset->language_id; 254 } 255 $this->expectCountChange(fn () => BeatmapsetEvent::count(), $countChange); 256 257 $user = User::factory()->withGroup('loved')->create(); 258 259 $this->actingAsVerified($user) 260 ->put(route('beatmapsets.update', ['beatmapset' => $beatmapset->getKey()]), [ 261 'beatmapset' => [ 262 'genre_id' => $newGenre->getKey(), 263 'language_id' => $newLanguage->getKey(), 264 ], 265 ])->assertStatus($status); 266 267 $beatmapset->refresh(); 268 269 $this->assertSame($resultGenreId, $beatmapset->genre_id); 270 $this->assertSame($resultLanguageId, $beatmapset->language_id); 271 } 272 273 /** 274 * @dataProvider dataProviderForTestBeatmapsetUpdateOffset 275 */ 276 public function testBeatmapsetUpdateOffset(string $userGroupOrOwner, bool $ok): void 277 { 278 $beatmapset = Beatmapset::factory()->create([ 279 'approved' => Beatmapset::STATES['ranked'], 280 'user_id' => User::factory(), 281 ]); 282 283 $user = $userGroupOrOwner === 'owner' 284 ? $beatmapset->user 285 : User::factory()->withGroup($userGroupOrOwner)->create(); 286 287 $newOffset = $beatmapset->offset + 25; 288 $expectedOffset = $ok ? $newOffset : $beatmapset->offset; 289 290 $this->expectCountChange(fn () => BeatmapsetEvent::count(), $ok ? 1 : 0); 291 292 $this->actingAsVerified($user) 293 ->put(route('beatmapsets.update', ['beatmapset' => $beatmapset->getKey()]), [ 294 'beatmapset' => [ 295 'offset' => $newOffset, 296 ], 297 ])->assertStatus($ok ? 200 : 403); 298 299 $beatmapset->refresh(); 300 301 $this->assertSame($expectedOffset, $beatmapset->offset); 302 } 303 304 /** 305 * @dataProvider dataProviderForTestBeatmapsetUpdateTags 306 */ 307 public function testBeatmapsetUpdateTags(string $userGroupOrOwner, bool $ok): void 308 { 309 $beatmapset = Beatmapset::factory()->create([ 310 'approved' => Beatmapset::STATES['ranked'], 311 'user_id' => User::factory(), 312 ]); 313 314 $user = $userGroupOrOwner === 'owner' 315 ? $beatmapset->user 316 : User::factory()->withGroup($userGroupOrOwner)->create(); 317 318 $newTags = "{$beatmapset->tags} more_tag"; 319 $expectedTags = $ok ? $newTags : $beatmapset->tags; 320 321 $this->expectCountChange(fn () => BeatmapsetEvent::count(), $ok ? 1 : 0); 322 323 $this->actingAsVerified($user) 324 ->put(route('beatmapsets.update', ['beatmapset' => $beatmapset->getKey()]), [ 325 'beatmapset' => [ 326 'tags' => $newTags, 327 ], 328 ])->assertStatus($ok ? 200 : 403); 329 330 $this->assertSame($expectedTags, $beatmapset->fresh()->tags); 331 } 332 333 public static function beatmapsetStatesDataProvider() 334 { 335 return array_map(function ($state) { 336 return [$state]; 337 }, array_keys(Beatmapset::STATES)); 338 } 339 340 public static function dataProviderForTestBeatmapsetUpdateOffset(): array 341 { 342 return [ 343 ['admin', true], 344 ['bng', false], 345 ['default', false], 346 ['gmt', false], 347 ['nat', false], 348 ['owner', false], 349 ]; 350 } 351 352 public static function dataProviderForTestBeatmapsetUpdateTags(): array 353 { 354 return [ 355 ['admin', true], 356 ['bng', false], 357 ['default', false], 358 ['gmt', true], 359 ['nat', true], 360 ['owner', false], 361 ]; 362 } 363 364 public static function dataProviderForTestBeatmapsetUpdateDescriptionAsOwner(): array 365 { 366 return [ 367 [false, null, true], 368 [true, null, false], 369 [false, 'https://fail.works/notice', false], 370 [true, 'https://fail.works/notice', false], 371 ]; 372 } 373}