the browser-facing portion of osu!
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\Singletons;
7
8use App\Enums\Ruleset;
9use App\Exceptions\InvariantException;
10use Tests\TestCase;
11
12class ModsTest extends TestCase
13{
14 public function testModSettings()
15 {
16 $settings = app('mods')->filterSettings(Ruleset::osu->value, 'WU', ['initial_rate' => '1']);
17
18 $this->assertSame(1.0, $settings->initial_rate);
19 }
20
21 public function testModSettingsInvalid()
22 {
23 $this->expectException(InvariantException::class);
24 app('mods')->filterSettings(Ruleset::osu->value, 'WU', ['x' => '1']);
25 }
26
27 public function testParseInputArray()
28 {
29 $input = [['acronym' => 'WU', 'settings' => []]];
30 $parsed = app('mods')->parseInputArray(Ruleset::osu->value, $input);
31
32 $this->assertSame(1, count($parsed));
33 $this->assertSame(0, count((array) $parsed[0]->settings));
34 $this->assertSame('WU', $parsed[0]->acronym);
35 }
36
37 public function testParseInputArrayInvalidMod()
38 {
39 $input = [['acronym' => 'XYZ', 'settings' => []]];
40
41 $this->expectException(InvariantException::class);
42 app('mods')->parseInputArray(Ruleset::osu->value, $input);
43 }
44
45 public function testParseInputArrayWithSettings()
46 {
47 $input = [['acronym' => 'WU', 'settings' => ['initial_rate' => '1', 'adjust_pitch' => false]]];
48 $parsed = app('mods')->parseInputArray(Ruleset::osu->value, $input);
49
50 $this->assertSame(1, count($parsed));
51 $this->assertSame(2, count((array) $parsed[0]->settings));
52 $this->assertSame(1.0, $parsed[0]->settings->initial_rate);
53 $this->assertSame(false, $parsed[0]->settings->adjust_pitch);
54 $this->assertSame('WU', $parsed[0]->acronym);
55 }
56
57 public function testParseInputArrayWithSettingsInvalid()
58 {
59 $input = [['acronym' => 'WU', 'settings' => ['x' => '1']]];
60
61 $this->expectException(InvariantException::class);
62 app('mods')->parseInputArray(Ruleset::osu->value, $input);
63 }
64
65 public function testValidateSelectionWithInvalidRuleset()
66 {
67 $this->expectException(InvariantException::class);
68 app('mods')->validateSelection(-1, []);
69 }
70
71 /**
72 * @dataProvider modComboExclusives
73 */
74 public function testAssertValidExclusivity(Ruleset $ruleset, $requiredIds, $allowedIds, $isValid)
75 {
76 if (!$isValid) {
77 $this->expectException(InvariantException::class);
78 }
79
80 $result = app('mods')->assertValidExclusivity($ruleset->value, $requiredIds, $allowedIds);
81
82 if ($isValid) {
83 $this->assertTrue($result);
84 }
85 }
86
87 /**
88 * @dataProvider modCombos
89 */
90 public function testValidateSelection(Ruleset $ruleset, $modCombo, $isValid)
91 {
92 if (!$isValid) {
93 $this->expectException(InvariantException::class);
94 }
95
96 $result = app('mods')->validateSelection($ruleset->value, $modCombo);
97
98 if ($isValid) {
99 $this->assertTrue($result);
100 }
101 }
102
103 public static function modCombos()
104 {
105 return [
106 // valid
107 [Ruleset::osu, ['HD', 'DT'], true],
108 [Ruleset::osu, ['HD', 'HR'], true],
109 [Ruleset::osu, ['HD', 'HR'], true],
110 [Ruleset::osu, ['HD', 'NC'], true],
111
112 [Ruleset::taiko, ['HD', 'NC'], true],
113 [Ruleset::taiko, ['HD', 'DT'], true],
114 [Ruleset::taiko, ['HD', 'HR'], true],
115 [Ruleset::taiko, ['HR', 'PF'], true],
116 [Ruleset::taiko, ['RD', 'SD'], true],
117
118 [Ruleset::catch, ['HD', 'HR'], true],
119 [Ruleset::catch, ['HD', 'PF'], true],
120 [Ruleset::catch, ['HD', 'SD'], true],
121 [Ruleset::catch, ['HD'], true],
122 [Ruleset::catch, ['EZ'], true],
123
124 [Ruleset::mania, ['DT', 'PF'], true],
125 [Ruleset::mania, ['NC', 'SD'], true],
126 [Ruleset::mania, ['6K', 'HD'], true],
127 [Ruleset::mania, ['4K', 'HT'], true],
128
129 // invalid
130 [Ruleset::osu, ['5K'], false],
131 [Ruleset::osu, ['DS'], false],
132 [Ruleset::osu, ['HD', 'HD'], false],
133
134 [Ruleset::taiko, ['AP'], false],
135
136 [Ruleset::catch, ['4K'], false],
137 [Ruleset::catch, ['AP'], false],
138
139 [Ruleset::mania, ['AP'], false],
140 ];
141 }
142
143 public static function modComboExclusives()
144 {
145 return [
146 // non-exclusive required mods and no allowed mods
147 [Ruleset::osu, ['HD', 'NC'], [], true],
148 [Ruleset::mania, ['DT', 'PF'], [], true],
149
150 // no conflicting exclusive required mods and allowed mods
151 [Ruleset::osu, ['HD'], ['NC'], true],
152 [Ruleset::mania, ['DT'], ['PF'], true],
153
154 // conflicting exclusive required mods
155 [Ruleset::osu, ['HT', 'DT'], [], false],
156 [Ruleset::mania, ['FI', 'HD'], [], false],
157
158 // allowed mods conflicts with exclusive required mods
159 [Ruleset::osu, ['HT'], ['DT'], false],
160 [Ruleset::taiko, ['HT'], ['DT'], false],
161 ];
162 }
163}