the browser-facing portion of osu!
at master 5.2 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\Commands; 9 10use App\Console\Commands\ModdingRankCommand; 11use App\Enums\Ruleset; 12use App\Jobs\CheckBeatmapsetCovers; 13use App\Jobs\Notifications\BeatmapsetRank; 14use App\Models\Beatmap; 15use App\Models\BeatmapDiscussion; 16use App\Models\Beatmapset; 17use Bus; 18use Database\Factories\BeatmapsetFactory; 19use Tests\TestCase; 20 21class ModdingRankCommandTest extends TestCase 22{ 23 public function testCountOnly(): void 24 { 25 $this->beatmapset([Ruleset::osu])->create(); 26 27 $this->expectCountChange(fn () => Beatmapset::ranked()->count(), 0); 28 29 $this->artisan('modding:rank', ['--count-only' => true]); 30 31 Bus::assertNotDispatched(CheckBeatmapsetCovers::class); 32 Bus::assertNotDispatched(BeatmapsetRank::class); 33 } 34 35 /** 36 * @dataProvider rankDataProvider 37 */ 38 public function testRank(int $qualifiedDaysAgo, int $expected): void 39 { 40 $this->beatmapset([Ruleset::osu], $qualifiedDaysAgo)->create(); 41 42 $this->expectCountChange(fn () => Beatmapset::ranked()->count(), $expected); 43 44 $this->artisan('modding:rank', ['--no-wait' => true]); 45 46 Bus::assertDispatchedTimes(CheckBeatmapsetCovers::class, $expected); 47 Bus::assertDispatchedTimes(BeatmapsetRank::class, $expected); 48 } 49 50 /** 51 * @dataProvider rankHybridDataProvider 52 */ 53 public function testRankHybrid(array $beatmapsetRulesets, array $expectedCounts): void 54 { 55 foreach ($beatmapsetRulesets as $rulesets) { 56 $this->beatmapset($rulesets)->create(); 57 } 58 59 foreach (Ruleset::cases() as $ruleset) { 60 $this->assertSame($expectedCounts[$ruleset->value], ModdingRankCommand::getStats($ruleset)['inQueue']); 61 } 62 } 63 64 public function testRankOpenIssue(): void 65 { 66 $this->beatmapset([Ruleset::osu]) 67 ->has(BeatmapDiscussion::factory()->general()->problem()) 68 ->create(); 69 70 $this->expectCountChange(fn () => Beatmapset::ranked()->count(), 0); 71 72 $this->artisan('modding:rank', ['--no-wait' => true]); 73 74 Bus::assertNotDispatched(CheckBeatmapsetCovers::class); 75 Bus::assertNotDispatched(BeatmapsetRank::class); 76 } 77 78 public function testRankQuota(): void 79 { 80 $this->beatmapset([Ruleset::osu])->count(3)->create(); 81 82 $this->expectCountChange(fn () => Beatmapset::qualified()->count(), -2); 83 $this->expectCountChange(fn () => Beatmapset::ranked()->count(), 2); 84 85 $this->artisan('modding:rank', ['--no-wait' => true]); 86 87 Bus::assertDispatched(CheckBeatmapsetCovers::class); 88 Bus::assertDispatched(BeatmapsetRank::class); 89 } 90 91 public function testRankQuotaSeparateRuleset(): void 92 { 93 foreach (Ruleset::cases() as $ruleset) { 94 $this->beatmapset([$ruleset])->create(); 95 } 96 97 $count = count(Ruleset::cases()); 98 $this->expectCountChange(fn () => Beatmapset::ranked()->count(), $count); 99 100 $this->artisan('modding:rank', ['--no-wait' => true]); 101 102 Bus::assertDispatchedTimes(CheckBeatmapsetCovers::class, $count); 103 Bus::assertDispatchedTimes(BeatmapsetRank::class, $count); 104 } 105 106 107 public static function rankDataProvider() 108 { 109 // 1 day ago isn't used because it might or might not be equal to the cutoff depending on how fast it runs. 110 return [ 111 [0, 0], 112 [2, 1], 113 ]; 114 } 115 116 public static function rankHybridDataProvider() 117 { 118 return [ 119 // hybrid counts as ruleset with lowest enum value 120 [[[Ruleset::osu, Ruleset::taiko, Ruleset::catch, Ruleset::mania]], [1, 0, 0, 0]], 121 [[[Ruleset::taiko, Ruleset::catch, Ruleset::mania]], [0, 1, 0, 0]], 122 [[[Ruleset::catch, Ruleset::mania]], [0, 0, 1, 0]], 123 [[[Ruleset::mania]], [0, 0, 0, 1]], 124 125 // not comprehensive 126 [[[Ruleset::osu, Ruleset::taiko], [Ruleset::osu]], [2, 0, 0, 0]], 127 [[[Ruleset::osu, Ruleset::taiko], [Ruleset::taiko]], [1, 1, 0, 0]], 128 [[[Ruleset::mania, Ruleset::taiko], [Ruleset::taiko]], [0, 2, 0, 0]], 129 [[[Ruleset::mania, Ruleset::taiko], [Ruleset::mania]], [0, 1, 0, 1]], 130 [[[Ruleset::catch, Ruleset::taiko], [Ruleset::mania]], [0, 1, 0, 1]], 131 ]; 132 } 133 134 protected function setUp(): void 135 { 136 parent::setUp(); 137 138 config_set('osu.beatmapset.minimum_days_for_rank', 1); 139 config_set('osu.beatmapset.rank_per_day', 2); 140 141 Bus::fake([BeatmapsetRank::class, CheckBeatmapsetCovers::class]); 142 } 143 144 /** 145 * @param Ruleset[] $rulesets 146 */ 147 protected function beatmapset(array $rulesets, int $qualifiedDaysAgo = 2): BeatmapsetFactory 148 { 149 $factory = Beatmapset::factory() 150 ->owner() 151 ->qualified(now()->subDays($qualifiedDaysAgo)); 152 153 foreach ($rulesets as $ruleset) { 154 $factory = $factory->has(Beatmap::factory()->ruleset($ruleset->legacyName())); 155 } 156 157 return $factory; 158 } 159}