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;
9
10use App\Libraries\Search\ScoreSearch;
11use App\Models\Beatmap;
12use App\Models\BeatmapPack;
13use App\Models\BeatmapPackItem;
14use App\Models\Beatmapset;
15use App\Models\Country;
16use App\Models\Genre;
17use App\Models\Group;
18use App\Models\Language;
19use App\Models\Solo\Score;
20use App\Models\User;
21use App\Models\UserGroup;
22use App\Models\UserGroupEvent;
23use Tests\TestCase;
24
25/**
26 * @group RequiresScoreIndexer
27 */
28class BeatmapPackUserCompletionTest extends TestCase
29{
30 private static array $users;
31 private static BeatmapPack $pack;
32
33 public static function setUpBeforeClass(): void
34 {
35 parent::setUpBeforeClass();
36
37 static::withDbAccess(function () {
38 $beatmap = Beatmap::factory()->ranked()->state([
39 'playmode' => Beatmap::MODES['taiko'],
40 ])->create();
41 static::$pack = BeatmapPack::factory()->create();
42 static::$pack->items()->create(['beatmapset_id' => $beatmap->beatmapset_id]);
43
44 static::$users = [
45 'convertOsu' => User::factory()->create(),
46 'default' => User::factory()->create(),
47 'null' => null,
48 'unrelated' => User::factory()->create(),
49 ];
50
51 Score::factory()->create([
52 'beatmap_id' => $beatmap,
53 'ruleset_id' => Beatmap::MODES['osu'],
54 'preserve' => true,
55 'user_id' => static::$users['convertOsu'],
56 ]);
57 Score::factory()->create([
58 'beatmap_id' => $beatmap,
59 'preserve' => true,
60 'user_id' => static::$users['default'],
61 ]);
62
63 static::reindexScores();
64 });
65 }
66
67 public static function tearDownAfterClass(): void
68 {
69 static::withDbAccess(function () {
70 Beatmap::truncate();
71 BeatmapPack::truncate();
72 BeatmapPackItem::truncate();
73 Beatmapset::truncate();
74 Country::truncate();
75 Genre::truncate();
76 Language::truncate();
77 Score::select()->delete(); // TODO: revert to truncate after the table is actually renamed
78 User::truncate();
79 UserGroup::truncate();
80 UserGroupEvent::truncate();
81 (new ScoreSearch())->deleteAll();
82 });
83
84 parent::tearDownAfterClass();
85 }
86
87 protected $connectionsToTransact = [];
88
89 /**
90 * @dataProvider dataProviderForTestBasic
91 */
92 public function testBasic(string $userType, ?string $packRuleset, bool $completed): void
93 {
94 $user = static::$users[$userType];
95
96 $rulesetId = $packRuleset === null ? null : Beatmap::MODES[$packRuleset];
97 static::$pack->update(['playmode' => $rulesetId]);
98 static::$pack->refresh();
99
100 $data = static::$pack->userCompletionData($user, null);
101 $this->assertSame($completed ? 1 : 0, count($data['beatmapset_ids']));
102 $this->assertSame($completed, $data['completed']);
103 }
104
105 public static function dataProviderForTestBasic(): array
106 {
107 return [
108 ['convertOsu', 'osu', true],
109 ['convertOsu', 'taiko', false],
110 ['convertOsu', null, false],
111 ['default', 'osu', false],
112 ['default', 'taiko', true],
113 ['default', null, true],
114 ['null', 'osu', false],
115 ['null', 'taiko', false],
116 ['null', null, false],
117 ['unrelated', 'osu', false],
118 ['unrelated', 'taiko', false],
119 ['unrelated', null, false],
120 ];
121 }
122}