the browser-facing portion of osu!
at master 9.7 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 6declare(strict_types=1); 7 8namespace Tests\Models\Multiplayer; 9 10use App\Models\Multiplayer\PlaylistItem; 11use App\Models\Multiplayer\Room; 12use App\Models\Multiplayer\UserScoreAggregate; 13use App\Models\User; 14use App\Transformers\Multiplayer\UserScoreAggregateTransformer; 15use Tests\TestCase; 16 17class UserScoreAggregateTest extends TestCase 18{ 19 private Room $room; 20 21 public function testAddingHigherScore(): void 22 { 23 $user = User::factory()->create(); 24 $playlistItem = $this->createPlaylistItem(); 25 26 // first play 27 $scoreLink = $this->roomAddPlay($user, $playlistItem, [ 28 'accuracy' => 0.5, 29 'passed' => true, 30 'total_score' => 10, 31 ]); 32 33 $agg = UserScoreAggregate::new($user, $this->room); 34 $this->assertSame(1, $agg->completed); 35 $this->assertSame(0.5, $agg->accuracy); 36 $this->assertSame(10, $agg->total_score); 37 $this->assertSame($scoreLink->getKey(), $agg->last_score_id); 38 39 // second, higher score play 40 $scoreLink2 = $this->roomAddPlay($user, $playlistItem, [ 41 'accuracy' => 1, 42 'passed' => true, 43 'total_score' => 100, 44 ]); 45 46 $agg->refresh(); 47 $this->assertSame(1, $agg->completed); 48 $this->assertSame(1.0, $agg->accuracy); 49 $this->assertSame(100, $agg->total_score); 50 $this->assertSame($scoreLink2->getKey(), $agg->last_score_id); 51 } 52 53 public function testAddingLowerScore(): void 54 { 55 $user = User::factory()->create(); 56 $playlistItem = $this->createPlaylistItem(); 57 58 // first play 59 $scoreLink = $this->roomAddPlay($user, $playlistItem, [ 60 'accuracy' => 0.5, 61 'passed' => true, 62 'total_score' => 10, 63 ]); 64 65 $agg = UserScoreAggregate::new($user, $this->room); 66 $this->assertSame(1, $agg->completed); 67 $this->assertSame(0.5, $agg->accuracy); 68 $this->assertSame(10, $agg->total_score); 69 $this->assertSame($scoreLink->getKey(), $agg->last_score_id); 70 71 // second, lower score play 72 $this->roomAddPlay($user, $playlistItem, [ 73 'accuracy' => 1, 74 'passed' => true, 75 'total_score' => 1, 76 ]); 77 78 $agg->refresh(); 79 $this->assertSame(1, $agg->completed); 80 $this->assertSame(0.5, $agg->accuracy); 81 $this->assertSame(10, $agg->total_score); 82 $this->assertSame($scoreLink->getKey(), $agg->last_score_id); 83 } 84 85 public function testAddingEqualScore(): void 86 { 87 $firstUser = User::factory()->create(); 88 $secondUser = User::factory()->create(); 89 $playlistItem = $this->createPlaylistItem(); 90 91 // first user sets play 92 $firstUserPlay = $this->roomAddPlay($firstUser, $playlistItem, [ 93 'accuracy' => 0.5, 94 'passed' => true, 95 'total_score' => 10, 96 ]); 97 98 $firstUserAgg = UserScoreAggregate::new($firstUser, $this->room); 99 $this->assertSame(1, $firstUserAgg->completed); 100 $this->assertSame(0.5, $firstUserAgg->accuracy); 101 $this->assertSame(10, $firstUserAgg->total_score); 102 $this->assertSame(1, $firstUserAgg->userRank()); 103 $this->assertSame($firstUserPlay->getKey(), $firstUserAgg->last_score_id); 104 105 // second user sets play with same total, so they get second place due to being late 106 $secondUserPlay = $this->roomAddPlay($secondUser, $playlistItem, [ 107 'accuracy' => 0.5, 108 'passed' => true, 109 'total_score' => 10, 110 ]); 111 112 $secondUserAgg = UserScoreAggregate::new($secondUser, $this->room); 113 $this->assertSame(1, $secondUserAgg->completed); 114 $this->assertSame(0.5, $secondUserAgg->accuracy); 115 $this->assertSame(10, $secondUserAgg->total_score); 116 $this->assertSame(2, $secondUserAgg->userRank()); 117 $this->assertSame($secondUserPlay->getKey(), $secondUserAgg->last_score_id); 118 119 // first user sets play with same total again, but their rank should not move now 120 $this->roomAddPlay($firstUser, $playlistItem, [ 121 'accuracy' => 0.5, 122 'passed' => true, 123 'total_score' => 10, 124 ]); 125 126 $firstUserAgg->refresh(); 127 $this->assertSame(1, $firstUserAgg->completed); 128 $this->assertSame(0.5, $firstUserAgg->accuracy); 129 $this->assertSame(10, $firstUserAgg->total_score); 130 $this->assertSame(1, $firstUserAgg->userRank()); 131 $this->assertSame($firstUserPlay->getKey(), $firstUserAgg->last_score_id); 132 133 $secondUserAgg->refresh(); 134 $this->assertSame(2, $secondUserAgg->userRank()); 135 } 136 137 public function testAddingMultiplePlaylistItems(): void 138 { 139 $user = User::factory()->create(); 140 $playlistItem = $this->createPlaylistItem(); 141 $playlistItem2 = $this->createPlaylistItem(); 142 143 // first playlist item 144 $this->roomAddPlay($user, $playlistItem, [ 145 'accuracy' => 0.5, 146 'passed' => true, 147 'total_score' => 10, 148 ]); 149 150 $agg = UserScoreAggregate::new($user, $this->room); 151 $this->assertSame(1, $agg->completed); 152 $this->assertSame(0.5, $agg->accuracy); 153 $this->assertSame(0.5, $agg->averageAccuracy()); 154 $this->assertSame(10, $agg->total_score); 155 156 // second playlist item 157 $scoreLink = $this->roomAddPlay($user, $playlistItem2, [ 158 'accuracy' => 1, 159 'passed' => true, 160 'total_score' => 100, 161 ]); 162 163 $agg->refresh(); 164 $this->assertSame(2, $agg->completed); 165 $this->assertSame(1.5, $agg->accuracy); 166 $this->assertSame(0.75, $agg->averageAccuracy()); 167 $this->assertSame(110, $agg->total_score); 168 $this->assertSame($scoreLink->getKey(), $agg->last_score_id); 169 } 170 171 public function testStartingPlayIncreasesAttempts(): void 172 { 173 $user = User::factory()->create(); 174 $playlistItem = $this->createPlaylistItem(); 175 176 static::roomStartPlay($user, $playlistItem); 177 $agg = UserScoreAggregate::new($user, $this->room); 178 179 $this->assertSame(1, $agg->attempts); 180 $this->assertSame(0, $agg->completed); 181 } 182 183 public function testFailedScoresAreAttemptsOnly(): void 184 { 185 $user = User::factory()->create(); 186 $playlistItem = $this->createPlaylistItem(); 187 188 $this->roomAddPlay($user, $playlistItem, [ 189 'accuracy' => 0.1, 190 'passed' => false, 191 'total_score' => 10, 192 ]); 193 194 $playlistItem2 = $this->createPlaylistItem(); 195 $this->roomAddPlay($user, $playlistItem2, [ 196 'accuracy' => 1, 197 'passed' => true, 198 'total_score' => 1, 199 ]); 200 201 $agg = UserScoreAggregate::new($user, $this->room); 202 203 $this->assertSame(2, $agg->attempts); 204 $this->assertSame(1, $agg->completed); 205 $this->assertSame(1.0, $agg->averageAccuracy()); 206 $this->assertSame(1, $agg->total_score); 207 } 208 209 public function testPassedScoresIncrementsCompletedCount(): void 210 { 211 $user = User::factory()->create(); 212 $playlistItem = $this->createPlaylistItem(); 213 214 $this->roomAddPlay($user, $playlistItem, [ 215 'accuracy' => 1, 216 'passed' => true, 217 'total_score' => 1, 218 ]); 219 220 $agg = UserScoreAggregate::new($user, $this->room); 221 222 $this->assertSame(1, $agg->completed); 223 $this->assertSame(1, $agg->total_score); 224 } 225 226 public function testPassedScoresAreAveragedInTransformer(): void 227 { 228 $user = User::factory()->create(); 229 $playlistItem = $this->createPlaylistItem(); 230 $playlistItem2 = $this->createPlaylistItem(); 231 232 $this->roomAddPlay($user, $playlistItem, [ 233 'accuracy' => 0.1, 234 'passed' => false, 235 'total_score' => 1, 236 ]); 237 238 $this->roomAddPlay($user, $playlistItem, [ 239 'accuracy' => 0.3, 240 'passed' => false, 241 'total_score' => 1, 242 ]); 243 244 $this->roomAddPlay($user, $playlistItem, [ 245 'accuracy' => 0.5, 246 'passed' => true, 247 'total_score' => 1, 248 ]); 249 250 $this->roomAddPlay($user, $playlistItem2, [ 251 'accuracy' => 0.8, 252 'passed' => true, 253 'total_score' => 1, 254 ]); 255 256 $agg = UserScoreAggregate::new($user, $this->room); 257 258 $result = json_item($agg, new UserScoreAggregateTransformer()); 259 260 $this->assertSame(0.65, $result['accuracy']); 261 } 262 263 public function testRecalculate(): void 264 { 265 $playlistItem = $this->createPlaylistItem(); 266 $user = User::factory()->create(); 267 $this->roomAddPlay($user, $playlistItem, [ 268 'accuracy' => 0.3, 269 'passed' => true, 270 'total_score' => 1, 271 ]); 272 $agg = UserScoreAggregate::new($user, $this->room); 273 $agg->recalculate(); 274 $agg->refresh(); 275 276 $this->assertSame(1, $agg->total_score); 277 $this->assertSame(1, $agg->attempts); 278 $this->assertSame(0.3, $agg->accuracy); 279 $this->assertSame(1, $agg->completed); 280 } 281 282 protected function setUp(): void 283 { 284 parent::setUp(); 285 286 $this->room = Room::factory()->create(); 287 } 288 289 private function createPlaylistItem(): PlaylistItem 290 { 291 return PlaylistItem::factory()->create([ 292 'owner_id' => $this->room->host, 293 'room_id' => $this->room, 294 ]); 295 } 296}