2019-05-31 13:40:53 +08:00
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
2019-01-24 16:43:03 +08:00
// See the LICENCE file in the repository root for full licence text.
2018-04-20 16:30:27 +08:00
2022-06-17 15:37:17 +08:00
#nullable disable
2019-05-07 12:02:19 +08:00
using System ;
2019-05-10 17:21:07 +08:00
using System.Collections.Generic ;
2019-04-09 14:05:03 +08:00
using System.Linq ;
2018-08-02 18:47:50 +08:00
using System.Threading ;
2019-12-06 12:47:34 +08:00
using System.Threading.Tasks ;
2019-04-09 12:50:54 +08:00
using NUnit.Framework ;
2018-04-20 16:30:27 +08:00
using osu.Framework.Allocation ;
2019-09-25 18:24:05 +08:00
using osu.Framework.Audio ;
2019-02-12 18:53:08 +08:00
using osu.Framework.Graphics ;
2019-09-25 18:24:05 +08:00
using osu.Framework.Graphics.Containers ;
2019-01-23 19:52:00 +08:00
using osu.Framework.Screens ;
2020-10-20 06:08:26 +08:00
using osu.Framework.Testing ;
2022-08-31 00:40:27 +08:00
using osu.Framework.Utils ;
2024-03-15 16:41:37 +08:00
using osu.Game.Beatmaps ;
2019-10-02 00:15:40 +08:00
using osu.Game.Configuration ;
2019-09-25 18:24:05 +08:00
using osu.Game.Overlays ;
using osu.Game.Overlays.Notifications ;
2019-04-09 14:05:03 +08:00
using osu.Game.Rulesets.Mods ;
2019-04-19 18:45:17 +08:00
using osu.Game.Rulesets.Osu ;
2019-12-06 12:47:34 +08:00
using osu.Game.Rulesets.Osu.Mods ;
2019-04-09 14:05:03 +08:00
using osu.Game.Rulesets.Scoring ;
2019-04-25 18:56:57 +08:00
using osu.Game.Scoring ;
2024-02-02 06:17:28 +08:00
using osu.Game.Screens.Menu ;
2018-04-20 16:30:27 +08:00
using osu.Game.Screens.Play ;
2019-07-05 14:50:31 +08:00
using osu.Game.Screens.Play.PlayerSettings ;
2021-04-09 07:34:35 +08:00
using osu.Game.Utils ;
2024-02-02 06:17:28 +08:00
using osuTK ;
2019-09-25 18:24:05 +08:00
using osuTK.Input ;
2018-04-20 16:30:27 +08:00
2019-03-25 00:02:36 +08:00
namespace osu.Game.Tests.Visual.Gameplay
2018-04-20 16:30:27 +08:00
{
2022-11-24 13:32:20 +08:00
public partial class TestScenePlayerLoader : ScreenTestScene
2018-04-20 16:30:27 +08:00
{
2019-07-05 14:50:31 +08:00
private TestPlayerLoader loader ;
2019-09-25 18:24:05 +08:00
private TestPlayer player ;
2024-03-15 16:46:18 +08:00
private bool? epilepsyWarning ;
private BeatmapOnlineStatus ? onlineStatus ;
2020-07-21 16:48:11 +08:00
2019-09-25 18:24:05 +08:00
[Resolved]
private AudioManager audioManager { get ; set ; }
2019-10-02 00:15:40 +08:00
[Resolved]
private SessionStatics sessionStatics { get ; set ; }
2023-04-06 02:53:54 +08:00
[Resolved]
private OsuConfigManager config { get ; set ; }
2022-04-19 05:18:10 +08:00
[Cached(typeof(INotificationOverlay))]
2020-11-16 22:53:54 +08:00
private readonly NotificationOverlay notificationOverlay ;
[Cached]
private readonly VolumeOverlay volumeOverlay ;
2024-02-02 06:17:28 +08:00
[Cached]
private readonly OsuLogo logo ;
2021-04-12 22:52:12 +08:00
[Cached(typeof(BatteryInfo))]
private readonly LocalBatteryInfo batteryInfo = new LocalBatteryInfo ( ) ;
2021-04-09 07:34:35 +08:00
2020-11-16 22:53:54 +08:00
private readonly ChangelogOverlay changelogOverlay ;
2022-08-16 12:35:57 +08:00
private double savedTrackVolume ;
private double savedMasterVolume ;
private bool savedMutedState ;
2020-11-16 22:53:54 +08:00
public TestScenePlayerLoader ( )
{
AddRange ( new Drawable [ ]
{
notificationOverlay = new NotificationOverlay
{
Anchor = Anchor . TopRight ,
Origin = Anchor . TopRight ,
} ,
volumeOverlay = new VolumeOverlay
{
Anchor = Anchor . TopLeft ,
Origin = Anchor . TopLeft ,
} ,
2024-02-02 06:17:28 +08:00
changelogOverlay = new ChangelogOverlay ( ) ,
logo = new OsuLogo
{
Anchor = Anchor . BottomRight ,
Origin = Anchor . BottomRight ,
Scale = new Vector2 ( 0.5f ) ,
Position = new Vector2 ( 128f ) ,
} ,
2020-11-16 22:53:54 +08:00
} ) ;
}
[SetUp]
2024-03-15 16:46:18 +08:00
public void Setup ( ) = > Schedule ( ( ) = >
{
player = null ;
epilepsyWarning = null ;
onlineStatus = null ;
} ) ;
2020-11-16 22:53:54 +08:00
2022-08-31 00:40:27 +08:00
[SetUpSteps]
public override void SetUpSteps ( )
{
base . SetUpSteps ( ) ;
AddStep ( "read all notifications" , ( ) = >
{
notificationOverlay . Show ( ) ;
notificationOverlay . Hide ( ) ;
} ) ;
AddUntilStep ( "wait for no notifications" , ( ) = > notificationOverlay . UnreadCount . Value , ( ) = > Is . EqualTo ( 0 ) ) ;
}
2019-09-25 18:24:05 +08:00
/// <summary>
/// Sets the input manager child to a new test player loader container instance.
/// </summary>
/// <param name="interactive">If the test player should behave like the production one.</param>
/// <param name="beforeLoadAction">An action to run before player load but after bindable leases are returned.</param>
2020-11-16 22:53:54 +08:00
private void resetPlayer ( bool interactive , Action beforeLoadAction = null )
2019-02-25 21:05:49 +08:00
{
2019-09-25 18:24:05 +08:00
beforeLoadAction ? . Invoke ( ) ;
2020-08-13 11:59:00 +08:00
2021-05-26 18:08:00 +08:00
prepareBeatmap ( ) ;
LoadScreen ( loader = new TestPlayerLoader ( ( ) = > player = new TestPlayer ( interactive , interactive ) ) ) ;
}
private void prepareBeatmap ( )
{
2021-11-15 17:46:11 +08:00
var workingBeatmap = CreateWorkingBeatmap ( new OsuRuleset ( ) . RulesetInfo ) ;
2022-08-16 13:17:28 +08:00
// Add intro time to test quick retry skipping (TestQuickRetry).
workingBeatmap . BeatmapInfo . AudioLeadIn = 60000 ;
2024-03-15 16:41:37 +08:00
// Set up data for testing disclaimer display.
2024-03-15 16:46:18 +08:00
workingBeatmap . BeatmapInfo . EpilepsyWarning = epilepsyWarning ? ? false ;
workingBeatmap . BeatmapInfo . Status = onlineStatus ? ? BeatmapOnlineStatus . Ranked ;
2022-08-16 13:17:28 +08:00
2021-11-15 17:46:11 +08:00
Beatmap . Value = workingBeatmap ;
2019-09-25 18:24:05 +08:00
2019-12-13 20:45:38 +08:00
foreach ( var mod in SelectedMods . Value . OfType < IApplicableToTrack > ( ) )
2019-12-09 16:34:04 +08:00
mod . ApplyToTrack ( Beatmap . Value . Track ) ;
2019-09-25 18:24:05 +08:00
}
2019-02-25 21:05:49 +08:00
2020-08-13 12:05:00 +08:00
[Test]
public void TestEarlyExitBeforePlayerConstruction ( )
{
2020-11-16 22:53:54 +08:00
AddStep ( "load dummy beatmap" , ( ) = > resetPlayer ( false , ( ) = > SelectedMods . Value = new [ ] { new OsuModNightcore ( ) } ) ) ;
2020-08-13 12:05:00 +08:00
AddUntilStep ( "wait for current" , ( ) = > loader . IsCurrentScreen ( ) ) ;
AddStep ( "exit loader" , ( ) = > loader . Exit ( ) ) ;
AddUntilStep ( "wait for not current" , ( ) = > ! loader . IsCurrentScreen ( ) ) ;
AddAssert ( "player did not load" , ( ) = > player = = null ) ;
AddUntilStep ( "player disposed" , ( ) = > loader . DisposalTask = = null ) ;
AddAssert ( "mod rate still applied" , ( ) = > Beatmap . Value . Track . Rate ! = 1 ) ;
2019-09-25 18:24:05 +08:00
}
2019-02-25 21:05:49 +08:00
2019-12-06 12:47:34 +08:00
/// <summary>
/// When <see cref="PlayerLoader"/> exits early, it has to wait for the player load task
/// to complete before running disposal on player. This previously caused an issue where mod
/// speed adjustments were undone too late, causing cross-screen pollution.
/// </summary>
[Test]
2020-08-13 12:05:00 +08:00
public void TestEarlyExitAfterPlayerConstruction ( )
2019-12-06 12:47:34 +08:00
{
2020-11-16 22:53:54 +08:00
AddStep ( "load dummy beatmap" , ( ) = > resetPlayer ( false , ( ) = > SelectedMods . Value = new [ ] { new OsuModNightcore ( ) } ) ) ;
2019-12-06 12:47:34 +08:00
AddUntilStep ( "wait for current" , ( ) = > loader . IsCurrentScreen ( ) ) ;
AddAssert ( "mod rate applied" , ( ) = > Beatmap . Value . Track . Rate ! = 1 ) ;
2020-08-13 12:05:00 +08:00
AddUntilStep ( "wait for non-null player" , ( ) = > player ! = null ) ;
2019-12-06 12:47:34 +08:00
AddStep ( "exit loader" , ( ) = > loader . Exit ( ) ) ;
AddUntilStep ( "wait for not current" , ( ) = > ! loader . IsCurrentScreen ( ) ) ;
AddAssert ( "player did not load" , ( ) = > ! player . IsLoaded ) ;
AddUntilStep ( "player disposed" , ( ) = > loader . DisposalTask ? . IsCompleted = = true ) ;
AddAssert ( "mod rate still applied" , ( ) = > Beatmap . Value . Track . Rate ! = 1 ) ;
}
2019-07-05 14:50:31 +08:00
[Test]
public void TestBlockLoadViaMouseMovement ( )
{
2020-11-16 22:53:54 +08:00
AddStep ( "load dummy beatmap" , ( ) = > resetPlayer ( false ) ) ;
2019-07-06 14:25:53 +08:00
AddUntilStep ( "wait for current" , ( ) = > loader . IsCurrentScreen ( ) ) ;
2020-02-14 18:02:11 +08:00
AddUntilStep ( "wait for load ready" , ( ) = >
{
moveMouse ( ) ;
2020-08-13 11:53:37 +08:00
return player ? . LoadState = = LoadState . Ready ;
2020-02-14 18:02:11 +08:00
} ) ;
2022-08-16 12:35:57 +08:00
2020-02-14 18:02:11 +08:00
AddRepeatStep ( "move mouse" , moveMouse , 20 ) ;
AddAssert ( "loader still active" , ( ) = > loader . IsCurrentScreen ( ) ) ;
AddUntilStep ( "loads after idle" , ( ) = > ! loader . IsCurrentScreen ( ) ) ;
void moveMouse ( )
{
2022-08-16 12:35:57 +08:00
notificationOverlay . State . Value = Visibility . Hidden ;
2020-02-14 18:02:11 +08:00
InputManager . MoveMouseTo (
loader . VisualSettings . ScreenSpaceDrawQuad . TopLeft
+ ( loader . VisualSettings . ScreenSpaceDrawQuad . BottomRight - loader . VisualSettings . ScreenSpaceDrawQuad . TopLeft )
* RNG . NextSingle ( ) ) ;
}
}
[Test]
public void TestBlockLoadViaFocus ( )
{
2020-11-16 22:53:54 +08:00
AddStep ( "load dummy beatmap" , ( ) = > resetPlayer ( false ) ) ;
2020-02-14 18:02:11 +08:00
AddUntilStep ( "wait for current" , ( ) = > loader . IsCurrentScreen ( ) ) ;
2020-11-16 22:53:54 +08:00
AddStep ( "show focused overlay" , ( ) = > changelogOverlay . Show ( ) ) ;
AddUntilStep ( "overlay visible" , ( ) = > changelogOverlay . IsPresent ) ;
2020-02-14 18:02:11 +08:00
2020-11-16 22:53:54 +08:00
AddUntilStep ( "wait for load ready" , ( ) = > player ? . LoadState = = LoadState . Ready ) ;
2020-02-14 18:02:11 +08:00
AddRepeatStep ( "twiddle thumbs" , ( ) = > { } , 20 ) ;
2019-07-05 14:50:31 +08:00
AddAssert ( "loader still active" , ( ) = > loader . IsCurrentScreen ( ) ) ;
2020-02-14 18:02:11 +08:00
2020-11-16 22:53:54 +08:00
AddStep ( "hide overlay" , ( ) = > changelogOverlay . Hide ( ) ) ;
2019-07-05 14:50:31 +08:00
AddUntilStep ( "loads after idle" , ( ) = > ! loader . IsCurrentScreen ( ) ) ;
}
2024-02-02 06:17:28 +08:00
[Test]
public void TestLoadNotBlockedOnOsuLogo ( )
{
AddStep ( "load dummy beatmap" , ( ) = > resetPlayer ( false ) ) ;
AddUntilStep ( "wait for current" , ( ) = > loader . IsCurrentScreen ( ) ) ;
AddUntilStep ( "wait for load ready" , ( ) = >
{
moveMouse ( ) ;
return player ? . LoadState = = LoadState . Ready ;
} ) ;
// move mouse in logo while waiting for load to still proceed (it shouldn't be blocked when hovering logo).
AddUntilStep ( "move mouse in logo" , ( ) = >
{
moveMouse ( ) ;
return ! loader . IsCurrentScreen ( ) ;
} ) ;
void moveMouse ( )
{
notificationOverlay . State . Value = Visibility . Hidden ;
InputManager . MoveMouseTo (
logo . ScreenSpaceDrawQuad . TopLeft
+ ( logo . ScreenSpaceDrawQuad . BottomRight - logo . ScreenSpaceDrawQuad . TopLeft )
* RNG . NextSingle ( 0.3f , 0.7f ) ) ;
}
}
2019-04-09 12:50:54 +08:00
[Test]
public void TestLoadContinuation ( )
2018-04-20 16:30:27 +08:00
{
2019-05-07 12:02:19 +08:00
SlowLoadPlayer slowPlayer = null ;
2021-05-26 18:08:00 +08:00
AddStep ( "load slow dummy beatmap" , ( ) = >
{
prepareBeatmap ( ) ;
2021-05-26 21:24:51 +08:00
slowPlayer = new SlowLoadPlayer ( false , false ) ;
LoadScreen ( loader = new TestPlayerLoader ( ( ) = > slowPlayer ) ) ;
2021-05-26 18:08:00 +08:00
} ) ;
2021-05-26 17:58:18 +08:00
AddStep ( "schedule slow load" , ( ) = > Scheduler . AddDelayed ( ( ) = > slowPlayer . AllowLoad . Set ( ) , 5000 ) ) ;
2018-08-02 18:47:50 +08:00
2019-05-07 12:02:19 +08:00
AddUntilStep ( "wait for player to be current" , ( ) = > slowPlayer . IsCurrentScreen ( ) ) ;
2018-08-02 18:47:50 +08:00
}
2019-04-09 14:05:03 +08:00
[Test]
public void TestModReinstantiation ( )
{
TestMod gameMod = null ;
TestMod playerMod1 = null ;
TestMod playerMod2 = null ;
2020-11-16 22:53:54 +08:00
AddStep ( "load player" , ( ) = > { resetPlayer ( true , ( ) = > SelectedMods . Value = new [ ] { gameMod = new TestMod ( ) } ) ; } ) ;
2019-04-09 14:05:03 +08:00
2019-04-19 18:45:17 +08:00
AddUntilStep ( "wait for loader to become current" , ( ) = > loader . IsCurrentScreen ( ) ) ;
AddStep ( "mouse in centre" , ( ) = > InputManager . MoveMouseTo ( loader . ScreenSpaceDrawQuad . Centre ) ) ;
AddUntilStep ( "wait for player to be current" , ( ) = > player . IsCurrentScreen ( ) ) ;
2021-10-07 14:00:37 +08:00
AddStep ( "retrieve mods" , ( ) = > playerMod1 = ( TestMod ) player . GameplayState . Mods . Single ( ) ) ;
2019-04-09 14:05:03 +08:00
AddAssert ( "game mods not applied" , ( ) = > gameMod . Applied = = false ) ;
AddAssert ( "player mods applied" , ( ) = > playerMod1 . Applied ) ;
AddStep ( "restart player" , ( ) = >
{
2019-04-19 18:45:17 +08:00
var lastPlayer = player ;
2019-04-09 14:05:03 +08:00
player = null ;
2019-04-19 18:45:17 +08:00
lastPlayer . Restart ( ) ;
2019-04-09 14:05:03 +08:00
} ) ;
2019-04-19 18:45:17 +08:00
AddUntilStep ( "wait for player to be current" , ( ) = > player . IsCurrentScreen ( ) ) ;
2021-10-07 14:00:37 +08:00
AddStep ( "retrieve mods" , ( ) = > playerMod2 = ( TestMod ) player . GameplayState . Mods . Single ( ) ) ;
2019-04-09 14:05:03 +08:00
AddAssert ( "game mods not applied" , ( ) = > gameMod . Applied = = false ) ;
AddAssert ( "player has different mods" , ( ) = > playerMod1 ! = playerMod2 ) ;
AddAssert ( "player mods applied" , ( ) = > playerMod2 . Applied ) ;
}
2020-01-09 02:55:35 +08:00
[Test]
public void TestModDisplayChanges ( )
{
var testMod = new TestMod ( ) ;
2020-11-16 22:53:54 +08:00
AddStep ( "load player" , ( ) = > resetPlayer ( true ) ) ;
2020-01-09 02:55:35 +08:00
AddUntilStep ( "wait for loader to become current" , ( ) = > loader . IsCurrentScreen ( ) ) ;
AddStep ( "set test mod in loader" , ( ) = > loader . Mods . Value = new [ ] { testMod } ) ;
AddAssert ( "test mod is displayed" , ( ) = > ( TestMod ) loader . DisplayedMods . Single ( ) = = testMod ) ;
}
2019-09-25 18:24:05 +08:00
[Test]
2024-02-16 15:52:27 +08:00
public void TestMutedNotificationLowMusicVolume ( )
2020-02-14 18:27:32 +08:00
{
2024-02-02 18:48:57 +08:00
addVolumeSteps ( "master and music volumes" , ( ) = >
2024-02-01 07:47:47 +08:00
{
2024-02-16 16:17:54 +08:00
audioManager . Volume . Value = 0.6 ;
2024-02-16 07:56:09 +08:00
audioManager . VolumeTrack . Value = 0.01 ;
2024-02-16 16:17:54 +08:00
} , ( ) = > Precision . AlmostEquals ( audioManager . Volume . Value , 0.6 ) & & Precision . AlmostEquals ( audioManager . VolumeTrack . Value , 0.5 ) ) ;
2020-02-14 18:27:32 +08:00
}
2019-09-26 20:05:43 +08:00
[Test]
2024-02-01 07:47:47 +08:00
public void TestMutedNotificationLowMasterVolume ( )
2020-02-14 18:27:32 +08:00
{
2024-02-02 18:48:57 +08:00
addVolumeSteps ( "master and music volumes" , ( ) = >
2024-02-01 07:47:47 +08:00
{
audioManager . Volume . Value = 0.01 ;
2024-02-16 16:17:54 +08:00
audioManager . VolumeTrack . Value = 0.6 ;
} , ( ) = > Precision . AlmostEquals ( audioManager . Volume . Value , 0.5 ) & & Precision . AlmostEquals ( audioManager . VolumeTrack . Value , 0.6 ) ) ;
2020-02-14 18:27:32 +08:00
}
2019-09-26 20:05:43 +08:00
[Test]
2020-02-14 18:27:32 +08:00
public void TestMutedNotificationMuteButton ( )
{
2021-12-08 12:37:46 +08:00
addVolumeSteps ( "mute button" , ( ) = >
{
// Importantly, in the case the volume is muted but the user has a volume level set, it should be retained.
2024-02-16 15:52:27 +08:00
audioManager . Volume . Value = 0.5 ;
audioManager . VolumeTrack . Value = 0.5 ;
2021-12-08 12:37:46 +08:00
volumeOverlay . IsMuted . Value = true ;
2024-02-16 15:52:27 +08:00
} , ( ) = > ! volumeOverlay . IsMuted . Value & & audioManager . Volume . Value = = 0.5 & & audioManager . VolumeTrack . Value = = 0.5 ) ;
2020-02-14 18:27:32 +08:00
}
2019-09-26 20:05:43 +08:00
/// <remarks>
/// Created for avoiding copy pasting code for the same steps.
/// </remarks>
/// <param name="volumeName">What part of the volume system is checked</param>
/// <param name="beforeLoad">The action to be invoked to set the volume before loading</param>
/// <param name="assert">The function to be invoked and checked</param>
2020-08-13 11:59:00 +08:00
private void addVolumeSteps ( string volumeName , Action beforeLoad , Func < bool > assert )
2019-09-25 18:24:05 +08:00
{
2019-10-02 00:15:40 +08:00
AddStep ( "reset notification lock" , ( ) = > sessionStatics . GetBindable < bool > ( Static . MutedAudioNotificationShownOnce ) . Value = false ) ;
2019-09-25 18:24:05 +08:00
2020-11-16 22:53:54 +08:00
AddStep ( "load player" , ( ) = > resetPlayer ( false , beforeLoad ) ) ;
2020-08-13 11:53:37 +08:00
AddUntilStep ( "wait for player" , ( ) = > player ? . LoadState = = LoadState . Ready ) ;
2019-09-25 18:24:05 +08:00
2022-08-16 12:35:57 +08:00
saveVolumes ( ) ;
2022-08-31 00:40:27 +08:00
AddAssert ( "check for notification" , ( ) = > notificationOverlay . UnreadCount . Value , ( ) = > Is . EqualTo ( 1 ) ) ;
2019-09-25 18:24:05 +08:00
2022-09-06 22:36:27 +08:00
clickNotification ( ) ;
2019-09-25 18:24:05 +08:00
2019-09-26 20:05:43 +08:00
AddAssert ( "check " + volumeName , assert ) ;
2020-02-14 18:27:32 +08:00
2022-08-16 12:35:57 +08:00
restoreVolumes ( ) ;
2020-02-14 18:27:32 +08:00
AddUntilStep ( "wait for player load" , ( ) = > player . IsLoaded ) ;
2019-09-25 18:24:05 +08:00
}
2020-07-21 16:48:11 +08:00
[TestCase(true)]
[TestCase(false)]
public void TestEpilepsyWarning ( bool warning )
{
2022-08-16 12:35:57 +08:00
saveVolumes ( ) ;
setFullVolume ( ) ;
2023-04-06 02:53:54 +08:00
AddStep ( "enable storyboards" , ( ) = > config . SetValue ( OsuSetting . ShowStoryboard , true ) ) ;
2020-10-20 05:53:41 +08:00
AddStep ( "change epilepsy warning" , ( ) = > epilepsyWarning = warning ) ;
2020-11-16 22:53:54 +08:00
AddStep ( "load dummy beatmap" , ( ) = > resetPlayer ( false ) ) ;
2020-10-20 06:08:26 +08:00
2020-07-21 16:48:11 +08:00
AddUntilStep ( "wait for current" , ( ) = > loader . IsCurrentScreen ( ) ) ;
2020-10-20 06:08:26 +08:00
2024-03-15 16:27:33 +08:00
AddAssert ( $"epilepsy warning {(warning ? " present " : " absent ")}" , ( ) = > this . ChildrenOfType < PlayerLoaderDisclaimer > ( ) . Count ( ) , ( ) = > Is . EqualTo ( warning ? 1 : 0 ) ) ;
2022-08-16 12:35:57 +08:00
restoreVolumes ( ) ;
}
2023-04-06 02:56:50 +08:00
[Test]
public void TestEpilepsyWarningWithDisabledStoryboard ( )
{
saveVolumes ( ) ;
setFullVolume ( ) ;
AddStep ( "disable storyboards" , ( ) = > config . SetValue ( OsuSetting . ShowStoryboard , false ) ) ;
AddStep ( "change epilepsy warning" , ( ) = > epilepsyWarning = true ) ;
AddStep ( "load dummy beatmap" , ( ) = > resetPlayer ( false ) ) ;
AddUntilStep ( "wait for current" , ( ) = > loader . IsCurrentScreen ( ) ) ;
2024-03-15 16:27:33 +08:00
AddUntilStep ( "epilepsy warning absent" , ( ) = > this . ChildrenOfType < PlayerLoaderDisclaimer > ( ) . Single ( ) . Alpha , ( ) = > Is . Zero ) ;
2022-08-16 12:35:57 +08:00
restoreVolumes ( ) ;
2020-10-21 00:27:03 +08:00
}
2024-03-15 16:41:37 +08:00
[TestCase(BeatmapOnlineStatus.Loved, 1)]
[TestCase(BeatmapOnlineStatus.Qualified, 1)]
[TestCase(BeatmapOnlineStatus.Graveyard, 0)]
public void TestStatusWarning ( BeatmapOnlineStatus status , int expectedDisclaimerCount )
{
saveVolumes ( ) ;
setFullVolume ( ) ;
AddStep ( "enable storyboards" , ( ) = > config . SetValue ( OsuSetting . ShowStoryboard , true ) ) ;
AddStep ( "disable epilepsy warning" , ( ) = > epilepsyWarning = false ) ;
AddStep ( "set beatmap status" , ( ) = > onlineStatus = status ) ;
AddStep ( "load dummy beatmap" , ( ) = > resetPlayer ( false ) ) ;
AddUntilStep ( "wait for current" , ( ) = > loader . IsCurrentScreen ( ) ) ;
AddAssert ( $"disclaimer count is {expectedDisclaimerCount}" , ( ) = > this . ChildrenOfType < PlayerLoaderDisclaimer > ( ) . Count ( ) , ( ) = > Is . EqualTo ( expectedDisclaimerCount ) ) ;
restoreVolumes ( ) ;
}
[Test]
public void TestCombinedWarnings ( )
{
saveVolumes ( ) ;
setFullVolume ( ) ;
AddStep ( "enable storyboards" , ( ) = > config . SetValue ( OsuSetting . ShowStoryboard , true ) ) ;
AddStep ( "disable epilepsy warning" , ( ) = > epilepsyWarning = true ) ;
AddStep ( "set beatmap status" , ( ) = > onlineStatus = BeatmapOnlineStatus . Loved ) ;
AddStep ( "load dummy beatmap" , ( ) = > resetPlayer ( false ) ) ;
AddUntilStep ( "wait for current" , ( ) = > loader . IsCurrentScreen ( ) ) ;
2024-03-15 18:26:48 +08:00
AddAssert ( "disclaimer count is 2" , ( ) = > this . ChildrenOfType < PlayerLoaderDisclaimer > ( ) . Count ( ) , ( ) = > Is . EqualTo ( 2 ) ) ;
2024-03-15 16:41:37 +08:00
restoreVolumes ( ) ;
}
2022-07-30 20:26:19 +08:00
[TestCase(true, 1.0, false)] // on battery, above cutoff --> no warning
[TestCase(false, 0.1, false)] // not on battery, below cutoff --> no warning
[TestCase(true, 0.25, true)] // on battery, at cutoff --> warning
[TestCase(true, null, false)] // on battery, level unknown --> no warning
public void TestLowBatteryNotification ( bool onBattery , double? chargeLevel , bool shouldWarn )
2021-04-09 07:34:35 +08:00
{
2021-04-10 05:55:41 +08:00
AddStep ( "reset notification lock" , ( ) = > sessionStatics . GetBindable < bool > ( Static . LowBatteryNotificationShownOnce ) . Value = false ) ;
2021-04-09 07:34:35 +08:00
// set charge status and level
2021-04-09 08:28:23 +08:00
AddStep ( "load player" , ( ) = > resetPlayer ( false , ( ) = >
2021-04-09 08:38:16 +08:00
{
2022-07-30 20:26:19 +08:00
batteryInfo . SetOnBattery ( onBattery ) ;
2021-04-12 22:52:12 +08:00
batteryInfo . SetChargeLevel ( chargeLevel ) ;
2021-04-09 08:28:23 +08:00
} ) ) ;
2021-04-09 07:34:35 +08:00
AddUntilStep ( "wait for player" , ( ) = > player ? . LoadState = = LoadState . Ready ) ;
2022-09-06 22:36:27 +08:00
if ( shouldWarn )
clickNotification ( ) ;
else
AddAssert ( "notification not triggered" , ( ) = > notificationOverlay . UnreadCount . Value = = 0 ) ;
2021-04-09 07:34:35 +08:00
AddUntilStep ( "wait for player load" , ( ) = > player . IsLoaded ) ;
}
2022-08-16 12:35:57 +08:00
private void restoreVolumes ( )
2020-10-21 00:27:03 +08:00
{
2022-08-16 12:35:57 +08:00
AddStep ( "restore previous volumes" , ( ) = >
{
audioManager . VolumeTrack . Value = savedTrackVolume ;
audioManager . Volume . Value = savedMasterVolume ;
volumeOverlay . IsMuted . Value = savedMutedState ;
} ) ;
}
2021-10-18 12:30:24 +08:00
2022-08-16 12:35:57 +08:00
private void setFullVolume ( )
{
AddStep ( "set volumes to 100%" , ( ) = >
{
audioManager . VolumeTrack . Value = 1 ;
audioManager . Volume . Value = 1 ;
volumeOverlay . IsMuted . Value = false ;
} ) ;
}
2020-10-21 00:27:03 +08:00
2022-08-16 12:35:57 +08:00
private void saveVolumes ( )
{
AddStep ( "save previous volumes" , ( ) = >
{
savedTrackVolume = audioManager . VolumeTrack . Value ;
savedMasterVolume = audioManager . Volume . Value ;
savedMutedState = volumeOverlay . IsMuted . Value ;
} ) ;
2020-07-21 16:48:11 +08:00
}
2020-10-21 00:27:03 +08:00
[Test]
2022-08-09 03:12:38 +08:00
public void TestQuickRetry ( )
2020-10-21 00:27:03 +08:00
{
2022-08-16 13:17:28 +08:00
TestPlayer getCurrentPlayer ( ) = > loader . CurrentPlayer as TestPlayer ;
bool checkSkipButtonVisible ( ) = > player . ChildrenOfType < SkipOverlay > ( ) . FirstOrDefault ( ) ? . IsButtonVisible = = true ;
TestPlayer previousPlayer = null ;
2020-11-16 22:53:54 +08:00
AddStep ( "load dummy beatmap" , ( ) = > resetPlayer ( false ) ) ;
2020-10-21 00:27:03 +08:00
2022-08-16 13:17:28 +08:00
AddUntilStep ( "wait for current" , ( ) = > getCurrentPlayer ( ) ? . IsCurrentScreen ( ) = = true ) ;
AddStep ( "store previous player" , ( ) = > previousPlayer = getCurrentPlayer ( ) ) ;
2020-10-21 00:27:03 +08:00
2022-08-16 13:17:28 +08:00
AddStep ( "Restart map normally" , ( ) = > getCurrentPlayer ( ) . Restart ( ) ) ;
AddUntilStep ( "wait for load" , ( ) = > getCurrentPlayer ( ) ? . LoadedBeatmapSuccessfully = = true ) ;
2021-10-18 12:30:24 +08:00
2022-08-16 13:17:28 +08:00
AddUntilStep ( "restart completed" , ( ) = > getCurrentPlayer ( ) ! = null & & getCurrentPlayer ( ) ! = previousPlayer ) ;
AddStep ( "store previous player" , ( ) = > previousPlayer = getCurrentPlayer ( ) ) ;
2020-10-21 00:27:03 +08:00
2022-08-16 13:17:28 +08:00
AddUntilStep ( "skip button visible" , checkSkipButtonVisible ) ;
AddStep ( "press quick retry key" , ( ) = > InputManager . PressKey ( Key . Tilde ) ) ;
AddUntilStep ( "restart completed" , ( ) = > getCurrentPlayer ( ) ! = null & & getCurrentPlayer ( ) ! = previousPlayer ) ;
AddStep ( "release quick retry key" , ( ) = > InputManager . ReleaseKey ( Key . Tilde ) ) ;
2022-08-17 16:07:06 +08:00
AddUntilStep ( "wait for player" , ( ) = > getCurrentPlayer ( ) ? . LoadState = = LoadState . Ready ) ;
2022-08-16 13:17:28 +08:00
AddUntilStep ( "time reached zero" , ( ) = > getCurrentPlayer ( ) ? . GameplayClockContainer . CurrentTime > 0 ) ;
AddUntilStep ( "skip button not visible" , ( ) = > ! checkSkipButtonVisible ( ) ) ;
2020-07-21 16:48:11 +08:00
}
2022-09-06 22:36:27 +08:00
private void clickNotification ( )
2022-08-31 00:40:27 +08:00
{
2022-09-06 22:36:27 +08:00
Notification notification = null ;
AddUntilStep ( "wait for notification" , ( ) = > ( notification = notificationOverlay . ChildrenOfType < Notification > ( ) . FirstOrDefault ( ) ) ! = null ) ;
AddStep ( "open notification overlay" , ( ) = > notificationOverlay . Show ( ) ) ;
AddStep ( "click notification" , ( ) = > notification . TriggerClick ( ) ) ;
2022-08-31 00:40:27 +08:00
}
2022-11-24 13:32:20 +08:00
private partial class TestPlayerLoader : PlayerLoader
2019-07-05 14:50:31 +08:00
{
public new VisualSettings VisualSettings = > base . VisualSettings ;
2019-12-06 12:47:34 +08:00
public new Task DisposalTask = > base . DisposalTask ;
2020-01-09 03:10:43 +08:00
public IReadOnlyList < Mod > DisplayedMods = > MetadataInfo . Mods . Value ;
2020-01-09 02:55:35 +08:00
2019-07-05 14:50:31 +08:00
public TestPlayerLoader ( Func < Player > createPlayer )
: base ( createPlayer )
{
}
}
2024-01-15 20:01:13 +08:00
private class TestMod : OsuModDoubleTime , IApplicableToScoreProcessor
2019-04-09 14:05:03 +08:00
{
public bool Applied { get ; private set ; }
public void ApplyToScoreProcessor ( ScoreProcessor scoreProcessor )
{
Applied = true ;
}
2019-04-25 18:56:57 +08:00
public ScoreRank AdjustRank ( ScoreRank rank , double accuracy ) = > rank ;
2019-04-09 14:05:03 +08:00
}
2022-11-24 13:32:20 +08:00
protected partial class SlowLoadPlayer : TestPlayer
2018-08-02 18:47:50 +08:00
{
2019-05-07 12:02:19 +08:00
public readonly ManualResetEventSlim AllowLoad = new ManualResetEventSlim ( false ) ;
2018-08-02 18:47:50 +08:00
2019-03-26 15:53:44 +08:00
public SlowLoadPlayer ( bool allowPause = true , bool showResults = true )
: base ( allowPause , showResults )
{
}
2018-08-02 18:47:50 +08:00
[BackgroundDependencyLoader]
private void load ( )
{
2019-05-07 12:02:19 +08:00
if ( ! AllowLoad . Wait ( TimeSpan . FromSeconds ( 10 ) ) )
throw new TimeoutException ( ) ;
2018-08-02 18:47:50 +08:00
}
2018-04-20 16:30:27 +08:00
}
2021-04-10 05:55:41 +08:00
/// <summary>
2021-04-12 22:52:12 +08:00
/// Mutable dummy BatteryInfo class for <see cref="TestScenePlayerLoader.TestLowBatteryNotification"/>
2021-04-10 05:55:41 +08:00
/// </summary>
/// <inheritdoc/>
2021-04-12 22:52:12 +08:00
private class LocalBatteryInfo : BatteryInfo
2021-04-10 05:55:41 +08:00
{
2022-07-30 20:26:19 +08:00
private bool onBattery ;
private double? chargeLevel ;
2021-04-10 05:55:41 +08:00
2022-07-30 20:26:19 +08:00
public override bool OnBattery = > onBattery ;
2021-04-10 05:55:41 +08:00
2022-07-30 20:26:19 +08:00
public override double? ChargeLevel = > chargeLevel ;
2021-04-10 05:55:41 +08:00
2022-07-30 20:26:19 +08:00
public void SetOnBattery ( bool value )
2021-04-10 05:55:41 +08:00
{
2022-07-30 20:26:19 +08:00
onBattery = value ;
2021-04-10 05:55:41 +08:00
}
2022-07-30 20:26:19 +08:00
public void SetChargeLevel ( double? value )
2021-04-10 05:55:41 +08:00
{
chargeLevel = value ;
}
}
2018-04-20 16:30:27 +08:00
}
}