2022-05-15 01:39:54 +08:00
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
2022-03-27 05:43:17 +08:00
// See the LICENCE file in the repository root for full licence text.
2022-04-22 05:49:40 +08:00
using System ;
2022-04-18 02:26:16 +08:00
using System.Collections.Generic ;
2022-03-27 06:21:17 +08:00
using System.Linq ;
2022-03-27 05:43:17 +08:00
using NUnit.Framework ;
2022-04-04 02:24:32 +08:00
using osu.Framework.Allocation ;
2022-04-18 02:26:16 +08:00
using osu.Framework.Bindables ;
2022-08-15 03:35:09 +08:00
using osu.Framework.Extensions.ObjectExtensions ;
2022-03-27 05:43:17 +08:00
using osu.Framework.Graphics ;
using osu.Framework.Graphics.Containers ;
2024-05-22 21:55:53 +08:00
using osu.Framework.Input ;
2022-08-11 04:09:11 +08:00
using osu.Framework.Localisation ;
2022-03-27 06:21:17 +08:00
using osu.Framework.Testing ;
2022-04-03 23:43:13 +08:00
using osu.Framework.Utils ;
2023-12-14 16:30:04 +08:00
using osu.Game.Configuration ;
2022-03-27 06:21:17 +08:00
using osu.Game.Graphics.UserInterface ;
2023-04-30 23:23:45 +08:00
using osu.Game.Overlays ;
2022-03-27 05:43:17 +08:00
using osu.Game.Overlays.Mods ;
2022-04-18 02:26:16 +08:00
using osu.Game.Overlays.Settings ;
2022-04-04 02:24:32 +08:00
using osu.Game.Rulesets ;
2022-10-14 06:59:55 +08:00
using osu.Game.Rulesets.Catch.Mods ;
2022-04-03 23:43:13 +08:00
using osu.Game.Rulesets.Mods ;
2022-04-18 02:26:16 +08:00
using osu.Game.Rulesets.Osu ;
2022-03-27 06:21:17 +08:00
using osu.Game.Rulesets.Osu.Mods ;
2023-02-22 02:05:10 +08:00
using osu.Game.Rulesets.Taiko.Mods ;
2022-05-12 01:59:30 +08:00
using osu.Game.Tests.Mods ;
2022-05-06 17:37:50 +08:00
using osuTK ;
2022-03-27 06:21:17 +08:00
using osuTK.Input ;
2022-03-27 05:43:17 +08:00
namespace osu.Game.Tests.Visual.UserInterface
{
[TestFixture]
2022-11-24 13:32:20 +08:00
public partial class TestSceneModSelectOverlay : OsuManualInputManagerTestScene
2022-03-27 05:43:17 +08:00
{
2022-08-15 03:35:09 +08:00
protected override bool UseFreshStoragePerRun = > true ;
private RulesetStore rulesetStore = null ! ;
private TestModSelectOverlay modSelectOverlay = null ! ;
2022-04-04 02:24:32 +08:00
2023-12-14 16:30:04 +08:00
[Resolved]
private OsuConfigManager configManager { get ; set ; } = null ! ;
2022-08-15 03:35:09 +08:00
[BackgroundDependencyLoader]
private void load ( )
{
Dependencies . Cache ( rulesetStore = new RealmRulesetStore ( Realm ) ) ;
Dependencies . Cache ( Realm ) ;
}
2022-03-27 05:43:17 +08:00
2022-03-27 06:21:17 +08:00
[SetUpSteps]
public void SetUpSteps ( )
{
2022-04-04 02:24:32 +08:00
AddStep ( "clear contents" , Clear ) ;
AddStep ( "reset ruleset" , ( ) = > Ruleset . Value = rulesetStore . GetRuleset ( 0 ) ) ;
2022-04-03 23:43:13 +08:00
AddStep ( "reset mods" , ( ) = > SelectedMods . SetDefault ( ) ) ;
2023-09-11 15:52:43 +08:00
AddStep ( "set beatmap" , ( ) = > Beatmap . Value = CreateWorkingBeatmap ( new OsuRuleset ( ) . RulesetInfo ) ) ;
2022-08-16 00:44:51 +08:00
AddStep ( "set up presets" , ( ) = >
{
Realm . Write ( r = >
{
r . RemoveAll < ModPreset > ( ) ;
r . Add ( new ModPreset
{
Name = "AR0" ,
Description = "Too... many... circles..." ,
2023-07-06 12:37:42 +08:00
Ruleset = r . Find < RulesetInfo > ( OsuRuleset . SHORT_NAME ) ! ,
2022-08-16 00:44:51 +08:00
Mods = new [ ]
{
new OsuModDifficultyAdjust
{
ApproachRate = { Value = 0 }
}
}
} ) ;
2023-04-30 23:23:45 +08:00
r . Add ( new ModPreset
{
Name = "Half Time 0.5x" ,
Description = "Very slow" ,
2023-07-06 12:37:42 +08:00
Ruleset = r . Find < RulesetInfo > ( OsuRuleset . SHORT_NAME ) ! ,
2023-04-30 23:23:45 +08:00
Mods = new [ ]
{
new OsuModHalfTime
{
SpeedChange = { Value = 0.5 }
}
}
} ) ;
2022-08-16 00:44:51 +08:00
} ) ;
} ) ;
2022-03-27 06:21:17 +08:00
}
2022-03-27 05:43:17 +08:00
2022-04-04 02:24:32 +08:00
private void createScreen ( )
2022-04-03 23:43:13 +08:00
{
2022-08-15 03:35:09 +08:00
AddStep ( "create screen" , ( ) = > Child = modSelectOverlay = new TestModSelectOverlay
2022-04-04 02:24:32 +08:00
{
RelativeSizeAxes = Axes . Both ,
State = { Value = Visibility . Visible } ,
2023-09-11 15:52:43 +08:00
Beatmap = Beatmap . Value ,
2022-04-04 02:24:32 +08:00
SelectedMods = { BindTarget = SelectedMods }
} ) ;
waitForColumnLoad ( ) ;
}
2022-04-03 23:43:13 +08:00
2022-03-27 06:21:17 +08:00
[Test]
public void TestStateChange ( )
{
2022-04-03 23:43:13 +08:00
createScreen ( ) ;
2022-05-11 04:29:57 +08:00
AddStep ( "toggle state" , ( ) = > modSelectOverlay . ToggleVisibility ( ) ) ;
2022-03-27 05:43:17 +08:00
}
2022-03-27 06:21:17 +08:00
2022-04-03 23:43:13 +08:00
[Test]
public void TestPreexistingSelection ( )
{
AddStep ( "set mods" , ( ) = > SelectedMods . Value = new Mod [ ] { new OsuModAlternate ( ) , new OsuModDaycore ( ) } ) ;
createScreen ( ) ;
2022-05-11 04:29:57 +08:00
AddUntilStep ( "two panels active" , ( ) = > modSelectOverlay . ChildrenOfType < ModPanel > ( ) . Count ( panel = > panel . Active . Value ) = = 2 ) ;
2022-04-03 23:43:13 +08:00
AddAssert ( "mod multiplier correct" , ( ) = >
{
2022-04-04 14:29:03 +08:00
double multiplier = SelectedMods . Value . Aggregate ( 1d , ( m , mod ) = > m * mod . ScoreMultiplier ) ;
2024-01-31 22:50:43 +08:00
return Precision . AlmostEquals ( multiplier , modSelectOverlay . ChildrenOfType < RankingInformationDisplay > ( ) . Single ( ) . ModMultiplier . Value ) ;
2022-04-03 23:43:13 +08:00
} ) ;
assertCustomisationToggleState ( disabled : false , active : false ) ;
2022-05-11 04:29:57 +08:00
AddAssert ( "setting items created" , ( ) = > modSelectOverlay . ChildrenOfType < ISettingsItem > ( ) . Any ( ) ) ;
2022-04-03 23:43:13 +08:00
}
[Test]
public void TestExternalSelection ( )
{
createScreen ( ) ;
AddStep ( "set mods" , ( ) = > SelectedMods . Value = new Mod [ ] { new OsuModAlternate ( ) , new OsuModDaycore ( ) } ) ;
2022-05-11 04:29:57 +08:00
AddUntilStep ( "two panels active" , ( ) = > modSelectOverlay . ChildrenOfType < ModPanel > ( ) . Count ( panel = > panel . Active . Value ) = = 2 ) ;
2022-04-03 23:43:13 +08:00
AddAssert ( "mod multiplier correct" , ( ) = >
{
2022-04-04 14:29:03 +08:00
double multiplier = SelectedMods . Value . Aggregate ( 1d , ( m , mod ) = > m * mod . ScoreMultiplier ) ;
2024-01-31 22:50:43 +08:00
return Precision . AlmostEquals ( multiplier , modSelectOverlay . ChildrenOfType < RankingInformationDisplay > ( ) . Single ( ) . ModMultiplier . Value ) ;
2022-04-03 23:43:13 +08:00
} ) ;
assertCustomisationToggleState ( disabled : false , active : false ) ;
2022-05-11 04:29:57 +08:00
AddAssert ( "setting items created" , ( ) = > modSelectOverlay . ChildrenOfType < ISettingsItem > ( ) . Any ( ) ) ;
2022-04-03 23:43:13 +08:00
}
2022-04-04 00:38:23 +08:00
[Test]
public void TestRulesetChange ( )
{
createScreen ( ) ;
2022-04-04 02:24:32 +08:00
changeRuleset ( 0 ) ;
changeRuleset ( 1 ) ;
changeRuleset ( 2 ) ;
changeRuleset ( 3 ) ;
2022-04-04 00:38:23 +08:00
}
2022-04-22 05:49:40 +08:00
[Test]
public void TestIncompatibilityToggling ( )
{
createScreen ( ) ;
changeRuleset ( 0 ) ;
AddStep ( "activate DT" , ( ) = > getPanelForMod ( typeof ( OsuModDoubleTime ) ) . TriggerClick ( ) ) ;
AddAssert ( "DT active" , ( ) = > SelectedMods . Value . Single ( ) . GetType ( ) = = typeof ( OsuModDoubleTime ) ) ;
2022-05-03 05:29:30 +08:00
AddAssert ( "DT panel active" , ( ) = > getPanelForMod ( typeof ( OsuModDoubleTime ) ) . Active . Value ) ;
2022-04-22 05:49:40 +08:00
AddStep ( "activate NC" , ( ) = > getPanelForMod ( typeof ( OsuModNightcore ) ) . TriggerClick ( ) ) ;
AddAssert ( "only NC active" , ( ) = > SelectedMods . Value . Single ( ) . GetType ( ) = = typeof ( OsuModNightcore ) ) ;
2022-05-03 05:29:30 +08:00
AddAssert ( "DT panel not active" , ( ) = > ! getPanelForMod ( typeof ( OsuModDoubleTime ) ) . Active . Value ) ;
AddAssert ( "NC panel active" , ( ) = > getPanelForMod ( typeof ( OsuModNightcore ) ) . Active . Value ) ;
2022-04-22 05:49:40 +08:00
AddStep ( "activate HR" , ( ) = > getPanelForMod ( typeof ( OsuModHardRock ) ) . TriggerClick ( ) ) ;
AddAssert ( "NC+HR active" , ( ) = > SelectedMods . Value . Any ( mod = > mod . GetType ( ) = = typeof ( OsuModNightcore ) )
& & SelectedMods . Value . Any ( mod = > mod . GetType ( ) = = typeof ( OsuModHardRock ) ) ) ;
2022-05-03 05:29:30 +08:00
AddAssert ( "NC panel active" , ( ) = > getPanelForMod ( typeof ( OsuModNightcore ) ) . Active . Value ) ;
AddAssert ( "HR panel active" , ( ) = > getPanelForMod ( typeof ( OsuModHardRock ) ) . Active . Value ) ;
2022-04-22 05:49:40 +08:00
AddStep ( "activate MR" , ( ) = > getPanelForMod ( typeof ( OsuModMirror ) ) . TriggerClick ( ) ) ;
AddAssert ( "NC+MR active" , ( ) = > SelectedMods . Value . Any ( mod = > mod . GetType ( ) = = typeof ( OsuModNightcore ) )
& & SelectedMods . Value . Any ( mod = > mod . GetType ( ) = = typeof ( OsuModMirror ) ) ) ;
2022-05-03 05:29:30 +08:00
AddAssert ( "NC panel active" , ( ) = > getPanelForMod ( typeof ( OsuModNightcore ) ) . Active . Value ) ;
AddAssert ( "HR panel not active" , ( ) = > ! getPanelForMod ( typeof ( OsuModHardRock ) ) . Active . Value ) ;
AddAssert ( "MR panel active" , ( ) = > getPanelForMod ( typeof ( OsuModMirror ) ) . Active . Value ) ;
2022-04-22 05:49:40 +08:00
}
2022-04-26 05:41:40 +08:00
[Test]
public void TestDimmedState ( )
{
createScreen ( ) ;
changeRuleset ( 0 ) ;
AddUntilStep ( "any column dimmed" , ( ) = > this . ChildrenOfType < ModColumn > ( ) . Any ( column = > ! column . Active . Value ) ) ;
2022-08-15 03:35:09 +08:00
ModSelectColumn lastColumn = null ! ;
2022-04-26 05:41:40 +08:00
2022-04-27 05:11:38 +08:00
AddAssert ( "last column dimmed" , ( ) = > ! this . ChildrenOfType < ModColumn > ( ) . Last ( ) . Active . Value ) ;
AddStep ( "request scroll to last column" , ( ) = >
2022-04-26 05:41:40 +08:00
{
2022-05-11 04:29:57 +08:00
var lastDimContainer = this . ChildrenOfType < ModSelectOverlay . ColumnDimContainer > ( ) . Last ( ) ;
2022-04-27 05:11:38 +08:00
lastColumn = lastDimContainer . Column ;
lastDimContainer . RequestScroll ? . Invoke ( lastDimContainer ) ;
2022-04-26 05:41:40 +08:00
} ) ;
2022-04-27 05:11:38 +08:00
AddUntilStep ( "column undimmed" , ( ) = > lastColumn . Active . Value ) ;
2022-04-26 05:41:40 +08:00
2022-04-27 05:11:38 +08:00
AddStep ( "click panel" , ( ) = >
2022-04-26 05:41:40 +08:00
{
2022-04-27 05:11:38 +08:00
InputManager . MoveMouseTo ( lastColumn . ChildrenOfType < ModPanel > ( ) . First ( ) ) ;
2022-04-26 05:41:40 +08:00
InputManager . Click ( MouseButton . Left ) ;
} ) ;
2022-04-27 05:11:38 +08:00
AddUntilStep ( "panel selected" , ( ) = > lastColumn . ChildrenOfType < ModPanel > ( ) . First ( ) . Active . Value ) ;
2022-04-26 05:41:40 +08:00
}
2022-03-27 06:21:17 +08:00
[Test]
public void TestCustomisationToggleState ( )
{
2022-04-03 23:43:13 +08:00
createScreen ( ) ;
2022-03-27 06:21:17 +08:00
assertCustomisationToggleState ( disabled : true , active : false ) ;
AddStep ( "select customisable mod" , ( ) = > SelectedMods . Value = new [ ] { new OsuModDoubleTime ( ) } ) ;
assertCustomisationToggleState ( disabled : false , active : false ) ;
2022-08-16 01:46:17 +08:00
AddStep ( "select mod requiring configuration externally" , ( ) = > SelectedMods . Value = new [ ] { new OsuModDifficultyAdjust ( ) } ) ;
assertCustomisationToggleState ( disabled : false , active : false ) ;
AddStep ( "reset mods" , ( ) = > SelectedMods . SetDefault ( ) ) ;
AddStep ( "select difficulty adjust via panel" , ( ) = > getPanelForMod ( typeof ( OsuModDifficultyAdjust ) ) . TriggerClick ( ) ) ;
2022-03-27 06:21:17 +08:00
assertCustomisationToggleState ( disabled : false , active : true ) ;
2022-05-06 17:37:50 +08:00
AddStep ( "dismiss mod customisation via toggle" , ( ) = >
2022-03-27 06:21:17 +08:00
{
2023-06-22 14:58:05 +08:00
InputManager . MoveMouseTo ( modSelectOverlay . CustomisationButton . AsNonNull ( ) ) ;
2022-03-27 06:21:17 +08:00
InputManager . Click ( MouseButton . Left ) ;
} ) ;
2022-05-06 01:08:38 +08:00
assertCustomisationToggleState ( disabled : false , active : false ) ;
AddStep ( "reset mods" , ( ) = > SelectedMods . SetDefault ( ) ) ;
2022-08-16 01:46:17 +08:00
AddStep ( "select difficulty adjust via panel" , ( ) = > getPanelForMod ( typeof ( OsuModDifficultyAdjust ) ) . TriggerClick ( ) ) ;
2022-05-06 01:08:38 +08:00
assertCustomisationToggleState ( disabled : false , active : true ) ;
AddStep ( "dismiss mod customisation via keyboard" , ( ) = > InputManager . Key ( Key . Escape ) ) ;
assertCustomisationToggleState ( disabled : false , active : false ) ;
2022-03-27 06:21:17 +08:00
AddStep ( "append another mod not requiring config" , ( ) = > SelectedMods . Value = SelectedMods . Value . Append ( new OsuModFlashlight ( ) ) . ToArray ( ) ) ;
assertCustomisationToggleState ( disabled : false , active : false ) ;
AddStep ( "select mod without configuration" , ( ) = > SelectedMods . Value = new [ ] { new OsuModAutoplay ( ) } ) ;
assertCustomisationToggleState ( disabled : true , active : false ) ;
2022-08-16 01:46:17 +08:00
AddStep ( "select difficulty adjust via panel" , ( ) = > getPanelForMod ( typeof ( OsuModDifficultyAdjust ) ) . TriggerClick ( ) ) ;
2022-03-27 06:21:17 +08:00
assertCustomisationToggleState ( disabled : false , active : true ) ;
AddStep ( "select mod without configuration" , ( ) = > SelectedMods . Value = new [ ] { new OsuModAutoplay ( ) } ) ;
assertCustomisationToggleState ( disabled : true , active : false ) ; // config was dismissed without explicit user action.
2022-08-16 00:44:51 +08:00
AddStep ( "select mod preset with mod requiring configuration" , ( ) = >
{
InputManager . MoveMouseTo ( this . ChildrenOfType < ModPresetPanel > ( ) . First ( ) ) ;
InputManager . Click ( MouseButton . Left ) ;
} ) ;
assertCustomisationToggleState ( disabled : false , active : false ) ;
2022-03-27 06:21:17 +08:00
}
2022-05-06 17:37:50 +08:00
[Test]
public void TestDismissCustomisationViaDimmedArea ( )
{
createScreen ( ) ;
assertCustomisationToggleState ( disabled : true , active : false ) ;
2022-08-16 01:46:17 +08:00
AddStep ( "select difficulty adjust via panel" , ( ) = > getPanelForMod ( typeof ( OsuModDifficultyAdjust ) ) . TriggerClick ( ) ) ;
2022-05-06 17:37:50 +08:00
assertCustomisationToggleState ( disabled : false , active : true ) ;
AddStep ( "move mouse to settings area" , ( ) = > InputManager . MoveMouseTo ( this . ChildrenOfType < ModSettingsArea > ( ) . Single ( ) ) ) ;
AddStep ( "move mouse to dimmed area" , ( ) = >
{
InputManager . MoveMouseTo ( new Vector2 (
2022-05-11 04:29:57 +08:00
modSelectOverlay . ScreenSpaceDrawQuad . TopLeft . X ,
( modSelectOverlay . ScreenSpaceDrawQuad . TopLeft . Y + modSelectOverlay . ScreenSpaceDrawQuad . BottomLeft . Y ) / 2 ) ) ;
2022-05-06 17:37:50 +08:00
} ) ;
AddStep ( "click" , ( ) = > InputManager . Click ( MouseButton . Left ) ) ;
assertCustomisationToggleState ( disabled : false , active : false ) ;
2022-05-11 04:29:57 +08:00
AddStep ( "move mouse to first mod panel" , ( ) = > InputManager . MoveMouseTo ( modSelectOverlay . ChildrenOfType < ModPanel > ( ) . First ( ) ) ) ;
AddAssert ( "first mod panel is hovered" , ( ) = > modSelectOverlay . ChildrenOfType < ModPanel > ( ) . First ( ) . IsHovered ) ;
2022-05-06 17:37:50 +08:00
}
2022-04-18 02:26:16 +08:00
/// <summary>
/// Ensure that two mod overlays are not cross polluting via central settings instances.
/// </summary>
[Test]
public void TestSettingsNotCrossPolluting ( )
{
2022-08-15 03:35:09 +08:00
Bindable < IReadOnlyList < Mod > > selectedMods2 = null ! ;
ModSelectOverlay modSelectOverlay2 = null ! ;
2022-04-18 02:26:16 +08:00
createScreen ( ) ;
2022-08-16 01:46:17 +08:00
AddStep ( "select difficulty adjust via panel" , ( ) = > getPanelForMod ( typeof ( OsuModDifficultyAdjust ) ) . TriggerClick ( ) ) ;
2022-04-18 02:26:16 +08:00
2023-02-03 00:24:45 +08:00
AddStep ( "set setting" , ( ) = > modSelectOverlay . ChildrenOfType < RoundedSliderBar < float > > ( ) . First ( ) . Current . Value = 8 ) ;
2022-04-18 02:26:16 +08:00
AddAssert ( "ensure setting is propagated" , ( ) = > SelectedMods . Value . OfType < OsuModDifficultyAdjust > ( ) . Single ( ) . CircleSize . Value = = 8 ) ;
AddStep ( "create second bindable" , ( ) = > selectedMods2 = new Bindable < IReadOnlyList < Mod > > ( new Mod [ ] { new OsuModDifficultyAdjust ( ) } ) ) ;
AddStep ( "create second overlay" , ( ) = >
{
2022-05-12 00:05:09 +08:00
Add ( modSelectOverlay2 = new UserModSelectOverlay ( ) . With ( d = >
2022-04-18 02:26:16 +08:00
{
d . Origin = Anchor . TopCentre ;
d . Anchor = Anchor . TopCentre ;
d . SelectedMods . BindTarget = selectedMods2 ;
} ) ) ;
} ) ;
2022-05-12 00:05:09 +08:00
AddStep ( "show" , ( ) = > modSelectOverlay2 . Show ( ) ) ;
2022-04-18 02:26:16 +08:00
AddAssert ( "ensure first is unchanged" , ( ) = > SelectedMods . Value . OfType < OsuModDifficultyAdjust > ( ) . Single ( ) . CircleSize . Value = = 8 ) ;
AddAssert ( "ensure second is default" , ( ) = > selectedMods2 . Value . OfType < OsuModDifficultyAdjust > ( ) . Single ( ) . CircleSize . Value = = null ) ;
}
[Test]
public void TestSettingsResetOnDeselection ( )
{
var osuModDoubleTime = new OsuModDoubleTime { SpeedChange = { Value = 1.2 } } ;
createScreen ( ) ;
changeRuleset ( 0 ) ;
AddStep ( "set dt mod with custom rate" , ( ) = > { SelectedMods . Value = new [ ] { osuModDoubleTime } ; } ) ;
AddAssert ( "selected mod matches" , ( ) = > ( SelectedMods . Value . Single ( ) as OsuModDoubleTime ) ? . SpeedChange . Value = = 1.2 ) ;
AddStep ( "deselect" , ( ) = > getPanelForMod ( typeof ( OsuModDoubleTime ) ) . TriggerClick ( ) ) ;
AddAssert ( "selected mods empty" , ( ) = > SelectedMods . Value . Count = = 0 ) ;
AddStep ( "reselect" , ( ) = > getPanelForMod ( typeof ( OsuModDoubleTime ) ) . TriggerClick ( ) ) ;
AddAssert ( "selected mod has default value" , ( ) = > ( SelectedMods . Value . Single ( ) as OsuModDoubleTime ) ? . SpeedChange . IsDefault = = true ) ;
}
[Test]
public void TestAnimationFlushOnClose ( )
{
createScreen ( ) ;
changeRuleset ( 0 ) ;
AddStep ( "Select all fun mods" , ( ) = >
{
2022-05-11 04:29:57 +08:00
modSelectOverlay . ChildrenOfType < ModColumn > ( )
. Single ( c = > c . ModType = = ModType . DifficultyIncrease )
. SelectAll ( ) ;
2022-04-18 02:26:16 +08:00
} ) ;
AddUntilStep ( "many mods selected" , ( ) = > SelectedMods . Value . Count > = 5 ) ;
AddStep ( "trigger deselect and close overlay" , ( ) = >
{
2022-05-11 04:29:57 +08:00
modSelectOverlay . ChildrenOfType < ModColumn > ( )
. Single ( c = > c . ModType = = ModType . DifficultyIncrease )
. DeselectAll ( ) ;
2022-04-18 02:26:16 +08:00
2022-05-11 04:29:57 +08:00
modSelectOverlay . Hide ( ) ;
2022-04-18 02:26:16 +08:00
} ) ;
AddAssert ( "all mods deselected" , ( ) = > SelectedMods . Value . Count = = 0 ) ;
}
[Test]
2022-10-14 06:59:55 +08:00
public void TestCommonModsMaintainedOnRulesetChange ( )
2022-04-18 02:26:16 +08:00
{
createScreen ( ) ;
changeRuleset ( 0 ) ;
2022-10-14 06:59:55 +08:00
AddStep ( "select relax mod" , ( ) = > SelectedMods . Value = new [ ] { Ruleset . Value . CreateInstance ( ) . CreateMod < ModRelax > ( ) } ) ;
2022-04-18 02:26:16 +08:00
changeRuleset ( 0 ) ;
2022-10-14 06:59:55 +08:00
AddAssert ( "ensure mod still selected" , ( ) = > SelectedMods . Value . SingleOrDefault ( ) is OsuModRelax ) ;
2022-04-18 02:26:16 +08:00
2022-10-14 06:59:55 +08:00
changeRuleset ( 2 ) ;
AddAssert ( "catch variant selected" , ( ) = > SelectedMods . Value . SingleOrDefault ( ) is CatchModRelax ) ;
2022-04-18 02:26:16 +08:00
changeRuleset ( 3 ) ;
2022-10-14 06:59:55 +08:00
AddAssert ( "no mod selected" , ( ) = > SelectedMods . Value . Count = = 0 ) ;
}
2022-04-18 02:26:16 +08:00
2022-10-14 06:59:55 +08:00
[Test]
public void TestUncommonModsDiscardedOnRulesetChange ( )
{
createScreen ( ) ;
changeRuleset ( 0 ) ;
AddStep ( "select single tap mod" , ( ) = > SelectedMods . Value = new [ ] { new OsuModSingleTap ( ) } ) ;
2022-04-18 02:26:16 +08:00
changeRuleset ( 0 ) ;
2022-10-14 06:59:55 +08:00
AddAssert ( "ensure mod still selected" , ( ) = > SelectedMods . Value . SingleOrDefault ( ) is OsuModSingleTap ) ;
2022-04-18 02:26:16 +08:00
2022-10-14 06:59:55 +08:00
changeRuleset ( 3 ) ;
AddAssert ( "no mod selected" , ( ) = > SelectedMods . Value . Count = = 0 ) ;
2022-04-18 02:26:16 +08:00
}
2023-02-22 02:05:10 +08:00
[Test]
public void TestKeepSharedSettingsFromSimilarMods ( )
{
const float setting_change = 1.2f ;
createScreen ( ) ;
changeRuleset ( 0 ) ;
AddStep ( "select difficulty adjust mod" , ( ) = > SelectedMods . Value = new [ ] { Ruleset . Value . CreateInstance ( ) . CreateMod < ModDifficultyAdjust > ( ) ! } ) ;
changeRuleset ( 0 ) ;
AddAssert ( "ensure mod still selected" , ( ) = > SelectedMods . Value . SingleOrDefault ( ) is OsuModDifficultyAdjust ) ;
AddStep ( "change mod settings" , ( ) = >
{
2023-05-05 01:12:22 +08:00
var osuMod = getSelectedMod < OsuModDifficultyAdjust > ( ) ;
2023-02-24 22:11:22 +08:00
2023-02-22 02:05:10 +08:00
osuMod . ExtendedLimits . Value = true ;
osuMod . CircleSize . Value = setting_change ;
osuMod . DrainRate . Value = setting_change ;
osuMod . OverallDifficulty . Value = setting_change ;
osuMod . ApproachRate . Value = setting_change ;
} ) ;
changeRuleset ( 1 ) ;
AddAssert ( "taiko variant selected" , ( ) = > SelectedMods . Value . SingleOrDefault ( ) is TaikoModDifficultyAdjust ) ;
2023-05-05 01:11:51 +08:00
AddAssert ( "shared settings preserved" , ( ) = >
2023-02-22 02:05:10 +08:00
{
2023-05-05 01:12:22 +08:00
var taikoMod = getSelectedMod < TaikoModDifficultyAdjust > ( ) ;
2023-02-24 22:11:22 +08:00
return taikoMod . ExtendedLimits . Value & &
taikoMod . DrainRate . Value = = setting_change & &
taikoMod . OverallDifficulty . Value = = setting_change ;
} ) ;
2023-05-05 01:11:51 +08:00
AddAssert ( "non-shared settings remain default" , ( ) = >
2023-02-24 22:11:22 +08:00
{
2023-05-05 01:12:22 +08:00
var taikoMod = getSelectedMod < TaikoModDifficultyAdjust > ( ) ;
2023-02-24 22:11:22 +08:00
return taikoMod . ScrollSpeed . IsDefault ;
} ) ;
}
2022-04-18 02:26:16 +08:00
[Test]
public void TestExternallySetCustomizedMod ( )
{
createScreen ( ) ;
changeRuleset ( 0 ) ;
AddStep ( "set customized mod externally" , ( ) = > SelectedMods . Value = new [ ] { new OsuModDoubleTime { SpeedChange = { Value = 1.01 } } } ) ;
AddAssert ( "ensure button is selected and customized accordingly" , ( ) = >
{
var button = getPanelForMod ( SelectedMods . Value . Single ( ) . GetType ( ) ) ;
return ( ( OsuModDoubleTime ) button . Mod ) . SpeedChange . Value = = 1.01 ;
} ) ;
}
[Test]
public void TestSettingsAreRetainedOnReload ( )
{
createScreen ( ) ;
changeRuleset ( 0 ) ;
AddStep ( "set customized mod externally" , ( ) = > SelectedMods . Value = new [ ] { new OsuModDoubleTime { SpeedChange = { Value = 1.01 } } } ) ;
AddAssert ( "setting remains" , ( ) = > ( SelectedMods . Value . SingleOrDefault ( ) as OsuModDoubleTime ) ? . SpeedChange . Value = = 1.01 ) ;
createScreen ( ) ;
AddAssert ( "setting remains" , ( ) = > ( SelectedMods . Value . SingleOrDefault ( ) as OsuModDoubleTime ) ? . SpeedChange . Value = = 1.01 ) ;
}
[Test]
public void TestExternallySetModIsReplacedByOverlayInstance ( )
{
Mod external = new OsuModDoubleTime ( ) ;
2022-08-15 03:35:09 +08:00
Mod overlayButtonMod = null ! ;
2022-04-18 02:26:16 +08:00
createScreen ( ) ;
changeRuleset ( 0 ) ;
AddStep ( "set mod externally" , ( ) = > { SelectedMods . Value = new [ ] { external } ; } ) ;
AddAssert ( "ensure button is selected" , ( ) = >
{
var button = getPanelForMod ( SelectedMods . Value . Single ( ) . GetType ( ) ) ;
overlayButtonMod = button . Mod ;
return button . Active . Value ;
} ) ;
// Right now, when an external change occurs, the ModSelectOverlay will replace the global instance with its own
AddAssert ( "mod instance doesn't match" , ( ) = > external ! = overlayButtonMod ) ;
AddAssert ( "one mod present in global selected" , ( ) = > SelectedMods . Value . Count = = 1 ) ;
2022-05-04 03:44:44 +08:00
AddAssert ( "globally selected matches button's mod instance" , ( ) = > SelectedMods . Value . Any ( mod = > ReferenceEquals ( mod , overlayButtonMod ) ) ) ;
AddAssert ( "globally selected doesn't contain original external change" , ( ) = > ! SelectedMods . Value . Any ( mod = > ReferenceEquals ( mod , external ) ) ) ;
2022-04-18 02:26:16 +08:00
}
[Test]
public void TestChangeIsValidChangesButtonVisibility ( )
{
createScreen ( ) ;
changeRuleset ( 0 ) ;
2023-06-02 16:33:38 +08:00
AddAssert ( "double time visible" , ( ) = > modSelectOverlay . ChildrenOfType < ModPanel > ( ) . Where ( panel = > panel . Mod is OsuModDoubleTime ) . Any ( panel = > panel . Visible ) ) ;
2022-04-18 02:26:16 +08:00
2022-05-11 04:29:57 +08:00
AddStep ( "make double time invalid" , ( ) = > modSelectOverlay . IsValidMod = m = > ! ( m is OsuModDoubleTime ) ) ;
2023-06-02 16:33:38 +08:00
AddUntilStep ( "double time not visible" , ( ) = > modSelectOverlay . ChildrenOfType < ModPanel > ( ) . Where ( panel = > panel . Mod is OsuModDoubleTime ) . All ( panel = > ! panel . Visible ) ) ;
AddAssert ( "nightcore still visible" , ( ) = > modSelectOverlay . ChildrenOfType < ModPanel > ( ) . Where ( panel = > panel . Mod is OsuModNightcore ) . Any ( panel = > panel . Visible ) ) ;
2022-04-18 02:26:16 +08:00
2022-06-24 20:25:23 +08:00
AddStep ( "make double time valid again" , ( ) = > modSelectOverlay . IsValidMod = _ = > true ) ;
2023-06-02 16:33:38 +08:00
AddUntilStep ( "double time visible" , ( ) = > modSelectOverlay . ChildrenOfType < ModPanel > ( ) . Where ( panel = > panel . Mod is OsuModDoubleTime ) . Any ( panel = > panel . Visible ) ) ;
AddAssert ( "nightcore still visible" , ( ) = > modSelectOverlay . ChildrenOfType < ModPanel > ( ) . Where ( b = > b . Mod is OsuModNightcore ) . Any ( panel = > panel . Visible ) ) ;
2022-04-18 02:26:16 +08:00
}
[Test]
public void TestChangeIsValidPreservesSelection ( )
{
createScreen ( ) ;
changeRuleset ( 0 ) ;
AddStep ( "select DT + HD" , ( ) = > SelectedMods . Value = new Mod [ ] { new OsuModDoubleTime ( ) , new OsuModHidden ( ) } ) ;
2022-05-11 04:29:57 +08:00
AddAssert ( "DT + HD selected" , ( ) = > modSelectOverlay . ChildrenOfType < ModPanel > ( ) . Count ( panel = > panel . Active . Value ) = = 2 ) ;
2022-04-18 02:26:16 +08:00
2022-05-11 04:29:57 +08:00
AddStep ( "make NF invalid" , ( ) = > modSelectOverlay . IsValidMod = m = > ! ( m is ModNoFail ) ) ;
AddAssert ( "DT + HD still selected" , ( ) = > modSelectOverlay . ChildrenOfType < ModPanel > ( ) . Count ( panel = > panel . Active . Value ) = = 2 ) ;
2022-04-18 02:26:16 +08:00
}
[Test]
public void TestUnimplementedModIsUnselectable ( )
{
var testRuleset = new TestUnimplementedModOsuRuleset ( ) ;
createScreen ( ) ;
AddStep ( "set ruleset" , ( ) = > Ruleset . Value = testRuleset . RulesetInfo ) ;
waitForColumnLoad ( ) ;
2023-06-02 16:33:38 +08:00
AddAssert ( "unimplemented mod panel is filtered" , ( ) = > ! getPanelForMod ( typeof ( TestUnimplementedMod ) ) . Visible ) ;
2022-04-18 02:26:16 +08:00
}
2023-05-21 16:05:01 +08:00
[Test]
public void TestFirstModSelectDeselect ( )
{
createScreen ( ) ;
AddStep ( "apply search" , ( ) = > modSelectOverlay . SearchTerm = "HD" ) ;
AddStep ( "press enter" , ( ) = > InputManager . Key ( Key . Enter ) ) ;
AddAssert ( "hidden selected" , ( ) = > getPanelForMod ( typeof ( OsuModHidden ) ) . Active . Value ) ;
2024-01-16 02:05:33 +08:00
AddAssert ( "all text selected in textbox" , ( ) = >
{
var textBox = modSelectOverlay . ChildrenOfType < SearchTextBox > ( ) . Single ( ) ;
return textBox . SelectedText = = textBox . Text ;
} ) ;
2023-05-21 16:05:01 +08:00
AddStep ( "press enter again" , ( ) = > InputManager . Key ( Key . Enter ) ) ;
AddAssert ( "hidden deselected" , ( ) = > ! getPanelForMod ( typeof ( OsuModHidden ) ) . Active . Value ) ;
2024-01-16 02:07:52 +08:00
AddStep ( "apply search matching nothing" , ( ) = > modSelectOverlay . SearchTerm = "ZZZ" ) ;
AddStep ( "press enter" , ( ) = > InputManager . Key ( Key . Enter ) ) ;
AddAssert ( "all text not selected in textbox" , ( ) = >
{
var textBox = modSelectOverlay . ChildrenOfType < SearchTextBox > ( ) . Single ( ) ;
return textBox . SelectedText ! = textBox . Text ;
} ) ;
2023-05-21 16:05:01 +08:00
AddStep ( "clear search" , ( ) = > modSelectOverlay . SearchTerm = string . Empty ) ;
AddStep ( "press enter" , ( ) = > InputManager . Key ( Key . Enter ) ) ;
2023-07-27 03:49:54 +08:00
AddAssert ( "mod select hidden" , ( ) = > modSelectOverlay . State . Value = = Visibility . Hidden ) ;
2023-05-21 16:05:01 +08:00
}
2023-05-14 23:32:16 +08:00
[Test]
2023-06-05 20:54:19 +08:00
public void TestSearchFocusChangeViaClick ( )
2023-05-14 23:32:16 +08:00
{
createScreen ( ) ;
2023-06-05 20:54:19 +08:00
AddStep ( "click on search" , navigateAndClick < ShearedSearchTextBox > ) ;
AddAssert ( "focused" , ( ) = > modSelectOverlay . SearchTextBox . HasFocus ) ;
2023-06-18 21:50:25 +08:00
AddStep ( "click on mod column" , navigateAndClick < ModColumn > ) ;
AddAssert ( "lost focus" , ( ) = > ! modSelectOverlay . SearchTextBox . HasFocus ) ;
2023-05-14 23:32:16 +08:00
void navigateAndClick < T > ( ) where T : Drawable
{
2023-06-22 14:58:05 +08:00
InputManager . MoveMouseTo ( modSelectOverlay . ChildrenOfType < T > ( ) . First ( ) ) ;
2023-05-14 23:32:16 +08:00
InputManager . Click ( MouseButton . Left ) ;
}
}
2023-06-05 20:54:19 +08:00
[Test]
2023-12-14 16:30:04 +08:00
public void TestTextSearchActiveByDefault ( )
2023-06-05 20:54:19 +08:00
{
2023-12-19 21:52:16 +08:00
AddStep ( "text search starts active" , ( ) = > configManager . SetValue ( OsuSetting . ModSelectTextSearchStartsActive , true ) ) ;
2023-06-05 20:54:19 +08:00
createScreen ( ) ;
2023-12-14 16:30:04 +08:00
AddUntilStep ( "search text box focused" , ( ) = > modSelectOverlay . SearchTextBox . HasFocus ) ;
2023-06-05 20:54:19 +08:00
2023-12-14 16:30:04 +08:00
AddStep ( "press tab" , ( ) = > InputManager . Key ( Key . Tab ) ) ;
AddAssert ( "search text box unfocused" , ( ) = > ! modSelectOverlay . SearchTextBox . HasFocus ) ;
2023-06-05 20:54:19 +08:00
2023-12-14 16:30:04 +08:00
AddStep ( "press tab" , ( ) = > InputManager . Key ( Key . Tab ) ) ;
AddAssert ( "search text box focused" , ( ) = > modSelectOverlay . SearchTextBox . HasFocus ) ;
}
[Test]
public void TestTextSearchNotActiveByDefault ( )
{
2023-12-19 21:52:16 +08:00
AddStep ( "text search does not start active" , ( ) = > configManager . SetValue ( OsuSetting . ModSelectTextSearchStartsActive , false ) ) ;
2023-12-14 16:30:04 +08:00
createScreen ( ) ;
AddUntilStep ( "search text box not focused" , ( ) = > ! modSelectOverlay . SearchTextBox . HasFocus ) ;
AddStep ( "press tab" , ( ) = > InputManager . Key ( Key . Tab ) ) ;
AddAssert ( "search text box focused" , ( ) = > modSelectOverlay . SearchTextBox . HasFocus ) ;
AddStep ( "press tab" , ( ) = > InputManager . Key ( Key . Tab ) ) ;
AddAssert ( "search text box unfocused" , ( ) = > ! modSelectOverlay . SearchTextBox . HasFocus ) ;
2023-06-05 20:54:19 +08:00
}
2024-04-19 17:04:05 +08:00
[Test]
public void TestSearchBoxFocusToggleRespondsToExternalChanges ( )
{
AddStep ( "text search does not start active" , ( ) = > configManager . SetValue ( OsuSetting . ModSelectTextSearchStartsActive , false ) ) ;
createScreen ( ) ;
AddUntilStep ( "search text box not focused" , ( ) = > ! modSelectOverlay . SearchTextBox . HasFocus ) ;
AddStep ( "press tab" , ( ) = > InputManager . Key ( Key . Tab ) ) ;
AddAssert ( "search text box focused" , ( ) = > modSelectOverlay . SearchTextBox . HasFocus ) ;
2024-05-22 21:55:53 +08:00
AddStep ( "unfocus search text box externally" , ( ) = > ( ( IFocusManager ) InputManager ) . ChangeFocus ( null ) ) ;
2024-04-19 17:04:05 +08:00
AddStep ( "press tab" , ( ) = > InputManager . Key ( Key . Tab ) ) ;
AddAssert ( "search text box focused" , ( ) = > modSelectOverlay . SearchTextBox . HasFocus ) ;
}
2023-12-19 21:52:16 +08:00
[Test]
public void TestTextSearchDoesNotBlockCustomisationPanelKeyboardInteractions ( )
{
AddStep ( "text search starts active" , ( ) = > configManager . SetValue ( OsuSetting . ModSelectTextSearchStartsActive , true ) ) ;
createScreen ( ) ;
AddUntilStep ( "search text box focused" , ( ) = > modSelectOverlay . SearchTextBox . HasFocus ) ;
AddStep ( "select DT" , ( ) = > SelectedMods . Value = new Mod [ ] { new OsuModDoubleTime ( ) } ) ;
AddAssert ( "DT selected" , ( ) = > modSelectOverlay . ChildrenOfType < ModPanel > ( ) . Count ( panel = > panel . Active . Value ) , ( ) = > Is . EqualTo ( 1 ) ) ;
AddStep ( "open customisation area" , ( ) = > modSelectOverlay . CustomisationButton ! . TriggerClick ( ) ) ;
assertCustomisationToggleState ( false , true ) ;
AddStep ( "hover over mod settings slider" , ( ) = >
{
var slider = modSelectOverlay . ChildrenOfType < ModSettingsArea > ( ) . Single ( ) . ChildrenOfType < OsuSliderBar < double > > ( ) . First ( ) ;
InputManager . MoveMouseTo ( slider ) ;
} ) ;
AddStep ( "press right arrow" , ( ) = > InputManager . PressKey ( Key . Right ) ) ;
AddAssert ( "DT speed changed" , ( ) = > ! SelectedMods . Value . OfType < OsuModDoubleTime > ( ) . Single ( ) . SpeedChange . IsDefault ) ;
AddStep ( "close customisation area" , ( ) = > InputManager . PressKey ( Key . Escape ) ) ;
AddUntilStep ( "search text box reacquired focus" , ( ) = > modSelectOverlay . SearchTextBox . HasFocus ) ;
}
2022-05-15 01:39:54 +08:00
[Test]
public void TestDeselectAllViaKey ( )
{
createScreen ( ) ;
changeRuleset ( 0 ) ;
2023-06-04 22:11:04 +08:00
AddStep ( "kill search bar focus" , ( ) = > modSelectOverlay . SearchTextBox . KillFocus ( ) ) ;
2022-05-15 01:39:54 +08:00
AddStep ( "select DT + HD" , ( ) = > SelectedMods . Value = new Mod [ ] { new OsuModDoubleTime ( ) , new OsuModHidden ( ) } ) ;
AddAssert ( "DT + HD selected" , ( ) = > modSelectOverlay . ChildrenOfType < ModPanel > ( ) . Count ( panel = > panel . Active . Value ) = = 2 ) ;
2022-05-15 02:18:44 +08:00
AddStep ( "press backspace" , ( ) = > InputManager . Key ( Key . BackSpace ) ) ;
2022-05-15 01:39:54 +08:00
AddUntilStep ( "all mods deselected" , ( ) = > ! SelectedMods . Value . Any ( ) ) ;
}
2023-05-09 21:14:42 +08:00
[Test]
public void TestDeselectAllViaKey_WithSearchApplied ( )
{
createScreen ( ) ;
changeRuleset ( 0 ) ;
AddStep ( "select DT + HD" , ( ) = > SelectedMods . Value = new Mod [ ] { new OsuModDoubleTime ( ) , new OsuModHidden ( ) } ) ;
AddStep ( "focus on search" , ( ) = > modSelectOverlay . SearchTextBox . TakeFocus ( ) ) ;
AddStep ( "apply search" , ( ) = > modSelectOverlay . SearchTerm = "Easy" ) ;
2023-06-02 16:33:38 +08:00
AddAssert ( "DT + HD selected and hidden" , ( ) = > modSelectOverlay . ChildrenOfType < ModPanel > ( ) . Count ( panel = > ! panel . Visible & & panel . Active . Value ) = = 2 ) ;
2023-05-09 21:14:42 +08:00
AddStep ( "press backspace" , ( ) = > InputManager . Key ( Key . BackSpace ) ) ;
AddAssert ( "DT + HD still selected" , ( ) = > modSelectOverlay . ChildrenOfType < ModPanel > ( ) . Count ( panel = > panel . Active . Value ) = = 2 ) ;
AddAssert ( "search term changed" , ( ) = > modSelectOverlay . SearchTerm = = "Eas" ) ;
AddStep ( "kill focus" , ( ) = > modSelectOverlay . SearchTextBox . KillFocus ( ) ) ;
AddStep ( "press backspace" , ( ) = > InputManager . Key ( Key . BackSpace ) ) ;
AddUntilStep ( "all mods deselected" , ( ) = > ! SelectedMods . Value . Any ( ) ) ;
}
2022-05-07 02:54:36 +08:00
[Test]
public void TestDeselectAllViaButton ( )
{
createScreen ( ) ;
changeRuleset ( 0 ) ;
2022-05-26 04:27:54 +08:00
AddAssert ( "deselect all button disabled" , ( ) = > ! this . ChildrenOfType < DeselectAllModsButton > ( ) . Single ( ) . Enabled . Value ) ;
2022-05-26 03:49:31 +08:00
2022-05-07 02:54:36 +08:00
AddStep ( "select DT + HD" , ( ) = > SelectedMods . Value = new Mod [ ] { new OsuModDoubleTime ( ) , new OsuModHidden ( ) } ) ;
2022-05-11 04:29:57 +08:00
AddAssert ( "DT + HD selected" , ( ) = > modSelectOverlay . ChildrenOfType < ModPanel > ( ) . Count ( panel = > panel . Active . Value ) = = 2 ) ;
2022-05-26 04:27:54 +08:00
AddAssert ( "deselect all button enabled" , ( ) = > this . ChildrenOfType < DeselectAllModsButton > ( ) . Single ( ) . Enabled . Value ) ;
2022-05-07 02:54:36 +08:00
AddStep ( "click deselect all button" , ( ) = >
{
2022-05-26 04:27:54 +08:00
InputManager . MoveMouseTo ( this . ChildrenOfType < DeselectAllModsButton > ( ) . Single ( ) ) ;
2023-05-07 20:50:21 +08:00
InputManager . Click ( MouseButton . Left ) ;
} ) ;
AddUntilStep ( "all mods deselected" , ( ) = > ! SelectedMods . Value . Any ( ) ) ;
AddAssert ( "deselect all button disabled" , ( ) = > ! this . ChildrenOfType < DeselectAllModsButton > ( ) . Single ( ) . Enabled . Value ) ;
}
[Test]
public void TestDeselectAllViaButton_WithSearchApplied ( )
{
createScreen ( ) ;
changeRuleset ( 0 ) ;
AddAssert ( "deselect all button disabled" , ( ) = > ! this . ChildrenOfType < DeselectAllModsButton > ( ) . Single ( ) . Enabled . Value ) ;
AddStep ( "select DT + HD + RD" , ( ) = > SelectedMods . Value = new Mod [ ] { new OsuModDoubleTime ( ) , new OsuModHidden ( ) , new OsuModRandom ( ) } ) ;
AddAssert ( "DT + HD + RD selected" , ( ) = > modSelectOverlay . ChildrenOfType < ModPanel > ( ) . Count ( panel = > panel . Active . Value ) = = 3 ) ;
AddAssert ( "deselect all button enabled" , ( ) = > this . ChildrenOfType < DeselectAllModsButton > ( ) . Single ( ) . Enabled . Value ) ;
AddStep ( "apply search" , ( ) = > modSelectOverlay . SearchTerm = "Easy" ) ;
2023-06-02 16:33:38 +08:00
AddAssert ( "DT + HD + RD are hidden and selected" , ( ) = > modSelectOverlay . ChildrenOfType < ModPanel > ( ) . Count ( panel = > ! panel . Visible & & panel . Active . Value ) = = 3 ) ;
2023-05-07 20:50:21 +08:00
AddAssert ( "deselect all button enabled" , ( ) = > this . ChildrenOfType < DeselectAllModsButton > ( ) . Single ( ) . Enabled . Value ) ;
AddStep ( "click deselect all button" , ( ) = >
{
InputManager . MoveMouseTo ( this . ChildrenOfType < DeselectAllModsButton > ( ) . Single ( ) ) ;
2022-05-07 02:54:36 +08:00
InputManager . Click ( MouseButton . Left ) ;
} ) ;
AddUntilStep ( "all mods deselected" , ( ) = > ! SelectedMods . Value . Any ( ) ) ;
2022-05-26 04:27:54 +08:00
AddAssert ( "deselect all button disabled" , ( ) = > ! this . ChildrenOfType < DeselectAllModsButton > ( ) . Single ( ) . Enabled . Value ) ;
2022-05-07 02:54:36 +08:00
}
2022-05-07 16:23:49 +08:00
[Test]
public void TestCloseViaBackButton ( )
{
createScreen ( ) ;
changeRuleset ( 0 ) ;
2022-08-16 01:46:17 +08:00
AddStep ( "select difficulty adjust via panel" , ( ) = > getPanelForMod ( typeof ( OsuModDifficultyAdjust ) ) . TriggerClick ( ) ) ;
2022-05-07 16:23:49 +08:00
assertCustomisationToggleState ( disabled : false , active : true ) ;
2022-08-15 03:35:09 +08:00
AddAssert ( "back button disabled" , ( ) = > ! modSelectOverlay . BackButton . Enabled . Value ) ;
2022-05-07 16:23:49 +08:00
AddStep ( "dismiss customisation area" , ( ) = > InputManager . Key ( Key . Escape ) ) ;
AddStep ( "click back button" , ( ) = >
{
2022-08-15 03:35:09 +08:00
InputManager . MoveMouseTo ( modSelectOverlay . BackButton ) ;
2022-05-07 16:23:49 +08:00
InputManager . Click ( MouseButton . Left ) ;
} ) ;
2022-05-11 04:29:57 +08:00
AddAssert ( "mod select hidden" , ( ) = > modSelectOverlay . State . Value = = Visibility . Hidden ) ;
2022-05-07 16:23:49 +08:00
}
2023-05-06 17:21:32 +08:00
/// <summary>
2023-06-18 20:24:35 +08:00
/// Covers columns hiding/unhiding on changes of <see cref="ModSelectOverlay.IsValidMod"/>.
2023-05-06 17:21:32 +08:00
/// </summary>
2022-05-08 20:45:01 +08:00
[Test]
2023-06-18 20:24:35 +08:00
public void TestColumnHidingOnIsValidChange ( )
2022-05-08 20:45:01 +08:00
{
2022-08-15 03:35:09 +08:00
AddStep ( "create screen" , ( ) = > Child = modSelectOverlay = new TestModSelectOverlay
2022-05-08 20:45:01 +08:00
{
RelativeSizeAxes = Axes . Both ,
State = { Value = Visibility . Visible } ,
SelectedMods = { BindTarget = SelectedMods } ,
IsValidMod = mod = > mod . Type = = ModType . DifficultyIncrease | | mod . Type = = ModType . Conversion
} ) ;
waitForColumnLoad ( ) ;
changeRuleset ( 0 ) ;
AddAssert ( "two columns visible" , ( ) = > this . ChildrenOfType < ModColumn > ( ) . Count ( col = > col . IsPresent ) = = 2 ) ;
2022-05-11 04:29:57 +08:00
AddStep ( "unset filter" , ( ) = > modSelectOverlay . IsValidMod = _ = > true ) ;
2022-05-08 20:45:01 +08:00
AddAssert ( "all columns visible" , ( ) = > this . ChildrenOfType < ModColumn > ( ) . All ( col = > col . IsPresent ) ) ;
2022-05-11 04:29:57 +08:00
AddStep ( "filter out everything" , ( ) = > modSelectOverlay . IsValidMod = _ = > false ) ;
2022-05-08 20:45:01 +08:00
AddAssert ( "no columns visible" , ( ) = > this . ChildrenOfType < ModColumn > ( ) . All ( col = > ! col . IsPresent ) ) ;
2022-05-11 04:29:57 +08:00
AddStep ( "hide" , ( ) = > modSelectOverlay . Hide ( ) ) ;
AddStep ( "set filter for 3 columns" , ( ) = > modSelectOverlay . IsValidMod = mod = > mod . Type = = ModType . DifficultyReduction
| | mod . Type = = ModType . Automation
| | mod . Type = = ModType . Conversion ) ;
2022-05-08 20:45:01 +08:00
2022-05-11 04:29:57 +08:00
AddStep ( "show" , ( ) = > modSelectOverlay . Show ( ) ) ;
2022-05-08 20:45:01 +08:00
AddUntilStep ( "3 columns visible" , ( ) = > this . ChildrenOfType < ModColumn > ( ) . Count ( col = > col . IsPresent ) = = 3 ) ;
}
2023-05-06 17:21:32 +08:00
/// <summary>
2023-06-18 20:24:35 +08:00
/// Covers columns hiding/unhiding on changes of <see cref="ModSelectOverlay.SearchTerm"/>.
2023-05-06 17:21:32 +08:00
/// </summary>
[Test]
2023-06-18 20:24:35 +08:00
public void TestColumnHidingOnTextFilterChange ( )
2023-05-06 17:21:32 +08:00
{
AddStep ( "create screen" , ( ) = > Child = modSelectOverlay = new TestModSelectOverlay
{
RelativeSizeAxes = Axes . Both ,
State = { Value = Visibility . Visible } ,
SelectedMods = { BindTarget = SelectedMods }
} ) ;
waitForColumnLoad ( ) ;
changeRuleset ( 0 ) ;
AddAssert ( "all columns visible" , ( ) = > this . ChildrenOfType < ModColumn > ( ) . All ( col = > col . IsPresent ) ) ;
AddStep ( "set search" , ( ) = > modSelectOverlay . SearchTerm = "HD" ) ;
2024-02-22 17:56:13 +08:00
AddAssert ( "two columns visible" , ( ) = > this . ChildrenOfType < ModColumn > ( ) . Count ( col = > col . IsPresent ) = = 2 ) ;
2023-05-06 17:21:32 +08:00
AddStep ( "filter out everything" , ( ) = > modSelectOverlay . SearchTerm = "Some long search term with no matches" ) ;
AddAssert ( "no columns visible" , ( ) = > this . ChildrenOfType < ModColumn > ( ) . All ( col = > ! col . IsPresent ) ) ;
AddStep ( "clear search bar" , ( ) = > modSelectOverlay . SearchTerm = "" ) ;
AddAssert ( "all columns visible" , ( ) = > this . ChildrenOfType < ModColumn > ( ) . All ( col = > col . IsPresent ) ) ;
}
[Test]
2023-06-18 20:24:35 +08:00
public void TestHidingOverlayClearsTextSearch ( )
2023-05-06 17:21:32 +08:00
{
AddStep ( "create screen" , ( ) = > Child = modSelectOverlay = new TestModSelectOverlay
{
RelativeSizeAxes = Axes . Both ,
State = { Value = Visibility . Visible } ,
SelectedMods = { BindTarget = SelectedMods }
} ) ;
waitForColumnLoad ( ) ;
changeRuleset ( 0 ) ;
AddAssert ( "all columns visible" , ( ) = > this . ChildrenOfType < ModColumn > ( ) . All ( col = > col . IsPresent ) ) ;
AddStep ( "set search" , ( ) = > modSelectOverlay . SearchTerm = "fail" ) ;
2024-02-22 17:56:13 +08:00
AddAssert ( "one column visible" , ( ) = > this . ChildrenOfType < ModColumn > ( ) . Count ( col = > col . IsPresent ) = = 1 ) ;
2023-05-06 17:21:32 +08:00
AddStep ( "hide" , ( ) = > modSelectOverlay . Hide ( ) ) ;
AddStep ( "show" , ( ) = > modSelectOverlay . Show ( ) ) ;
AddAssert ( "all columns visible" , ( ) = > this . ChildrenOfType < ModColumn > ( ) . All ( col = > col . IsPresent ) ) ;
}
2022-05-12 01:59:30 +08:00
[Test]
public void TestColumnHidingOnRulesetChange ( )
{
createScreen ( ) ;
changeRuleset ( 0 ) ;
AddAssert ( "5 columns visible" , ( ) = > this . ChildrenOfType < ModColumn > ( ) . Count ( col = > col . IsPresent ) = = 5 ) ;
AddStep ( "change to ruleset without all mod types" , ( ) = > Ruleset . Value = TestCustomisableModRuleset . CreateTestRulesetInfo ( ) ) ;
AddUntilStep ( "1 column visible" , ( ) = > this . ChildrenOfType < ModColumn > ( ) . Count ( col = > col . IsPresent ) = = 1 ) ;
changeRuleset ( 0 ) ;
AddAssert ( "5 columns visible" , ( ) = > this . ChildrenOfType < ModColumn > ( ) . Count ( col = > col . IsPresent ) = = 5 ) ;
}
2023-04-30 23:23:45 +08:00
[Test]
public void TestModMultiplierUpdates ( )
{
createScreen ( ) ;
AddStep ( "select mod preset with half time" , ( ) = >
{
InputManager . MoveMouseTo ( this . ChildrenOfType < ModPresetPanel > ( ) . Single ( preset = > preset . Preset . Value . Name = = "Half Time 0.5x" ) ) ;
InputManager . Click ( MouseButton . Left ) ;
} ) ;
2023-12-13 16:25:56 +08:00
AddAssert ( "difficulty multiplier display shows correct value" ,
2024-01-31 22:50:43 +08:00
( ) = > modSelectOverlay . ChildrenOfType < RankingInformationDisplay > ( ) . Single ( ) . ModMultiplier . Value , ( ) = > Is . EqualTo ( 0.1 ) . Within ( Precision . DOUBLE_EPSILON ) ) ;
2023-04-30 23:23:45 +08:00
// this is highly unorthodox in a test, but because the `ModSettingChangeTracker` machinery heavily leans on events and object disposal and re-creation,
// it is instrumental in the reproduction of the failure scenario that this test is supposed to cover.
AddStep ( "force collection" , GC . Collect ) ;
AddStep ( "open customisation area" , ( ) = > modSelectOverlay . CustomisationButton ! . TriggerClick ( ) ) ;
AddStep ( "reset half time speed to default" , ( ) = > modSelectOverlay . ChildrenOfType < ModSettingsArea > ( ) . Single ( )
2023-07-13 12:46:50 +08:00
. ChildrenOfType < RevertToDefaultButton < double > > ( ) . Single ( ) . TriggerClick ( ) ) ;
2023-12-13 16:25:56 +08:00
AddUntilStep ( "difficulty multiplier display shows correct value" ,
2024-01-31 22:50:43 +08:00
( ) = > modSelectOverlay . ChildrenOfType < RankingInformationDisplay > ( ) . Single ( ) . ModMultiplier . Value , ( ) = > Is . EqualTo ( 0.3 ) . Within ( Precision . DOUBLE_EPSILON ) ) ;
2023-04-30 23:23:45 +08:00
}
2024-03-05 04:36:45 +08:00
[Test]
public void TestModSettingsOrder ( )
{
createScreen ( ) ;
AddStep ( "select DT + HD + DF" , ( ) = > SelectedMods . Value = new Mod [ ] { new OsuModDoubleTime ( ) , new OsuModHidden ( ) , new OsuModDeflate ( ) } ) ;
AddAssert ( "mod settings order: DT, HD, DF" , ( ) = >
{
var columns = this . ChildrenOfType < ModSettingsArea > ( ) . Single ( ) . ChildrenOfType < ModSettingsArea . ModSettingsColumn > ( ) ;
return columns . ElementAt ( 0 ) . Mod is OsuModDoubleTime & &
columns . ElementAt ( 1 ) . Mod is OsuModHidden & &
columns . ElementAt ( 2 ) . Mod is OsuModDeflate ;
} ) ;
AddStep ( "replace DT with NC" , ( ) = > SelectedMods . Value = SelectedMods . Value . Where ( m = > m is not ModDoubleTime ) . Append ( new OsuModNightcore ( ) ) . ToList ( ) ) ;
AddAssert ( "mod settings order: NC, HD, DF" , ( ) = >
{
var columns = this . ChildrenOfType < ModSettingsArea > ( ) . Single ( ) . ChildrenOfType < ModSettingsArea . ModSettingsColumn > ( ) ;
return columns . ElementAt ( 0 ) . Mod is OsuModNightcore & &
columns . ElementAt ( 1 ) . Mod is OsuModHidden & &
columns . ElementAt ( 2 ) . Mod is OsuModDeflate ;
} ) ;
}
2023-10-31 13:53:07 +08:00
private void waitForColumnLoad ( ) = > AddUntilStep ( "all column content loaded" , ( ) = >
modSelectOverlay . ChildrenOfType < ModColumn > ( ) . Any ( )
& & modSelectOverlay . ChildrenOfType < ModColumn > ( ) . All ( column = > column . IsLoaded & & column . ItemsLoaded )
& & modSelectOverlay . ChildrenOfType < ModPresetColumn > ( ) . Any ( )
& & modSelectOverlay . ChildrenOfType < ModPresetColumn > ( ) . All ( column = > column . IsLoaded ) ) ;
2022-04-04 02:24:32 +08:00
private void changeRuleset ( int id )
{
AddStep ( $"set ruleset to {id}" , ( ) = > Ruleset . Value = rulesetStore . GetRuleset ( id ) ) ;
waitForColumnLoad ( ) ;
}
2022-03-27 06:21:17 +08:00
private void assertCustomisationToggleState ( bool disabled , bool active )
{
2022-08-15 03:35:09 +08:00
AddAssert ( $"customisation toggle is {(disabled ? "" : " not ")}disabled" , ( ) = > modSelectOverlay . CustomisationButton . AsNonNull ( ) . Active . Disabled = = disabled ) ;
AddAssert ( $"customisation toggle is {(active ? "" : " not ")}active" , ( ) = > modSelectOverlay . CustomisationButton . AsNonNull ( ) . Active . Value = = active ) ;
2022-03-27 06:21:17 +08:00
}
2022-04-22 05:49:40 +08:00
2023-05-05 01:12:22 +08:00
private T getSelectedMod < T > ( ) where T : Mod = > SelectedMods . Value . OfType < T > ( ) . Single ( ) ;
2023-02-24 22:11:22 +08:00
2022-04-22 05:49:40 +08:00
private ModPanel getPanelForMod ( Type modType )
2022-05-11 04:29:57 +08:00
= > modSelectOverlay . ChildrenOfType < ModPanel > ( ) . Single ( panel = > panel . Mod . GetType ( ) = = modType ) ;
2022-04-18 02:26:16 +08:00
2022-11-24 13:32:20 +08:00
private partial class TestModSelectOverlay : UserModSelectOverlay
2022-08-15 03:35:09 +08:00
{
protected override bool ShowPresets = > true ;
public new ShearedButton BackButton = > base . BackButton ;
public new ShearedToggleButton ? CustomisationButton = > base . CustomisationButton ;
}
2022-04-18 02:26:16 +08:00
private class TestUnimplementedMod : Mod
{
public override string Name = > "Unimplemented mod" ;
public override string Acronym = > "UM" ;
2022-08-11 04:09:11 +08:00
public override LocalisableString Description = > "A mod that is not implemented." ;
2022-04-18 02:26:16 +08:00
public override double ScoreMultiplier = > 1 ;
public override ModType Type = > ModType . Conversion ;
}
private class TestUnimplementedModOsuRuleset : OsuRuleset
{
public override string ShortName = > "unimplemented" ;
2023-05-06 17:21:32 +08:00
public override IEnumerable < Mod > GetModsFor ( ModType type ) = >
type = = ModType . Conversion
? base . GetModsFor ( type ) . Concat ( new [ ] { new TestUnimplementedMod ( ) } )
: base . GetModsFor ( type ) ;
2022-04-18 02:26:16 +08:00
}
2022-03-27 05:43:17 +08:00
}
}