the browser-facing portion of osu!
at master 7.9 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\Models; 7 8use App\Models\Beatmap; 9use App\Models\BeatmapDiscussion; 10use App\Models\Beatmapset; 11use App\Models\KudosuHistory; 12use App\Models\User; 13use Illuminate\Database\Eloquent\Builder; 14use Tests\TestCase; 15 16class BeatmapDiscussionTest extends TestCase 17{ 18 /** 19 * Valid beatmapset status always maps to a scope method sanity test. 20 * 21 * @dataProvider validBeatmapsetStatuses 22 */ 23 public function testBeatmapsetScopesExist($scope) 24 { 25 $this->assertInstanceOf(Builder::class, Beatmapset::$scope()); 26 } 27 28 public function testMapperPost() 29 { 30 $mapper = User::factory()->create(); 31 $beatmapset = Beatmapset::factory()->create([ 32 'user_id' => $mapper, 33 ]); 34 $beatmap = $beatmapset->beatmaps()->save(Beatmap::factory()->make()); 35 36 $discussion = $this->newDiscussion($beatmapset); 37 $discussion->fill([ 38 'beatmap_id' => $beatmap->beatmap_id, 39 'message_type' => 'mapper_note', 40 'user_id' => $mapper->getKey(), 41 ]); 42 43 $this->assertTrue($discussion->isValid()); 44 45 $discussion->message_type = 'problem'; 46 $this->assertTrue($discussion->isValid()); 47 48 $discussion->message_type = 'suggestion'; 49 $this->assertTrue($discussion->isValid()); 50 51 $discussion->message_type = 'praise'; 52 $this->assertTrue($discussion->isValid()); 53 54 $discussion->beatmapset->update(['approved' => Beatmapset::STATES['pending']]); 55 $discussion->beatmap_id = null; 56 $discussion->message_type = 'hype'; 57 $this->assertFalse($discussion->isValid()); 58 } 59 60 public function testModderPost() 61 { 62 $mapper = User::factory()->create(); 63 $beatmapset = Beatmapset::factory()->create([ 64 'user_id' => $mapper, 65 ]); 66 $beatmap = $beatmapset->beatmaps()->save(Beatmap::factory()->make()); 67 $modder = User::factory()->create(); 68 69 $discussion = $this->newDiscussion($beatmapset); 70 $discussion->fill([ 71 'beatmap_id' => $beatmap->beatmap_id, 72 'message_type' => 'mapper_note', 73 'user_id' => $modder->getKey(), 74 ]); 75 76 $this->assertTrue($discussion->isValid()); 77 78 $discussion->message_type = 'problem'; 79 $this->assertTrue($discussion->isValid()); 80 81 $discussion->message_type = 'suggestion'; 82 $this->assertTrue($discussion->isValid()); 83 84 $discussion->message_type = 'praise'; 85 $this->assertTrue($discussion->isValid()); 86 87 $discussion->beatmapset->update(['approved' => Beatmapset::STATES['ranked']]); 88 $discussion->message_type = 'hype'; 89 $this->assertFalse($discussion->isValid()); 90 91 $discussion->beatmap_id = null; 92 $this->assertFalse($discussion->isValid()); 93 94 $discussion->beatmapset->update(['approved' => Beatmapset::STATES['pending']]); 95 $this->assertTrue($discussion->isValid()); 96 } 97 98 public function testIsValid() 99 { 100 $beatmapset = Beatmapset::factory()->create(); 101 $beatmap = $beatmapset->beatmaps()->save(Beatmap::factory()->make()); 102 103 $otherBeatmapset = Beatmapset::factory()->create(); 104 $otherBeatmap = $otherBeatmapset->beatmaps()->save(Beatmap::factory()->make()); 105 106 $validTimestamp = ($beatmap->total_length + 10) * 1000; 107 $invalidTimestamp = $validTimestamp + 1; 108 109 // blank everything not fine 110 $discussion = $this->newDiscussion($beatmapset); 111 $this->assertFalse($discussion->isValid()); 112 113 // is valid with message_type 114 $discussion = $this->newDiscussion($beatmapset); 115 $discussion->fill(['message_type' => 'problem']); 116 $this->assertTrue($discussion->isValid()); 117 118 // just beatmap_id is not fine (per-beatmap general) 119 $discussion = $this->newDiscussion($beatmapset); 120 $discussion->fill(['beatmap_id' => $beatmap->beatmap_id]); 121 $this->assertFalse($discussion->isValid()); 122 123 // with beatmap_id and message_type is fine (per-beatmap general) 124 $discussion = $this->newDiscussion($beatmapset); 125 $discussion->fill([ 126 'beatmap_id' => $beatmap->beatmap_id, 127 'message_type' => 'problem', 128 ]); 129 $this->assertTrue($discussion->isValid()); 130 131 // complete data is fine as well 132 $discussion = $this->newDiscussion($beatmapset); 133 $discussion->fill(['timestamp' => $validTimestamp, 'message_type' => 'praise', 'beatmap_id' => $beatmap->beatmap_id]); 134 $this->assertTrue($discussion->isValid()); 135 136 // Including timestamp 0 137 $discussion = $this->newDiscussion($beatmapset); 138 $discussion->fill(['timestamp' => 0, 'message_type' => 'praise', 'beatmap_id' => $beatmap->beatmap_id]); 139 $this->assertTrue($discussion->isValid()); 140 141 // just timestamp is not valid 142 $discussion = $this->newDiscussion($beatmapset); 143 $discussion->fill(['timestamp' => $validTimestamp]); 144 $this->assertFalse($discussion->isValid()); 145 146 // nor is wrong timestamp 147 $discussion = $this->newDiscussion($beatmapset); 148 $discussion->fill(['timestamp' => $invalidTimestamp, 'message_type' => 'praise', 'beatmap_id' => $beatmap->beatmap_id]); 149 $this->assertFalse($discussion->isValid()); 150 } 151 152 public function testSoftDeleteOrExplode() 153 { 154 $beatmapset = Beatmapset::factory()->create(); 155 $beatmap = $beatmapset->beatmaps()->save(Beatmap::factory()->make()); 156 $user = User::factory()->create(); 157 $discussion = BeatmapDiscussion::create([ 158 'beatmapset_id' => $beatmapset->getKey(), 159 'beatmap_id' => $beatmap->getKey(), 160 'user_id' => $user->getKey(), 161 'message_type' => 'suggestion', 162 ]); 163 164 $this->assertFalse($discussion->trashed()); 165 166 // Soft delete. 167 $discussion->softDeleteOrExplode($user); 168 $discussion = $discussion->fresh(); 169 $this->assertTrue($discussion->trashed()); 170 171 // Restore. 172 $discussion->restore($user); 173 $discussion = $discussion->fresh(); 174 $this->assertFalse($discussion->trashed()); 175 176 // Soft delete with deleted beatmap. 177 $beatmap->delete(); 178 $discussion->softDeleteOrExplode($user); 179 $discussion = $discussion->fresh(); 180 $this->assertTrue($discussion->trashed()); 181 182 // Restore with deleted beatmap. 183 $discussion->restore($user); 184 $discussion = $discussion->fresh(); 185 $this->assertFalse($discussion->trashed()); 186 } 187 188 public function testRefreshKudosu(): void 189 { 190 $discussion = BeatmapDiscussion::factory()->problem()->create([ 191 'beatmapset_id' => Beatmapset::factory()->create(), 192 'timestamp' => null, 193 'user_id' => User::factory()->create(), 194 ]); 195 $discussion->beatmapDiscussionVotes()->create([ 196 'score' => 1, 197 'user_id' => User::factory()->create()->getKey(), 198 ]); 199 $discussion->beatmapDiscussionVotes()->create([ 200 'score' => -1, 201 'user_id' => User::factory()->create()->getKey(), 202 ]); 203 204 $this->expectCountChange(fn () => KudosuHistory::count(), 1); 205 $this->expectCountChange(fn () => $discussion->user->fresh()->osu_kudostotal, 1); 206 $discussion->fresh()->refreshKudosu('recalculate'); 207 } 208 209 public static function validBeatmapsetStatuses() 210 { 211 return array_map(function ($status) { 212 return [camel_case($status)]; 213 }, BeatmapDiscussion::VALID_BEATMAPSET_STATUSES); 214 } 215 216 private function newDiscussion($beatmapset) 217 { 218 return new BeatmapDiscussion(['beatmapset_id' => $beatmapset->getKey()]); 219 } 220}