2019-07-29 13:30:46 +08:00
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
2022-06-17 15:37:17 +08:00
#nullable disable
2022-01-28 14:50:22 +08:00
using System ;
2024-02-17 19:00:30 +08:00
using System.IO ;
2019-07-29 13:30:46 +08:00
using System.Linq ;
2024-02-20 21:33:08 +08:00
using Newtonsoft.Json.Linq ;
2019-07-29 13:30:46 +08:00
using NUnit.Framework ;
using osu.Framework.Allocation ;
2023-10-26 22:19:53 +08:00
using osu.Framework.Configuration ;
2022-01-03 16:02:15 +08:00
using osu.Framework.Extensions ;
2022-04-18 17:09:14 +08:00
using osu.Framework.Graphics ;
2019-07-29 13:30:46 +08:00
using osu.Framework.Graphics.Containers ;
2022-05-24 05:37:05 +08:00
using osu.Framework.Graphics.UserInterface ;
2023-10-30 21:08:56 +08:00
using osu.Framework.Input ;
2020-07-10 17:13:58 +08:00
using osu.Framework.Screens ;
2020-09-14 02:49:16 +08:00
using osu.Framework.Testing ;
2019-10-10 10:58:43 +08:00
using osu.Game.Beatmaps ;
2022-05-24 05:37:05 +08:00
using osu.Game.Collections ;
2022-05-05 00:26:58 +08:00
using osu.Game.Configuration ;
2024-02-17 19:00:30 +08:00
using osu.Game.Extensions ;
2023-10-26 22:19:53 +08:00
using osu.Game.Graphics.Containers ;
2021-04-05 21:46:01 +08:00
using osu.Game.Graphics.UserInterface ;
Fix screen navigation test hijacking dummy request handler
In an upcoming change, I stumbled upon a test failure mode wherein tests
in `TestSceneScreenNavigation` would die on the following exception:
2023-05-07 17:58:42 [error]: System.ObjectDisposedException: Cannot access a closed Realm.
2023-05-07 17:58:42 [error]: Object name: 'Realms.Realm'.
2023-05-07 17:58:42 [error]: at Realms.Realm.ThrowIfDisposed()
2023-05-07 17:58:42 [error]: at Realms.Realm.All[T]()
2023-05-07 17:58:42 [error]: at osu.Game.Beatmaps.BeatmapManager.<>c__DisplayClass25_0.<QueryBeatmap>b__0(Realm r) in D:\a\osu\osu\osu.Game\Beatmaps\BeatmapManager.cs:line 282
2023-05-07 17:58:42 [error]: at osu.Game.Database.RealmAccess.Run[T](Func`2 action) in D:\a\osu\osu\osu.Game\Database\RealmAccess.cs:line 387
2023-05-07 17:58:42 [error]: at osu.Game.Beatmaps.BeatmapManager.QueryBeatmap(Expression`1 query) in D:\a\osu\osu\osu.Game\Beatmaps\BeatmapManager.cs:line 282
2023-05-07 17:58:42 [error]: at osu.Game.Tests.Visual.OnlinePlay.TestRoomRequestsHandler.<HandleRequest>g__createResponseBeatmaps|6_0(Int32[] beatmapIds, <>c__DisplayClass6_0& ) in D:\a\osu\osu\osu.Game\Tests\Visual\OnlinePlay\TestRoomRequestsHandler.cs:line 174
2023-05-07 17:58:42 [error]: at osu.Game.Tests.Visual.OnlinePlay.TestRoomRequestsHandler.HandleRequest(APIRequest request, APIUser localUser, BeatmapManager beatmapManager) in D:\a\osu\osu\osu.Game\Tests\Visual\OnlinePlay\TestRoomRequestsHandler.cs:line 140
2023-05-07 17:58:42 [error]: at osu.Game.Tests.Visual.TestMultiplayerComponents.<>c__DisplayClass18_0.<load>b__0(APIRequest request) in D:\a\osu\osu\osu.Game.Tests\Visual\TestMultiplayerComponents.cs:line 80
2023-05-07 17:58:42 [error]: at osu.Game.Online.API.DummyAPIAccess.<>c__DisplayClass32_0.<Queue>b__0() in D:\a\osu\osu\osu.Game\Online\API\DummyAPIAccess.cs:line 74
Upon closer inspection, one of the tests in the scene instantiates a
`TestMultiplayerComponents` instance. `TestMultiplayerComponents`
registers a custom request handler onto `DummyAPIAccess`. Normally, this
is not an issue; however, because `TestSceneScreenNavigation` is an
`OsuGameTestScene`, and therefore has its storage recycled after every
test, this leads to the error above in the following scenario:
1. `TestPushMatchSubScreenAndPressBackButtonImmediately()` passes.
2. The test is cleaned up, and the test case's storage is recycled,
including the test case's realm database.
3. In a subsequent test, a web request handled by the dummy API request
handler is fired. The dummy API request handler subsequently attempts
to access a realm that does not exist anymore.
As the usage of `TestMultiplayerComponents` is highly unorthodox in this
particular case, I'm opting for a localised fix which ensures that the
request handler is cleaned up appropriately.
2023-06-06 03:33:08 +08:00
using osu.Game.Online.API ;
2022-01-28 14:50:22 +08:00
using osu.Game.Online.Leaderboards ;
2024-02-20 21:33:08 +08:00
using osu.Game.Online.Notifications.WebSocket ;
using osu.Game.Online.Notifications.WebSocket.Events ;
2019-07-31 18:47:41 +08:00
using osu.Game.Overlays ;
2022-12-15 17:42:58 +08:00
using osu.Game.Overlays.BeatmapListing ;
2019-07-29 13:30:46 +08:00
using osu.Game.Overlays.Mods ;
2023-06-23 14:30:21 +08:00
using osu.Game.Overlays.Notifications ;
2020-09-14 02:49:16 +08:00
using osu.Game.Overlays.Toolbar ;
2021-06-03 13:37:38 +08:00
using osu.Game.Rulesets.Mods ;
2021-02-15 14:02:58 +08:00
using osu.Game.Rulesets.Osu.Mods ;
2022-01-28 14:50:22 +08:00
using osu.Game.Scoring ;
2021-09-10 17:16:10 +08:00
using osu.Game.Screens.Menu ;
2021-07-14 17:55:01 +08:00
using osu.Game.Screens.OnlinePlay.Lounge ;
2022-08-01 11:13:06 +08:00
using osu.Game.Screens.OnlinePlay.Match.Components ;
2022-07-29 16:05:51 +08:00
using osu.Game.Screens.OnlinePlay.Playlists ;
2019-10-10 10:58:43 +08:00
using osu.Game.Screens.Play ;
2024-01-16 14:21:43 +08:00
using osu.Game.Screens.Play.HUD ;
2021-02-15 14:02:58 +08:00
using osu.Game.Screens.Ranking ;
2019-07-29 13:30:46 +08:00
using osu.Game.Screens.Select ;
2023-10-26 22:19:53 +08:00
using osu.Game.Screens.Select.Carousel ;
2022-01-28 14:50:22 +08:00
using osu.Game.Screens.Select.Leaderboards ;
2020-09-15 02:21:39 +08:00
using osu.Game.Screens.Select.Options ;
2019-10-10 10:58:43 +08:00
using osu.Game.Tests.Beatmaps.IO ;
2024-08-14 11:26:21 +08:00
using osu.Game.Utils ;
2019-07-31 15:03:05 +08:00
using osuTK ;
2019-07-29 13:30:46 +08:00
using osuTK.Input ;
2024-07-10 21:01:45 +08:00
using SharpCompress ;
2019-07-29 13:30:46 +08:00
2020-01-29 13:23:23 +08:00
namespace osu.Game.Tests.Visual.Navigation
2019-07-29 13:30:46 +08:00
{
2022-11-24 13:32:20 +08:00
public partial class TestSceneScreenNavigation : OsuGameTestScene
2019-07-29 13:30:46 +08:00
{
2019-08-13 11:26:06 +08:00
private const float click_padding = 25 ;
2020-01-29 13:23:23 +08:00
private Vector2 backButtonPosition = > Game . ToScreenSpace ( new Vector2 ( click_padding , Game . LayoutRectangle . Bottom - click_padding ) ) ;
2019-07-29 13:30:46 +08:00
2020-01-29 13:23:23 +08:00
private Vector2 optionsButtonPosition = > Game . ToScreenSpace ( new Vector2 ( click_padding , click_padding ) ) ;
2019-07-29 13:30:46 +08:00
2022-07-29 16:05:51 +08:00
[TestCase(false)]
[TestCase(true)]
public void TestConfirmationRequiredToDiscardPlaylist ( bool withPlaylistItemAdded )
{
Screens . OnlinePlay . Playlists . Playlists playlistScreen = null ;
AddUntilStep ( "wait for dialog overlay" , ( ) = > Game . ChildrenOfType < DialogOverlay > ( ) . SingleOrDefault ( ) ! = null ) ;
PushAndConfirm ( ( ) = > playlistScreen = new Screens . OnlinePlay . Playlists . Playlists ( ) ) ;
AddStep ( "import beatmap" , ( ) = > BeatmapImportHelper . LoadQuickOszIntoOsu ( Game ) . WaitSafely ( ) ) ;
AddStep ( "open create screen" , ( ) = >
{
InputManager . MoveMouseTo ( playlistScreen . ChildrenOfType < CreatePlaylistsRoomButton > ( ) . Single ( ) ) ;
InputManager . Click ( MouseButton . Left ) ;
} ) ;
if ( withPlaylistItemAdded )
{
AddUntilStep ( "wait for settings displayed" ,
( ) = > ( playlistScreen . CurrentSubScreen as PlaylistsRoomSubScreen ) ? . ChildrenOfType < PlaylistsRoomSettingsOverlay > ( ) . SingleOrDefault ( ) ? . State . Value = = Visibility . Visible ) ;
AddStep ( "edit playlist" , ( ) = > InputManager . Key ( Key . Enter ) ) ;
AddUntilStep ( "wait for song select" , ( ) = > ( playlistScreen . CurrentSubScreen as PlaylistsSongSelect ) ? . BeatmapSetsLoaded = = true ) ;
AddUntilStep ( "wait for selection" , ( ) = > ! Game . Beatmap . IsDefault ) ;
AddStep ( "add item" , ( ) = > InputManager . Key ( Key . Enter ) ) ;
AddUntilStep ( "wait for return to playlist screen" , ( ) = > playlistScreen . CurrentSubScreen is PlaylistsRoomSubScreen ) ;
2022-08-01 11:13:06 +08:00
AddStep ( "go back to song select" , ( ) = >
{
2022-12-25 12:04:45 +08:00
InputManager . MoveMouseTo ( playlistScreen . ChildrenOfType < PurpleRoundedButton > ( ) . Single ( b = > b . Text = = "Edit playlist" ) ) ;
2022-08-01 11:13:06 +08:00
InputManager . Click ( MouseButton . Left ) ;
} ) ;
AddUntilStep ( "wait for song select" , ( ) = > ( playlistScreen . CurrentSubScreen as PlaylistsSongSelect ) ? . BeatmapSetsLoaded = = true ) ;
AddStep ( "press home button" , ( ) = >
{
InputManager . MoveMouseTo ( Game . Toolbar . ChildrenOfType < ToolbarHomeButton > ( ) . Single ( ) ) ;
InputManager . Click ( MouseButton . Left ) ;
} ) ;
AddAssert ( "confirmation dialog shown" , ( ) = > Game . ChildrenOfType < DialogOverlay > ( ) . Single ( ) . CurrentDialog is not null ) ;
2022-07-29 16:05:51 +08:00
pushEscape ( ) ;
2022-08-01 11:13:06 +08:00
pushEscape ( ) ;
2022-07-29 16:05:51 +08:00
AddAssert ( "confirmation dialog shown" , ( ) = > Game . ChildrenOfType < DialogOverlay > ( ) . Single ( ) . CurrentDialog is not null ) ;
AddStep ( "confirm exit" , ( ) = > InputManager . Key ( Key . Enter ) ) ;
AddAssert ( "dialog dismissed" , ( ) = > Game . ChildrenOfType < DialogOverlay > ( ) . Single ( ) . CurrentDialog = = null ) ;
exitViaEscapeAndConfirm ( ) ;
}
else
{
pushEscape ( ) ;
AddAssert ( "confirmation dialog not shown" , ( ) = > Game . ChildrenOfType < DialogOverlay > ( ) . Single ( ) . CurrentDialog = = null ) ;
exitViaEscapeAndConfirm ( ) ;
}
}
2019-07-29 13:30:46 +08:00
[Test]
2019-07-30 17:18:03 +08:00
public void TestExitSongSelectWithEscape ( )
2019-07-29 13:30:46 +08:00
{
2021-05-16 23:14:23 +08:00
TestPlaySongSelect songSelect = null ;
2019-07-29 13:30:46 +08:00
2021-05-16 23:14:23 +08:00
PushAndConfirm ( ( ) = > songSelect = new TestPlaySongSelect ( ) ) ;
2019-07-29 13:30:46 +08:00
AddStep ( "Show mods overlay" , ( ) = > songSelect . ModSelectOverlay . Show ( ) ) ;
AddAssert ( "Overlay was shown" , ( ) = > songSelect . ModSelectOverlay . State . Value = = Visibility . Visible ) ;
2019-10-10 10:58:43 +08:00
pushEscape ( ) ;
2019-07-29 13:30:46 +08:00
AddAssert ( "Overlay was hidden" , ( ) = > songSelect . ModSelectOverlay . State . Value = = Visibility . Hidden ) ;
exitViaEscapeAndConfirm ( ) ;
}
2024-09-18 15:11:47 +08:00
[Test]
public void TestEnterGameplayWhileFilteringToNoSelection ( )
{
TestPlaySongSelect songSelect = null ;
PushAndConfirm ( ( ) = > songSelect = new TestPlaySongSelect ( ) ) ;
2024-09-18 15:40:27 +08:00
AddUntilStep ( "wait for song select" , ( ) = > songSelect . BeatmapSetsLoaded ) ;
2024-09-18 15:11:47 +08:00
AddStep ( "import beatmap" , ( ) = > BeatmapImportHelper . LoadQuickOszIntoOsu ( Game ) . WaitSafely ( ) ) ;
AddUntilStep ( "wait for selected" , ( ) = > ! Game . Beatmap . IsDefault ) ;
AddStep ( "force selection" , ( ) = >
{
songSelect . FinaliseSelection ( ) ;
songSelect . FilterControl . CurrentTextSearch . Value = "test" ;
} ) ;
2024-09-18 15:40:27 +08:00
AddUntilStep ( "wait for player" , ( ) = > ! songSelect . IsCurrentScreen ( ) ) ;
AddStep ( "return to song select" , ( ) = > songSelect . MakeCurrent ( ) ) ;
AddUntilStep ( "wait for selection lost" , ( ) = > songSelect . Beatmap . IsDefault ) ;
2024-09-18 15:11:47 +08:00
}
2022-05-24 05:37:05 +08:00
[Test]
public void TestSongSelectBackActionHandling ( )
{
TestPlaySongSelect songSelect = null ;
PushAndConfirm ( ( ) = > songSelect = new TestPlaySongSelect ( ) ) ;
2023-12-13 13:42:32 +08:00
AddStep ( "set filter" , ( ) = > filterControlTextBox ( ) . Current . Value = "test" ) ;
2022-05-24 05:37:05 +08:00
AddStep ( "press back" , ( ) = > InputManager . Click ( MouseButton . Button1 ) ) ;
AddAssert ( "still at song select" , ( ) = > Game . ScreenStack . CurrentScreen = = songSelect ) ;
2023-12-13 13:42:32 +08:00
AddAssert ( "filter cleared" , ( ) = > string . IsNullOrEmpty ( filterControlTextBox ( ) . Current . Value ) ) ;
2022-05-24 05:37:05 +08:00
2023-12-13 13:42:32 +08:00
AddStep ( "set filter again" , ( ) = > filterControlTextBox ( ) . Current . Value = "test" ) ;
2022-05-24 05:37:05 +08:00
AddStep ( "open collections dropdown" , ( ) = >
{
2022-07-28 12:48:15 +08:00
InputManager . MoveMouseTo ( songSelect . ChildrenOfType < CollectionDropdown > ( ) . Single ( ) ) ;
2022-05-24 05:37:05 +08:00
InputManager . Click ( MouseButton . Left ) ;
} ) ;
AddStep ( "press back once" , ( ) = > InputManager . Click ( MouseButton . Button1 ) ) ;
AddAssert ( "still at song select" , ( ) = > Game . ScreenStack . CurrentScreen = = songSelect ) ;
AddAssert ( "collections dropdown closed" , ( ) = > songSelect
2022-07-28 12:48:15 +08:00
. ChildrenOfType < CollectionDropdown > ( ) . Single ( )
2022-05-24 05:37:05 +08:00
. ChildrenOfType < Dropdown < CollectionFilterMenuItem > . DropdownMenu > ( ) . Single ( ) . State = = MenuState . Closed ) ;
AddStep ( "press back a second time" , ( ) = > InputManager . Click ( MouseButton . Button1 ) ) ;
2023-12-13 13:42:32 +08:00
AddAssert ( "filter cleared" , ( ) = > string . IsNullOrEmpty ( filterControlTextBox ( ) . Current . Value ) ) ;
2022-05-24 05:37:05 +08:00
AddStep ( "press back a third time" , ( ) = > InputManager . Click ( MouseButton . Button1 ) ) ;
ConfirmAtMainMenu ( ) ;
2023-12-13 13:42:32 +08:00
TextBox filterControlTextBox ( ) = > songSelect . ChildrenOfType < FilterControl . FilterControlTextBox > ( ) . Single ( ) ;
2022-05-24 05:37:05 +08:00
}
2023-10-26 22:19:53 +08:00
[Test]
public void TestSongSelectScrollHandling ( )
{
TestPlaySongSelect songSelect = null ;
double scrollPosition = 0 ;
AddStep ( "set game volume to max" , ( ) = > Game . Dependencies . Get < FrameworkConfigManager > ( ) . SetValue ( FrameworkSetting . VolumeUniversal , 1d ) ) ;
2023-10-31 12:49:39 +08:00
AddUntilStep ( "wait for volume overlay to hide" , ( ) = > Game . ChildrenOfType < VolumeOverlay > ( ) . SingleOrDefault ( ) ? . State . Value , ( ) = > Is . EqualTo ( Visibility . Hidden ) ) ;
2023-10-26 22:19:53 +08:00
PushAndConfirm ( ( ) = > songSelect = new TestPlaySongSelect ( ) ) ;
AddUntilStep ( "wait for song select" , ( ) = > songSelect . BeatmapSetsLoaded ) ;
AddStep ( "import beatmap" , ( ) = > BeatmapImportHelper . LoadQuickOszIntoOsu ( Game ) . WaitSafely ( ) ) ;
AddUntilStep ( "wait for selected" , ( ) = > ! Game . Beatmap . IsDefault ) ;
AddStep ( "store scroll position" , ( ) = > scrollPosition = getCarouselScrollPosition ( ) ) ;
AddStep ( "move to left side" , ( ) = > InputManager . MoveMouseTo (
songSelect . ChildrenOfType < Screens . Select . SongSelect . LeftSideInteractionContainer > ( ) . Single ( ) . ScreenSpaceDrawQuad . TopLeft + new Vector2 ( 1 ) ) ) ;
AddStep ( "scroll down" , ( ) = > InputManager . ScrollVerticalBy ( - 1 ) ) ;
AddAssert ( "carousel didn't move" , getCarouselScrollPosition , ( ) = > Is . EqualTo ( scrollPosition ) ) ;
AddRepeatStep ( "alt-scroll down" , ( ) = >
{
InputManager . PressKey ( Key . AltLeft ) ;
InputManager . ScrollVerticalBy ( - 1 ) ;
InputManager . ReleaseKey ( Key . AltLeft ) ;
} , 5 ) ;
AddAssert ( "game volume decreased" , ( ) = > Game . Dependencies . Get < FrameworkConfigManager > ( ) . Get < double > ( FrameworkSetting . VolumeUniversal ) , ( ) = > Is . LessThan ( 1 ) ) ;
AddStep ( "move to carousel" , ( ) = > InputManager . MoveMouseTo ( songSelect . ChildrenOfType < BeatmapCarousel > ( ) . Single ( ) ) ) ;
AddStep ( "scroll down" , ( ) = > InputManager . ScrollVerticalBy ( - 1 ) ) ;
AddAssert ( "carousel moved" , getCarouselScrollPosition , ( ) = > Is . Not . EqualTo ( scrollPosition ) ) ;
double getCarouselScrollPosition ( ) = > Game . ChildrenOfType < UserTrackingScrollContainer < DrawableCarouselItem > > ( ) . Single ( ) . Current ;
}
2021-04-08 14:20:53 +08:00
/// <summary>
/// This tests that the F1 key will open the mod select overlay, and not be handled / blocked by the music controller (which has the same default binding
/// but should be handled *after* song select).
/// </summary>
[Test]
public void TestOpenModSelectOverlayUsingAction ( )
{
2021-05-16 23:14:23 +08:00
TestPlaySongSelect songSelect = null ;
2021-04-08 14:20:53 +08:00
2021-05-16 23:14:23 +08:00
PushAndConfirm ( ( ) = > songSelect = new TestPlaySongSelect ( ) ) ;
2021-04-08 14:20:53 +08:00
AddStep ( "Show mods overlay" , ( ) = > InputManager . Key ( Key . F1 ) ) ;
AddAssert ( "Overlay was shown" , ( ) = > songSelect . ModSelectOverlay . State . Value = = Visibility . Visible ) ;
}
2024-02-17 19:00:30 +08:00
[Test]
public void TestAttemptPlayBeatmapWrongHashFails ( )
{
Screens . Select . SongSelect songSelect = null ;
AddStep ( "import beatmap" , ( ) = > BeatmapImportHelper . LoadQuickOszIntoOsu ( Game ) . GetResultSafely ( ) ) ;
PushAndConfirm ( ( ) = > songSelect = new TestPlaySongSelect ( ) ) ;
AddUntilStep ( "wait for song select" , ( ) = > songSelect . BeatmapSetsLoaded ) ;
AddUntilStep ( "wait for selected" , ( ) = > ! Game . Beatmap . IsDefault ) ;
AddStep ( "change beatmap files" , ( ) = >
{
2024-08-14 11:26:21 +08:00
FileUtils . AttemptOperation ( ( ) = >
2024-02-17 19:00:30 +08:00
{
2024-08-14 11:26:21 +08:00
foreach ( var file in Game . Beatmap . Value . BeatmapSetInfo . Files . Where ( f = > Path . GetExtension ( f . Filename ) = = ".osu" ) )
{
using ( var stream = Game . Storage . GetStream ( Path . Combine ( "files" , file . File . GetStoragePath ( ) ) , FileAccess . ReadWrite ) )
stream . WriteByte ( 0 ) ;
}
} ) ;
2024-02-17 19:00:30 +08:00
} ) ;
AddStep ( "invalidate cache" , ( ) = >
{
( ( IWorkingBeatmapCache ) Game . BeatmapManager ) . Invalidate ( Game . Beatmap . Value . BeatmapSetInfo ) ;
} ) ;
AddStep ( "select next difficulty" , ( ) = > InputManager . Key ( Key . Down ) ) ;
AddStep ( "press enter" , ( ) = > InputManager . Key ( Key . Enter ) ) ;
AddUntilStep ( "wait for player loader" , ( ) = > Game . ScreenStack . CurrentScreen is PlayerLoader ) ;
AddUntilStep ( "wait for song select" , ( ) = > songSelect . IsCurrentScreen ( ) ) ;
}
[Test]
public void TestAttemptPlayBeatmapMissingFails ( )
{
Screens . Select . SongSelect songSelect = null ;
AddStep ( "import beatmap" , ( ) = > BeatmapImportHelper . LoadQuickOszIntoOsu ( Game ) . GetResultSafely ( ) ) ;
PushAndConfirm ( ( ) = > songSelect = new TestPlaySongSelect ( ) ) ;
AddUntilStep ( "wait for song select" , ( ) = > songSelect . BeatmapSetsLoaded ) ;
AddUntilStep ( "wait for selected" , ( ) = > ! Game . Beatmap . IsDefault ) ;
AddStep ( "delete beatmap files" , ( ) = >
{
2024-08-16 16:39:45 +08:00
FileUtils . AttemptOperation ( ( ) = >
{
foreach ( var file in Game . Beatmap . Value . BeatmapSetInfo . Files . Where ( f = > Path . GetExtension ( f . Filename ) = = ".osu" ) )
Game . Storage . Delete ( Path . Combine ( "files" , file . File . GetStoragePath ( ) ) ) ;
} ) ;
2024-02-17 19:00:30 +08:00
} ) ;
AddStep ( "invalidate cache" , ( ) = >
{
( ( IWorkingBeatmapCache ) Game . BeatmapManager ) . Invalidate ( Game . Beatmap . Value . BeatmapSetInfo ) ;
} ) ;
AddStep ( "select next difficulty" , ( ) = > InputManager . Key ( Key . Down ) ) ;
AddStep ( "press enter" , ( ) = > InputManager . Key ( Key . Enter ) ) ;
AddUntilStep ( "wait for player loader" , ( ) = > Game . ScreenStack . CurrentScreen is PlayerLoader ) ;
AddUntilStep ( "wait for song select" , ( ) = > songSelect . IsCurrentScreen ( ) ) ;
}
2021-03-31 13:09:38 +08:00
[Test]
public void TestRetryCountIncrements ( )
{
Player player = null ;
2021-11-25 20:11:13 +08:00
Screens . Select . SongSelect songSelect = null ;
PushAndConfirm ( ( ) = > songSelect = new TestPlaySongSelect ( ) ) ;
AddUntilStep ( "wait for song select" , ( ) = > songSelect . BeatmapSetsLoaded ) ;
2021-03-31 13:09:38 +08:00
2021-12-17 17:26:12 +08:00
AddStep ( "import beatmap" , ( ) = > BeatmapImportHelper . LoadQuickOszIntoOsu ( Game ) . WaitSafely ( ) ) ;
2021-03-31 13:09:38 +08:00
AddUntilStep ( "wait for selected" , ( ) = > ! Game . Beatmap . IsDefault ) ;
AddStep ( "press enter" , ( ) = > InputManager . Key ( Key . Enter ) ) ;
2021-09-13 18:38:53 +08:00
AddUntilStep ( "wait for player" , ( ) = >
{
2022-04-24 04:14:14 +08:00
DismissAnyNotifications ( ) ;
2023-01-15 20:51:18 +08:00
player = Game . ScreenStack . CurrentScreen as Player ;
return player ? . IsLoaded = = true ;
2021-09-13 18:38:53 +08:00
} ) ;
2021-03-31 13:09:38 +08:00
AddAssert ( "retry count is 0" , ( ) = > player . RestartCount = = 0 ) ;
2023-01-15 20:51:18 +08:00
// todo: see https://github.com/ppy/osu/issues/22220
// tests are supposed to be immune to this edge case by the logic in TestPlayer,
// but we're running a full game instance here, so we have to work around it manually.
AddStep ( "end spectator before retry" , ( ) = > Game . SpectatorClient . EndPlaying ( player . GameplayState ) ) ;
2021-03-31 13:09:38 +08:00
AddStep ( "attempt to retry" , ( ) = > player . ChildrenOfType < HotkeyRetryOverlay > ( ) . First ( ) . Action ( ) ) ;
2023-10-27 17:58:02 +08:00
AddAssert ( "old player score marked failed" , ( ) = > player . Score . ScoreInfo . Rank , ( ) = > Is . EqualTo ( ScoreRank . F ) ) ;
2021-03-31 13:09:38 +08:00
AddUntilStep ( "wait for old player gone" , ( ) = > Game . ScreenStack . CurrentScreen ! = player ) ;
AddUntilStep ( "get new player" , ( ) = > ( player = Game . ScreenStack . CurrentScreen as Player ) ! = null ) ;
AddAssert ( "retry count is 1" , ( ) = > player . RestartCount = = 1 ) ;
}
2023-10-12 14:42:16 +08:00
[Test]
public void TestRetryImmediatelyAfterCompletion ( )
{
var getOriginalPlayer = playToCompletion ( ) ;
AddStep ( "attempt to retry" , ( ) = > getOriginalPlayer ( ) . ChildrenOfType < HotkeyRetryOverlay > ( ) . First ( ) . Action ( ) ) ;
2023-10-27 17:38:10 +08:00
AddAssert ( "original play isn't failed" , ( ) = > getOriginalPlayer ( ) . Score . ScoreInfo . Rank , ( ) = > Is . Not . EqualTo ( ScoreRank . F ) ) ;
2023-10-12 14:42:16 +08:00
AddUntilStep ( "wait for player" , ( ) = > Game . ScreenStack . CurrentScreen ! = getOriginalPlayer ( ) & & Game . ScreenStack . CurrentScreen is Player ) ;
}
[Test]
public void TestExitImmediatelyAfterCompletion ( )
{
var player = playToCompletion ( ) ;
AddStep ( "attempt to exit" , ( ) = > player ( ) . ChildrenOfType < HotkeyExitOverlay > ( ) . First ( ) . Action ( ) ) ;
AddUntilStep ( "wait for results" , ( ) = > Game . ScreenStack . CurrentScreen is ResultsScreen ) ;
}
2024-02-20 21:33:08 +08:00
[Test]
public void TestShowMedalAtResults ( )
{
playToResults ( ) ;
AddStep ( "award medal" , ( ) = > ( ( DummyAPIAccess ) API ) . NotificationsClient . Receive ( new SocketMessage
{
Event = @"new" ,
Data = JObject . FromObject ( new NewPrivateNotificationEvent
{
Name = @"user_achievement_unlock" ,
Details = JObject . FromObject ( new UserAchievementUnlock
{
Title = "Time And A Half" ,
Description = "Having a right ol' time. One and a half of them, almost." ,
Slug = @"all-intro-doubletime"
} )
} )
} ) ) ;
AddUntilStep ( "medal overlay shown" , ( ) = > Game . ChildrenOfType < MedalOverlay > ( ) . Single ( ) . State . Value , ( ) = > Is . EqualTo ( Visibility . Visible ) ) ;
}
2021-02-15 14:02:58 +08:00
[Test]
public void TestRetryFromResults ( )
{
2022-01-28 14:50:22 +08:00
var getOriginalPlayer = playToResults ( ) ;
2021-02-15 14:02:58 +08:00
2022-01-28 14:50:22 +08:00
AddStep ( "attempt to retry" , ( ) = > ( ( ResultsScreen ) Game . ScreenStack . CurrentScreen ) . ChildrenOfType < HotkeyRetryOverlay > ( ) . First ( ) . Action ( ) ) ;
AddUntilStep ( "wait for player" , ( ) = > Game . ScreenStack . CurrentScreen ! = getOriginalPlayer ( ) & & Game . ScreenStack . CurrentScreen is Player ) ;
}
2021-02-15 14:02:58 +08:00
2022-01-28 14:54:51 +08:00
[Test]
public void TestDeleteAllScoresAfterPlaying ( )
{
playToResults ( ) ;
ScoreInfo score = null ;
LeaderboardScore scorePanel = null ;
AddStep ( "get score" , ( ) = > score = ( ( ResultsScreen ) Game . ScreenStack . CurrentScreen ) . Score ) ;
AddAssert ( "ensure score is databased" , ( ) = > Game . Realm . Run ( r = > r . Find < ScoreInfo > ( score . ID ) ? . DeletePending = = false ) ) ;
AddStep ( "press back button" , ( ) = > Game . ChildrenOfType < BackButton > ( ) . First ( ) . Action ( ) ) ;
2022-03-21 16:01:46 +08:00
AddStep ( "show local scores" ,
( ) = > Game . ChildrenOfType < BeatmapDetailAreaTabControl > ( ) . First ( ) . Current . Value = new BeatmapDetailAreaLeaderboardTabItem < BeatmapLeaderboardScope > ( BeatmapLeaderboardScope . Local ) ) ;
2022-01-28 14:54:51 +08:00
AddUntilStep ( "wait for score displayed" , ( ) = > ( scorePanel = Game . ChildrenOfType < LeaderboardScore > ( ) . FirstOrDefault ( s = > s . Score . Equals ( score ) ) ) ! = null ) ;
AddStep ( "open options" , ( ) = > InputManager . Key ( Key . F3 ) ) ;
AddStep ( "choose clear all scores" , ( ) = > InputManager . Key ( Key . Number4 ) ) ;
2022-04-18 17:09:14 +08:00
AddUntilStep ( "wait for dialog display" , ( ) = > ( ( Drawable ) Game . Dependencies . Get < IDialogOverlay > ( ) ) . IsLoaded ) ;
AddUntilStep ( "wait for dialog" , ( ) = > Game . Dependencies . Get < IDialogOverlay > ( ) . CurrentDialog ! = null ) ;
2022-01-28 14:54:51 +08:00
AddStep ( "confirm deletion" , ( ) = > InputManager . Key ( Key . Number1 ) ) ;
2022-04-18 17:09:14 +08:00
AddUntilStep ( "wait for dialog dismissed" , ( ) = > Game . Dependencies . Get < IDialogOverlay > ( ) . CurrentDialog = = null ) ;
2022-01-28 14:54:51 +08:00
2022-03-10 17:08:07 +08:00
AddUntilStep ( "ensure score is pending deletion" , ( ) = > Game . Realm . Run ( r = > r . Find < ScoreInfo > ( score . ID ) ? . DeletePending = = true ) ) ;
2022-01-28 14:54:51 +08:00
AddUntilStep ( "wait for score panel removal" , ( ) = > scorePanel . Parent = = null ) ;
}
2022-01-28 14:50:22 +08:00
[Test]
public void TestDeleteScoreAfterPlaying ( )
{
playToResults ( ) ;
2021-02-15 14:02:58 +08:00
2022-01-28 14:50:22 +08:00
ScoreInfo score = null ;
LeaderboardScore scorePanel = null ;
2021-02-15 14:02:58 +08:00
2022-01-28 14:50:22 +08:00
AddStep ( "get score" , ( ) = > score = ( ( ResultsScreen ) Game . ScreenStack . CurrentScreen ) . Score ) ;
2021-02-15 14:02:58 +08:00
2022-01-28 14:50:22 +08:00
AddAssert ( "ensure score is databased" , ( ) = > Game . Realm . Run ( r = > r . Find < ScoreInfo > ( score . ID ) ? . DeletePending = = false ) ) ;
2021-02-15 14:02:58 +08:00
2022-01-28 14:50:22 +08:00
AddStep ( "press back button" , ( ) = > Game . ChildrenOfType < BackButton > ( ) . First ( ) . Action ( ) ) ;
2021-09-13 18:38:53 +08:00
2022-03-21 16:01:46 +08:00
AddStep ( "show local scores" ,
( ) = > Game . ChildrenOfType < BeatmapDetailAreaTabControl > ( ) . First ( ) . Current . Value = new BeatmapDetailAreaLeaderboardTabItem < BeatmapLeaderboardScope > ( BeatmapLeaderboardScope . Local ) ) ;
2022-01-28 14:50:22 +08:00
AddUntilStep ( "wait for score displayed" , ( ) = > ( scorePanel = Game . ChildrenOfType < LeaderboardScore > ( ) . FirstOrDefault ( s = > s . Score . Equals ( score ) ) ) ! = null ) ;
AddStep ( "right click panel" , ( ) = >
2021-09-13 18:38:53 +08:00
{
2022-01-28 14:50:22 +08:00
InputManager . MoveMouseTo ( scorePanel ) ;
InputManager . Click ( MouseButton . Right ) ;
2021-09-13 18:38:53 +08:00
} ) ;
2022-01-28 14:50:22 +08:00
AddStep ( "click delete" , ( ) = >
{
var dropdownItem = Game
. ChildrenOfType < PlayBeatmapDetailArea > ( ) . First ( )
. ChildrenOfType < OsuContextMenu > ( ) . First ( )
. ChildrenOfType < DrawableOsuMenuItem > ( ) . First ( i = > i . Item . Text . ToString ( ) = = "Delete" ) ;
InputManager . MoveMouseTo ( dropdownItem ) ;
InputManager . Click ( MouseButton . Left ) ;
} ) ;
2022-04-18 17:09:14 +08:00
AddUntilStep ( "wait for dialog display" , ( ) = > ( ( Drawable ) Game . Dependencies . Get < IDialogOverlay > ( ) ) . IsLoaded ) ;
AddUntilStep ( "wait for dialog" , ( ) = > Game . Dependencies . Get < IDialogOverlay > ( ) . CurrentDialog ! = null ) ;
2022-01-28 14:50:22 +08:00
AddStep ( "confirm deletion" , ( ) = > InputManager . Key ( Key . Number1 ) ) ;
2022-04-18 17:09:14 +08:00
AddUntilStep ( "wait for dialog dismissed" , ( ) = > Game . Dependencies . Get < IDialogOverlay > ( ) . CurrentDialog = = null ) ;
2022-01-28 14:50:22 +08:00
2022-03-10 17:08:07 +08:00
AddUntilStep ( "ensure score is pending deletion" , ( ) = > Game . Realm . Run ( r = > r . Find < ScoreInfo > ( score . ID ) ? . DeletePending = = true ) ) ;
2022-01-28 14:50:22 +08:00
AddUntilStep ( "wait for score panel removal" , ( ) = > scorePanel . Parent = = null ) ;
2021-02-15 14:02:58 +08:00
}
2019-10-10 19:12:47 +08:00
[TestCase(true)]
[TestCase(false)]
public void TestSongContinuesAfterExitPlayer ( bool withUserPause )
2019-10-10 10:58:43 +08:00
{
Player player = null ;
2021-11-15 17:46:11 +08:00
IWorkingBeatmap beatmap ( ) = > Game . Beatmap . Value ;
2019-10-10 10:58:43 +08:00
2021-11-25 20:11:13 +08:00
Screens . Select . SongSelect songSelect = null ;
PushAndConfirm ( ( ) = > songSelect = new TestPlaySongSelect ( ) ) ;
AddUntilStep ( "wait for song select" , ( ) = > songSelect . BeatmapSetsLoaded ) ;
2019-10-10 10:58:43 +08:00
2021-12-17 17:26:12 +08:00
AddStep ( "import beatmap" , ( ) = > BeatmapImportHelper . LoadOszIntoOsu ( Game , virtualTrack : true ) . WaitSafely ( ) ) ;
2019-10-10 10:58:43 +08:00
2020-01-29 13:23:23 +08:00
AddUntilStep ( "wait for selected" , ( ) = > ! Game . Beatmap . IsDefault ) ;
2019-10-10 10:58:43 +08:00
2019-10-10 19:12:47 +08:00
if ( withUserPause )
2020-11-02 13:56:50 +08:00
AddStep ( "pause" , ( ) = > Game . Dependencies . Get < MusicController > ( ) . Stop ( true ) ) ;
2019-10-10 19:12:47 +08:00
2020-11-05 22:41:56 +08:00
AddStep ( "press enter" , ( ) = > InputManager . Key ( Key . Enter ) ) ;
2019-10-10 10:58:43 +08:00
2021-09-13 18:38:53 +08:00
AddUntilStep ( "wait for player" , ( ) = >
{
2022-04-24 04:14:14 +08:00
DismissAnyNotifications ( ) ;
2021-09-13 18:38:53 +08:00
return ( player = Game . ScreenStack . CurrentScreen as Player ) ! = null ;
} ) ;
2022-01-26 00:45:11 +08:00
AddUntilStep ( "wait for fail" , ( ) = > player . GameplayState . HasFailed ) ;
2019-10-10 10:58:43 +08:00
2020-08-07 21:06:04 +08:00
AddUntilStep ( "wait for track stop" , ( ) = > ! Game . MusicController . IsPlaying ) ;
2021-12-22 16:44:22 +08:00
AddAssert ( "Ensure time before preview point" , ( ) = > Game . MusicController . CurrentTrack . CurrentTime < beatmap ( ) . BeatmapInfo . Metadata . PreviewTime ) ;
2019-10-10 10:58:43 +08:00
pushEscape ( ) ;
2020-08-07 21:06:04 +08:00
AddUntilStep ( "wait for track playing" , ( ) = > Game . MusicController . IsPlaying ) ;
2021-12-22 16:44:22 +08:00
AddAssert ( "Ensure time wasn't reset to preview point" , ( ) = > Game . MusicController . CurrentTrack . CurrentTime < beatmap ( ) . BeatmapInfo . Metadata . PreviewTime ) ;
2019-10-10 10:58:43 +08:00
}
2020-07-10 17:13:58 +08:00
[Test]
public void TestMenuMakesMusic ( )
{
2021-05-16 23:14:23 +08:00
TestPlaySongSelect songSelect = null ;
2020-07-10 17:13:58 +08:00
2021-05-16 23:14:23 +08:00
PushAndConfirm ( ( ) = > songSelect = new TestPlaySongSelect ( ) ) ;
2020-07-10 17:13:58 +08:00
2020-08-07 21:06:04 +08:00
AddUntilStep ( "wait for no track" , ( ) = > Game . MusicController . CurrentTrack . IsDummyDevice ) ;
2020-07-10 17:13:58 +08:00
AddStep ( "return to menu" , ( ) = > songSelect . Exit ( ) ) ;
2020-08-11 12:14:20 +08:00
AddUntilStep ( "wait for track" , ( ) = > ! Game . MusicController . CurrentTrack . IsDummyDevice & & Game . MusicController . IsPlaying ) ;
2020-07-10 17:13:58 +08:00
}
2021-06-08 16:03:46 +08:00
[Test]
public void TestPushSongSelectAndPressBackButtonImmediately ( )
{
AddStep ( "push song select" , ( ) = > Game . ScreenStack . Push ( new TestPlaySongSelect ( ) ) ) ;
AddStep ( "press back button" , ( ) = > Game . ChildrenOfType < BackButton > ( ) . First ( ) . Action ( ) ) ;
2021-06-08 16:09:03 +08:00
AddWaitStep ( "wait two frames" , 2 ) ;
2021-06-08 16:03:46 +08:00
}
2019-07-29 13:30:46 +08:00
[Test]
2019-07-30 17:18:03 +08:00
public void TestExitSongSelectWithClick ( )
2019-07-29 13:30:46 +08:00
{
2021-05-16 23:14:23 +08:00
TestPlaySongSelect songSelect = null ;
2019-07-29 13:30:46 +08:00
2021-05-16 23:14:23 +08:00
PushAndConfirm ( ( ) = > songSelect = new TestPlaySongSelect ( ) ) ;
2019-07-29 13:30:46 +08:00
AddStep ( "Show mods overlay" , ( ) = > songSelect . ModSelectOverlay . Show ( ) ) ;
AddAssert ( "Overlay was shown" , ( ) = > songSelect . ModSelectOverlay . State . Value = = Visibility . Visible ) ;
2022-05-06 04:15:49 +08:00
AddStep ( "Move mouse to dimmed area" , ( ) = > InputManager . MoveMouseTo ( new Vector2 (
songSelect . ScreenSpaceDrawQuad . TopLeft . X + 1 ,
songSelect . ScreenSpaceDrawQuad . TopLeft . Y + songSelect . ScreenSpaceDrawQuad . Height / 2 ) ) ) ;
AddStep ( "Click left mouse button" , ( ) = > InputManager . Click ( MouseButton . Left ) ) ;
2019-07-29 13:30:46 +08:00
2019-07-31 15:03:05 +08:00
AddUntilStep ( "Overlay was hidden" , ( ) = > songSelect . ModSelectOverlay . State . Value = = Visibility . Hidden ) ;
2019-07-29 13:30:46 +08:00
exitViaBackButtonAndConfirm ( ) ;
}
2022-03-22 16:38:43 +08:00
[Test]
public void TestModsResetOnEnteringMultiplayer ( )
{
var osuAutomationMod = new OsuModAutoplay ( ) ;
AddStep ( "Enable autoplay" , ( ) = > { Game . SelectedMods . Value = new [ ] { osuAutomationMod } ; } ) ;
2022-03-23 02:13:22 +08:00
PushAndConfirm ( ( ) = > new Screens . OnlinePlay . Multiplayer . Multiplayer ( ) ) ;
AddUntilStep ( "Mods are removed" , ( ) = > Game . SelectedMods . Value . Count = = 0 ) ;
2022-03-22 16:38:43 +08:00
AddStep ( "Return to menu" , ( ) = > Game . ScreenStack . CurrentScreen . Exit ( ) ) ;
AddUntilStep ( "Mods are restored" , ( ) = > Game . SelectedMods . Value . Contains ( osuAutomationMod ) ) ;
}
2019-07-29 13:30:46 +08:00
[Test]
public void TestExitMultiWithEscape ( )
{
2020-12-25 23:50:00 +08:00
PushAndConfirm ( ( ) = > new Screens . OnlinePlay . Playlists . Playlists ( ) ) ;
2019-07-29 13:30:46 +08:00
exitViaEscapeAndConfirm ( ) ;
}
[Test]
public void TestExitMultiWithBackButton ( )
{
2020-12-25 23:50:00 +08:00
PushAndConfirm ( ( ) = > new Screens . OnlinePlay . Playlists . Playlists ( ) ) ;
2019-07-29 13:30:46 +08:00
exitViaBackButtonAndConfirm ( ) ;
}
2019-07-31 18:47:41 +08:00
[Test]
public void TestOpenOptionsAndExitWithEscape ( )
{
2020-01-29 13:23:23 +08:00
AddUntilStep ( "Wait for options to load" , ( ) = > Game . Settings . IsLoaded ) ;
2020-11-05 22:41:56 +08:00
AddStep ( "Enter menu" , ( ) = > InputManager . Key ( Key . Enter ) ) ;
2019-07-31 18:47:41 +08:00
AddStep ( "Move mouse to options overlay" , ( ) = > InputManager . MoveMouseTo ( optionsButtonPosition ) ) ;
AddStep ( "Click options overlay" , ( ) = > InputManager . Click ( MouseButton . Left ) ) ;
2020-01-29 13:23:23 +08:00
AddAssert ( "Options overlay was opened" , ( ) = > Game . Settings . State . Value = = Visibility . Visible ) ;
2020-11-05 22:41:56 +08:00
AddStep ( "Hide options overlay using escape" , ( ) = > InputManager . Key ( Key . Escape ) ) ;
2020-01-29 13:23:23 +08:00
AddAssert ( "Options overlay was closed" , ( ) = > Game . Settings . State . Value = = Visibility . Hidden ) ;
2019-07-31 18:47:41 +08:00
}
2020-03-05 16:12:14 +08:00
[Test]
public void TestWaitForNextTrackInMenu ( )
{
bool trackCompleted = false ;
AddUntilStep ( "Wait for music controller" , ( ) = > Game . MusicController . IsLoaded ) ;
AddStep ( "Seek close to end" , ( ) = >
{
2020-08-07 21:06:04 +08:00
Game . MusicController . SeekTo ( Game . MusicController . CurrentTrack . Length - 1000 ) ;
Game . MusicController . CurrentTrack . Completed + = ( ) = > trackCompleted = true ;
2020-03-05 16:12:14 +08:00
} ) ;
AddUntilStep ( "Track was completed" , ( ) = > trackCompleted ) ;
2020-08-07 21:06:04 +08:00
AddUntilStep ( "Track was restarted" , ( ) = > Game . MusicController . IsPlaying ) ;
2020-03-05 16:12:14 +08:00
}
2020-09-14 02:49:16 +08:00
[Test]
public void TestModSelectInput ( )
{
2022-01-13 04:52:04 +08:00
AddUntilStep ( "Wait for toolbar to load" , ( ) = > Game . Toolbar . IsLoaded ) ;
2020-09-14 02:49:16 +08:00
2022-01-13 04:52:04 +08:00
TestPlaySongSelect songSelect = null ;
2021-05-16 23:14:23 +08:00
PushAndConfirm ( ( ) = > songSelect = new TestPlaySongSelect ( ) ) ;
2020-09-14 02:49:16 +08:00
AddStep ( "Show mods overlay" , ( ) = > songSelect . ModSelectOverlay . Show ( ) ) ;
AddStep ( "Change ruleset to osu!taiko" , ( ) = >
{
InputManager . PressKey ( Key . ControlLeft ) ;
2020-11-05 22:41:56 +08:00
InputManager . Key ( Key . Number2 ) ;
2020-09-14 02:49:16 +08:00
InputManager . ReleaseKey ( Key . ControlLeft ) ;
} ) ;
2021-11-22 13:26:24 +08:00
AddAssert ( "Ruleset changed to osu!taiko" , ( ) = > Game . Toolbar . ChildrenOfType < ToolbarRulesetSelector > ( ) . Single ( ) . Current . Value . OnlineID = = 1 ) ;
2020-09-14 02:49:16 +08:00
AddAssert ( "Mods overlay still visible" , ( ) = > songSelect . ModSelectOverlay . State . Value = = Visibility . Visible ) ;
}
2020-09-15 02:21:39 +08:00
[Test]
public void TestBeatmapOptionsInput ( )
{
2022-01-13 04:52:04 +08:00
AddUntilStep ( "Wait for toolbar to load" , ( ) = > Game . Toolbar . IsLoaded ) ;
2020-09-15 02:21:39 +08:00
2022-11-18 12:07:56 +08:00
AddStep ( "import beatmap" , ( ) = > BeatmapImportHelper . LoadQuickOszIntoOsu ( Game ) . WaitSafely ( ) ) ;
2022-01-13 04:52:04 +08:00
TestPlaySongSelect songSelect = null ;
2021-05-16 23:14:23 +08:00
PushAndConfirm ( ( ) = > songSelect = new TestPlaySongSelect ( ) ) ;
2020-09-15 02:21:39 +08:00
AddStep ( "Show options overlay" , ( ) = > songSelect . BeatmapOptionsOverlay . Show ( ) ) ;
AddStep ( "Change ruleset to osu!taiko" , ( ) = >
{
InputManager . PressKey ( Key . ControlLeft ) ;
2020-11-05 22:41:56 +08:00
InputManager . Key ( Key . Number2 ) ;
2020-09-15 02:21:39 +08:00
InputManager . ReleaseKey ( Key . ControlLeft ) ;
} ) ;
2021-11-22 13:26:24 +08:00
AddAssert ( "Ruleset changed to osu!taiko" , ( ) = > Game . Toolbar . ChildrenOfType < ToolbarRulesetSelector > ( ) . Single ( ) . Current . Value . OnlineID = = 1 ) ;
2020-09-15 02:21:39 +08:00
AddAssert ( "Options overlay still visible" , ( ) = > songSelect . BeatmapOptionsOverlay . State . Value = = Visibility . Visible ) ;
}
2021-02-25 13:51:23 +08:00
[Test]
public void TestSettingsViaHotkeyFromMainMenu ( )
{
2022-01-13 04:52:04 +08:00
AddUntilStep ( "Wait for toolbar to load" , ( ) = > Game . Toolbar . IsLoaded ) ;
2021-02-25 13:51:23 +08:00
AddAssert ( "toolbar not displayed" , ( ) = > Game . Toolbar . State . Value = = Visibility . Hidden ) ;
AddStep ( "press settings hotkey" , ( ) = >
{
InputManager . PressKey ( Key . ControlLeft ) ;
InputManager . Key ( Key . O ) ;
InputManager . ReleaseKey ( Key . ControlLeft ) ;
} ) ;
AddUntilStep ( "settings displayed" , ( ) = > Game . Settings . State . Value = = Visibility . Visible ) ;
}
2020-11-10 06:43:06 +08:00
[Test]
public void TestToolbarHiddenByUser ( )
{
AddUntilStep ( "Wait for toolbar to load" , ( ) = > Game . Toolbar . IsLoaded ) ;
2022-01-13 04:52:04 +08:00
AddStep ( "Enter menu" , ( ) = > InputManager . Key ( Key . Enter ) ) ;
AddUntilStep ( "Toolbar is visible" , ( ) = > Game . Toolbar . State . Value = = Visibility . Visible ) ;
2020-11-10 06:43:06 +08:00
AddStep ( "Hide toolbar" , ( ) = >
{
InputManager . PressKey ( Key . ControlLeft ) ;
InputManager . Key ( Key . T ) ;
InputManager . ReleaseKey ( Key . ControlLeft ) ;
} ) ;
pushEscape ( ) ;
AddStep ( "Enter menu" , ( ) = > InputManager . Key ( Key . Enter ) ) ;
AddAssert ( "Toolbar is hidden" , ( ) = > Game . Toolbar . State . Value = = Visibility . Hidden ) ;
AddStep ( "Enter song select" , ( ) = >
{
InputManager . Key ( Key . Enter ) ;
InputManager . Key ( Key . Enter ) ;
} ) ;
AddAssert ( "Toolbar is hidden" , ( ) = > Game . Toolbar . State . Value = = Visibility . Hidden ) ;
}
2021-06-08 16:54:54 +08:00
[Test]
public void TestPushMatchSubScreenAndPressBackButtonImmediately ( )
{
2021-12-20 17:24:59 +08:00
TestMultiplayerComponents multiplayerComponents = null ;
2021-06-08 16:54:54 +08:00
2021-12-20 17:24:59 +08:00
PushAndConfirm ( ( ) = > multiplayerComponents = new TestMultiplayerComponents ( ) ) ;
2021-06-08 16:54:54 +08:00
2021-12-20 17:24:59 +08:00
AddUntilStep ( "wait for lounge" , ( ) = > multiplayerComponents . ChildrenOfType < LoungeSubScreen > ( ) . SingleOrDefault ( ) ? . IsLoaded = = true ) ;
AddStep ( "open room" , ( ) = > multiplayerComponents . ChildrenOfType < LoungeSubScreen > ( ) . Single ( ) . Open ( ) ) ;
2021-06-08 16:54:54 +08:00
AddStep ( "press back button" , ( ) = > Game . ChildrenOfType < BackButton > ( ) . First ( ) . Action ( ) ) ;
AddWaitStep ( "wait two frames" , 2 ) ;
Fix screen navigation test hijacking dummy request handler
In an upcoming change, I stumbled upon a test failure mode wherein tests
in `TestSceneScreenNavigation` would die on the following exception:
2023-05-07 17:58:42 [error]: System.ObjectDisposedException: Cannot access a closed Realm.
2023-05-07 17:58:42 [error]: Object name: 'Realms.Realm'.
2023-05-07 17:58:42 [error]: at Realms.Realm.ThrowIfDisposed()
2023-05-07 17:58:42 [error]: at Realms.Realm.All[T]()
2023-05-07 17:58:42 [error]: at osu.Game.Beatmaps.BeatmapManager.<>c__DisplayClass25_0.<QueryBeatmap>b__0(Realm r) in D:\a\osu\osu\osu.Game\Beatmaps\BeatmapManager.cs:line 282
2023-05-07 17:58:42 [error]: at osu.Game.Database.RealmAccess.Run[T](Func`2 action) in D:\a\osu\osu\osu.Game\Database\RealmAccess.cs:line 387
2023-05-07 17:58:42 [error]: at osu.Game.Beatmaps.BeatmapManager.QueryBeatmap(Expression`1 query) in D:\a\osu\osu\osu.Game\Beatmaps\BeatmapManager.cs:line 282
2023-05-07 17:58:42 [error]: at osu.Game.Tests.Visual.OnlinePlay.TestRoomRequestsHandler.<HandleRequest>g__createResponseBeatmaps|6_0(Int32[] beatmapIds, <>c__DisplayClass6_0& ) in D:\a\osu\osu\osu.Game\Tests\Visual\OnlinePlay\TestRoomRequestsHandler.cs:line 174
2023-05-07 17:58:42 [error]: at osu.Game.Tests.Visual.OnlinePlay.TestRoomRequestsHandler.HandleRequest(APIRequest request, APIUser localUser, BeatmapManager beatmapManager) in D:\a\osu\osu\osu.Game\Tests\Visual\OnlinePlay\TestRoomRequestsHandler.cs:line 140
2023-05-07 17:58:42 [error]: at osu.Game.Tests.Visual.TestMultiplayerComponents.<>c__DisplayClass18_0.<load>b__0(APIRequest request) in D:\a\osu\osu\osu.Game.Tests\Visual\TestMultiplayerComponents.cs:line 80
2023-05-07 17:58:42 [error]: at osu.Game.Online.API.DummyAPIAccess.<>c__DisplayClass32_0.<Queue>b__0() in D:\a\osu\osu\osu.Game\Online\API\DummyAPIAccess.cs:line 74
Upon closer inspection, one of the tests in the scene instantiates a
`TestMultiplayerComponents` instance. `TestMultiplayerComponents`
registers a custom request handler onto `DummyAPIAccess`. Normally, this
is not an issue; however, because `TestSceneScreenNavigation` is an
`OsuGameTestScene`, and therefore has its storage recycled after every
test, this leads to the error above in the following scenario:
1. `TestPushMatchSubScreenAndPressBackButtonImmediately()` passes.
2. The test is cleaned up, and the test case's storage is recycled,
including the test case's realm database.
3. In a subsequent test, a web request handled by the dummy API request
handler is fired. The dummy API request handler subsequently attempts
to access a realm that does not exist anymore.
As the usage of `TestMultiplayerComponents` is highly unorthodox in this
particular case, I'm opting for a localised fix which ensures that the
request handler is cleaned up appropriately.
2023-06-06 03:33:08 +08:00
AddStep ( "exit lounge" , ( ) = > Game . ScreenStack . Exit ( ) ) ;
// `TestMultiplayerComponents` registers a request handler in its BDL, but never unregisters it.
// to prevent the handler living for longer than it should be, clean up manually.
AddStep ( "clean up multiplayer request handler" , ( ) = > ( ( DummyAPIAccess ) API ) . HandleRequest = null ) ;
2021-06-08 16:54:54 +08:00
}
2022-12-15 17:42:58 +08:00
[Test]
public void TestFeaturedArtistDisclaimerDialog ( )
{
BeatmapListingOverlay getBeatmapListingOverlay ( ) = > Game . ChildrenOfType < BeatmapListingOverlay > ( ) . FirstOrDefault ( ) ;
AddStep ( "Wait for notifications to load" , ( ) = > Game . SearchBeatmapSet ( string . Empty ) ) ;
AddUntilStep ( "wait for dialog overlay" , ( ) = > Game . ChildrenOfType < DialogOverlay > ( ) . SingleOrDefault ( ) ! = null ) ;
AddUntilStep ( "Wait for beatmap overlay to load" , ( ) = > getBeatmapListingOverlay ( ) ? . State . Value = = Visibility . Visible ) ;
AddAssert ( "featured artist filter is on" , ( ) = > getBeatmapListingOverlay ( ) . ChildrenOfType < BeatmapSearchGeneralFilterRow > ( ) . First ( ) . Current . Contains ( SearchGeneral . FeaturedArtists ) ) ;
AddStep ( "toggle featured artist filter" ,
( ) = > getBeatmapListingOverlay ( ) . ChildrenOfType < FilterTabItem < SearchGeneral > > ( ) . First ( i = > i . Value = = SearchGeneral . FeaturedArtists ) . TriggerClick ( ) ) ;
AddAssert ( "disclaimer dialog is shown" , ( ) = > Game . ChildrenOfType < DialogOverlay > ( ) . Single ( ) . CurrentDialog ! = null ) ;
AddAssert ( "featured artist filter is still on" , ( ) = > getBeatmapListingOverlay ( ) . ChildrenOfType < BeatmapSearchGeneralFilterRow > ( ) . First ( ) . Current . Contains ( SearchGeneral . FeaturedArtists ) ) ;
AddStep ( "confirm" , ( ) = > InputManager . Key ( Key . Enter ) ) ;
AddAssert ( "dialog dismissed" , ( ) = > Game . ChildrenOfType < DialogOverlay > ( ) . Single ( ) . CurrentDialog = = null ) ;
AddUntilStep ( "featured artist filter is off" , ( ) = > ! getBeatmapListingOverlay ( ) . ChildrenOfType < BeatmapSearchGeneralFilterRow > ( ) . First ( ) . Current . Contains ( SearchGeneral . FeaturedArtists ) ) ;
}
2023-01-27 13:22:06 +08:00
[Test]
public void TestBeatmapListingLinkSearchOnInitialOpen ( )
{
BeatmapListingOverlay getBeatmapListingOverlay ( ) = > Game . ChildrenOfType < BeatmapListingOverlay > ( ) . FirstOrDefault ( ) ;
AddStep ( "open beatmap overlay with test query" , ( ) = > Game . SearchBeatmapSet ( "test" ) ) ;
AddUntilStep ( "wait for beatmap overlay to load" , ( ) = > getBeatmapListingOverlay ( ) ? . State . Value = = Visibility . Visible ) ;
AddAssert ( "beatmap overlay sorted by relevance" , ( ) = > getBeatmapListingOverlay ( ) . ChildrenOfType < BeatmapListingSortTabControl > ( ) . Single ( ) . Current . Value = = SortCriteria . Relevance ) ;
}
2022-11-08 13:58:52 +08:00
[Test]
public void TestMainOverlaysClosesNotificationOverlay ( )
{
ChangelogOverlay getChangelogOverlay ( ) = > Game . ChildrenOfType < ChangelogOverlay > ( ) . FirstOrDefault ( ) ;
2022-11-10 02:33:28 +08:00
AddUntilStep ( "Wait for notifications to load" , ( ) = > Game . Notifications . IsLoaded ) ;
2022-11-08 13:58:52 +08:00
AddStep ( "Show notifications" , ( ) = > Game . Notifications . Show ( ) ) ;
AddUntilStep ( "wait for notifications shown" , ( ) = > Game . Notifications . IsPresent & & Game . Notifications . State . Value = = Visibility . Visible ) ;
AddStep ( "Show changelog listing" , ( ) = > Game . ShowChangelogListing ( ) ) ;
AddUntilStep ( "wait for changelog shown" , ( ) = > getChangelogOverlay ( ) ? . IsPresent = = true & & getChangelogOverlay ( ) ? . State . Value = = Visibility . Visible ) ;
AddAssert ( "Notifications is hidden" , ( ) = > Game . Notifications . State . Value = = Visibility . Hidden ) ;
AddStep ( "Show notifications" , ( ) = > Game . Notifications . Show ( ) ) ;
AddUntilStep ( "wait for notifications shown" , ( ) = > Game . Notifications . State . Value = = Visibility . Visible ) ;
AddUntilStep ( "changelog still visible" , ( ) = > getChangelogOverlay ( ) . State . Value = = Visibility . Visible ) ;
}
[Test]
public void TestMainOverlaysClosesSettingsOverlay ( )
{
ChangelogOverlay getChangelogOverlay ( ) = > Game . ChildrenOfType < ChangelogOverlay > ( ) . FirstOrDefault ( ) ;
2022-11-10 02:33:28 +08:00
AddUntilStep ( "Wait for settings to load" , ( ) = > Game . Settings . IsLoaded ) ;
2022-11-08 13:58:52 +08:00
AddStep ( "Show settings" , ( ) = > Game . Settings . Show ( ) ) ;
AddUntilStep ( "wait for settings shown" , ( ) = > Game . Settings . IsPresent & & Game . Settings . State . Value = = Visibility . Visible ) ;
AddStep ( "Show changelog listing" , ( ) = > Game . ShowChangelogListing ( ) ) ;
AddUntilStep ( "wait for changelog shown" , ( ) = > getChangelogOverlay ( ) ? . IsPresent = = true & & getChangelogOverlay ( ) ? . State . Value = = Visibility . Visible ) ;
AddAssert ( "Settings is hidden" , ( ) = > Game . Settings . State . Value = = Visibility . Hidden ) ;
AddStep ( "Show settings" , ( ) = > Game . Settings . Show ( ) ) ;
AddUntilStep ( "wait for settings shown" , ( ) = > Game . Settings . State . Value = = Visibility . Visible ) ;
AddUntilStep ( "changelog still visible" , ( ) = > getChangelogOverlay ( ) . State . Value = = Visibility . Visible ) ;
}
2021-08-30 13:27:56 +08:00
[Test]
public void TestOverlayClosing ( )
{
// use now playing overlay for "overlay -> background" drag case
// since most overlays use a scroll container that absorbs on mouse down
NowPlayingOverlay nowPlayingOverlay = null ;
2021-10-07 14:47:59 +08:00
AddUntilStep ( "Wait for now playing load" , ( ) = > ( nowPlayingOverlay = Game . ChildrenOfType < NowPlayingOverlay > ( ) . FirstOrDefault ( ) ) ! = null ) ;
2021-08-30 13:27:56 +08:00
AddStep ( "enter menu" , ( ) = > InputManager . Key ( Key . Enter ) ) ;
2021-10-07 14:47:59 +08:00
AddUntilStep ( "toolbar displayed" , ( ) = > Game . Toolbar . State . Value = = Visibility . Visible ) ;
2021-08-30 13:27:56 +08:00
2021-10-07 14:47:59 +08:00
AddStep ( "open now playing" , ( ) = > InputManager . Key ( Key . F6 ) ) ;
AddUntilStep ( "now playing is visible" , ( ) = > nowPlayingOverlay . State . Value = = Visibility . Visible ) ;
2021-08-30 13:27:56 +08:00
// drag tests
// background -> toolbar
AddStep ( "move cursor to background" , ( ) = > InputManager . MoveMouseTo ( Game . ScreenSpaceDrawQuad . BottomRight ) ) ;
AddStep ( "press left mouse button" , ( ) = > InputManager . PressButton ( MouseButton . Left ) ) ;
AddStep ( "move cursor to toolbar" , ( ) = > InputManager . MoveMouseTo ( Game . Toolbar . ScreenSpaceDrawQuad . Centre ) ) ;
AddStep ( "release left mouse button" , ( ) = > InputManager . ReleaseButton ( MouseButton . Left ) ) ;
2021-08-31 11:53:43 +08:00
AddAssert ( "now playing is hidden" , ( ) = > nowPlayingOverlay . State . Value = = Visibility . Hidden ) ;
AddStep ( "press now playing hotkey" , ( ) = > InputManager . Key ( Key . F6 ) ) ;
2021-08-30 13:27:56 +08:00
// toolbar -> background
AddStep ( "press left mouse button" , ( ) = > InputManager . PressButton ( MouseButton . Left ) ) ;
AddStep ( "move cursor to background" , ( ) = > InputManager . MoveMouseTo ( Game . ScreenSpaceDrawQuad . BottomRight ) ) ;
AddStep ( "release left mouse button" , ( ) = > InputManager . ReleaseButton ( MouseButton . Left ) ) ;
AddAssert ( "now playing is still visible" , ( ) = > nowPlayingOverlay . State . Value = = Visibility . Visible ) ;
// background -> overlay
AddStep ( "press left mouse button" , ( ) = > InputManager . PressButton ( MouseButton . Left ) ) ;
AddStep ( "move cursor to now playing overlay" , ( ) = > InputManager . MoveMouseTo ( nowPlayingOverlay . ScreenSpaceDrawQuad . Centre ) ) ;
AddStep ( "release left mouse button" , ( ) = > InputManager . ReleaseButton ( MouseButton . Left ) ) ;
AddAssert ( "now playing is still visible" , ( ) = > nowPlayingOverlay . State . Value = = Visibility . Visible ) ;
// overlay -> background
AddStep ( "press left mouse button" , ( ) = > InputManager . PressButton ( MouseButton . Left ) ) ;
AddStep ( "move cursor to background" , ( ) = > InputManager . MoveMouseTo ( Game . ScreenSpaceDrawQuad . BottomRight ) ) ;
AddStep ( "release left mouse button" , ( ) = > InputManager . ReleaseButton ( MouseButton . Left ) ) ;
AddAssert ( "now playing is still visible" , ( ) = > nowPlayingOverlay . State . Value = = Visibility . Visible ) ;
// background -> background
AddStep ( "press left mouse button" , ( ) = > InputManager . PressButton ( MouseButton . Left ) ) ;
AddStep ( "move cursor to left" , ( ) = > InputManager . MoveMouseTo ( Game . ScreenSpaceDrawQuad . BottomLeft ) ) ;
AddStep ( "release left mouse button" , ( ) = > InputManager . ReleaseButton ( MouseButton . Left ) ) ;
AddAssert ( "now playing is hidden" , ( ) = > nowPlayingOverlay . State . Value = = Visibility . Hidden ) ;
AddStep ( "press now playing hotkey" , ( ) = > InputManager . Key ( Key . F6 ) ) ;
// click tests
// toolbar
AddStep ( "move cursor to toolbar" , ( ) = > InputManager . MoveMouseTo ( Game . Toolbar . ScreenSpaceDrawQuad . Centre ) ) ;
AddStep ( "click left mouse button" , ( ) = > InputManager . Click ( MouseButton . Left ) ) ;
AddAssert ( "now playing is still visible" , ( ) = > nowPlayingOverlay . State . Value = = Visibility . Visible ) ;
// background
AddStep ( "move cursor to background" , ( ) = > InputManager . MoveMouseTo ( Game . ScreenSpaceDrawQuad . BottomRight ) ) ;
AddStep ( "click left mouse button" , ( ) = > InputManager . Click ( MouseButton . Left ) ) ;
AddAssert ( "now playing is hidden" , ( ) = > nowPlayingOverlay . State . Value = = Visibility . Hidden ) ;
2022-05-24 05:58:12 +08:00
// move the mouse firmly inside game bounds to avoid interfering with other tests.
AddStep ( "center cursor" , ( ) = > InputManager . MoveMouseTo ( Game . ScreenSpaceDrawQuad . Centre ) ) ;
2021-08-30 13:27:56 +08:00
}
2023-06-23 14:30:21 +08:00
[Test]
public void TestExitWithOperationInProgress ( )
{
2024-07-10 21:14:12 +08:00
int x = 0 ;
AddUntilStep ( "wait for dialog overlay" , ( ) = >
{
x = 0 ;
return Game . ChildrenOfType < DialogOverlay > ( ) . SingleOrDefault ( ) ! = null ;
} ) ;
2023-06-23 14:30:21 +08:00
2024-07-10 21:01:45 +08:00
AddRepeatStep ( "start ongoing operation" , ( ) = >
2023-06-23 14:30:21 +08:00
{
2024-07-10 21:01:45 +08:00
Game . Notifications . Post ( new ProgressNotification
2023-06-23 14:30:21 +08:00
{
2024-07-10 21:14:12 +08:00
Text = $"Something is still running #{++x}" ,
2023-06-23 14:30:21 +08:00
Progress = 0.5f ,
State = ProgressNotificationState . Active ,
2024-07-10 21:01:45 +08:00
} ) ;
} , 15 ) ;
2023-06-23 14:30:21 +08:00
2024-07-10 21:14:12 +08:00
AddAssert ( "all notifications = 15" , ( ) = > Game . Notifications . AllNotifications . Count ( ) , ( ) = > Is . EqualTo ( 15 ) ) ;
2023-06-23 14:30:21 +08:00
AddStep ( "Hold escape" , ( ) = > InputManager . PressKey ( Key . Escape ) ) ;
AddUntilStep ( "confirmation dialog shown" , ( ) = > Game . ChildrenOfType < DialogOverlay > ( ) . Single ( ) . CurrentDialog is ConfirmExitDialog ) ;
AddStep ( "Release escape" , ( ) = > InputManager . ReleaseKey ( Key . Escape ) ) ;
AddStep ( "cancel exit" , ( ) = > InputManager . Key ( Key . Escape ) ) ;
AddAssert ( "dialog dismissed" , ( ) = > Game . ChildrenOfType < DialogOverlay > ( ) . Single ( ) . CurrentDialog = = null ) ;
AddStep ( "complete operation" , ( ) = >
{
2024-07-10 21:01:45 +08:00
this . ChildrenOfType < ProgressNotification > ( ) . ForEach ( n = >
{
n . Progress = 100 ;
n . State = ProgressNotificationState . Completed ;
} ) ;
2023-06-23 14:30:21 +08:00
} ) ;
AddStep ( "Hold escape" , ( ) = > InputManager . PressKey ( Key . Escape ) ) ;
AddUntilStep ( "Wait for intro" , ( ) = > Game . ScreenStack . CurrentScreen is IntroScreen ) ;
AddStep ( "Release escape" , ( ) = > InputManager . ReleaseKey ( Key . Escape ) ) ;
AddUntilStep ( "Wait for game exit" , ( ) = > Game . ScreenStack . CurrentScreen = = null ) ;
}
2023-07-16 22:28:44 +08:00
[Test]
public void TestForceExitWithOperationInProgress ( )
{
AddStep ( "set hold delay to 0" , ( ) = > Game . LocalConfig . SetValue ( OsuSetting . UIHoldActivationDelay , 0.0 ) ) ;
AddUntilStep ( "wait for dialog overlay" , ( ) = > Game . ChildrenOfType < DialogOverlay > ( ) . SingleOrDefault ( ) ! = null ) ;
2024-07-10 21:01:45 +08:00
AddRepeatStep ( "start ongoing operation" , ( ) = >
2023-07-16 22:28:44 +08:00
{
2023-07-16 23:10:26 +08:00
Game . Notifications . Post ( new ProgressNotification
2023-07-16 22:28:44 +08:00
{
Text = "Something is still running" ,
Progress = 0.5f ,
State = ProgressNotificationState . Active ,
2023-07-16 23:10:26 +08:00
} ) ;
2024-07-10 21:01:45 +08:00
} , 15 ) ;
2023-07-16 22:28:44 +08:00
2024-01-05 01:00:24 +08:00
AddRepeatStep ( "attempt force exit" , ( ) = > Game . ScreenStack . CurrentScreen . Exit ( ) , 2 ) ;
2023-07-16 22:28:44 +08:00
AddUntilStep ( "stopped at exit confirm" , ( ) = > Game . ChildrenOfType < DialogOverlay > ( ) . Single ( ) . CurrentDialog is ConfirmExitDialog ) ;
}
2021-09-10 17:16:10 +08:00
[Test]
public void TestExitGameFromSongSelect ( )
{
PushAndConfirm ( ( ) = > new TestPlaySongSelect ( ) ) ;
exitViaEscapeAndConfirm ( ) ;
pushEscape ( ) ; // returns to osu! logo
AddStep ( "Hold escape" , ( ) = > InputManager . PressKey ( Key . Escape ) ) ;
2021-10-07 14:47:59 +08:00
AddUntilStep ( "Wait for intro" , ( ) = > Game . ScreenStack . CurrentScreen is IntroScreen ) ;
2021-09-14 14:08:43 +08:00
AddStep ( "Release escape" , ( ) = > InputManager . ReleaseKey ( Key . Escape ) ) ;
2021-09-10 17:16:10 +08:00
AddUntilStep ( "Wait for game exit" , ( ) = > Game . ScreenStack . CurrentScreen = = null ) ;
2021-09-13 17:32:58 +08:00
AddStep ( "test dispose doesn't crash" , ( ) = > Game . Dispose ( ) ) ;
2021-09-10 17:16:10 +08:00
}
2022-01-28 14:50:22 +08:00
2022-05-05 00:26:58 +08:00
[Test]
2023-06-23 14:30:21 +08:00
public void TestExitWithHoldDisabled ( )
2022-05-05 00:26:58 +08:00
{
AddStep ( "set hold delay to 0" , ( ) = > Game . LocalConfig . SetValue ( OsuSetting . UIHoldActivationDelay , 0.0 ) ) ;
AddStep ( "press escape twice rapidly" , ( ) = >
{
InputManager . Key ( Key . Escape ) ;
2023-05-08 03:07:38 +08:00
Schedule ( InputManager . Key , Key . Escape ) ;
2022-05-05 00:26:58 +08:00
} ) ;
pushEscape ( ) ;
2023-06-23 14:30:21 +08:00
AddAssert ( "exit dialog is shown" , ( ) = > Game . Dependencies . Get < IDialogOverlay > ( ) . CurrentDialog is ConfirmExitDialog ) ;
2022-05-05 00:26:58 +08:00
}
2024-01-16 14:21:43 +08:00
[Test]
public void TestQuickSkinEditorDoesntNukeSkin ( )
{
AddStep ( "import beatmap" , ( ) = > BeatmapImportHelper . LoadQuickOszIntoOsu ( Game ) . WaitSafely ( ) ) ;
AddStep ( "open" , ( ) = > InputManager . Key ( Key . Space ) ) ;
AddStep ( "skin" , ( ) = > InputManager . Key ( Key . E ) ) ;
AddStep ( "editor" , ( ) = > InputManager . Key ( Key . S ) ) ;
AddStep ( "and close immediately" , ( ) = > InputManager . Key ( Key . Escape ) ) ;
AddStep ( "open again" , ( ) = > InputManager . Key ( Key . S ) ) ;
Player player = null ;
AddUntilStep ( "wait for player" , ( ) = > ( player = Game . ScreenStack . CurrentScreen as Player ) ! = null ) ;
AddUntilStep ( "wait for gameplay still has health bar" , ( ) = > player . ChildrenOfType < ArgonHealthDisplay > ( ) . Any ( ) ) ;
}
2023-10-30 21:08:56 +08:00
[Test]
2023-11-03 05:14:38 +08:00
public void TestTouchScreenDetectionAtSongSelect ( )
2023-10-30 21:08:56 +08:00
{
2024-07-18 14:57:57 +08:00
AddUntilStep ( "wait for settings" , ( ) = > Game . Settings . IsLoaded ) ;
2023-10-30 21:08:56 +08:00
AddStep ( "touch logo" , ( ) = >
{
var button = Game . ChildrenOfType < OsuLogo > ( ) . Single ( ) ;
var touch = new Touch ( TouchSource . Touch1 , button . ScreenSpaceDrawQuad . Centre ) ;
InputManager . BeginTouch ( touch ) ;
InputManager . EndTouch ( touch ) ;
} ) ;
AddAssert ( "touch screen detected active" , ( ) = > Game . Dependencies . Get < SessionStatics > ( ) . Get < bool > ( Static . TouchInputActive ) , ( ) = > Is . True ) ;
AddStep ( "click settings button" , ( ) = >
{
var button = Game . ChildrenOfType < MainMenuButton > ( ) . Last ( ) ;
InputManager . MoveMouseTo ( button ) ;
InputManager . Click ( MouseButton . Left ) ;
} ) ;
AddAssert ( "touch screen detected inactive" , ( ) = > Game . Dependencies . Get < SessionStatics > ( ) . Get < bool > ( Static . TouchInputActive ) , ( ) = > Is . False ) ;
2023-10-30 21:38:20 +08:00
AddStep ( "close settings sidebar" , ( ) = > InputManager . Key ( Key . Escape ) ) ;
2023-10-26 01:56:51 +08:00
Screens . Select . SongSelect songSelect = null ;
2023-11-03 05:14:38 +08:00
AddRepeatStep ( "go to solo" , ( ) = > InputManager . Key ( Key . P ) , 3 ) ;
AddUntilStep ( "wait for song select" , ( ) = > ( songSelect = Game . ScreenStack . CurrentScreen as Screens . Select . SongSelect ) ! = null ) ;
AddUntilStep ( "wait for beatmap sets loaded" , ( ) = > songSelect . BeatmapSetsLoaded ) ;
2023-10-26 01:56:51 +08:00
2023-10-30 21:38:20 +08:00
AddStep ( "switch to osu! ruleset" , ( ) = >
{
InputManager . PressKey ( Key . LControl ) ;
InputManager . Key ( Key . Number1 ) ;
InputManager . ReleaseKey ( Key . LControl ) ;
} ) ;
AddStep ( "touch beatmap wedge" , ( ) = >
{
var wedge = Game . ChildrenOfType < BeatmapInfoWedge > ( ) . Single ( ) ;
var touch = new Touch ( TouchSource . Touch2 , wedge . ScreenSpaceDrawQuad . Centre ) ;
InputManager . BeginTouch ( touch ) ;
InputManager . EndTouch ( touch ) ;
} ) ;
AddUntilStep ( "touch device mod activated" , ( ) = > Game . SelectedMods . Value , ( ) = > Has . One . InstanceOf < ModTouchDevice > ( ) ) ;
AddStep ( "switch to mania ruleset" , ( ) = >
{
InputManager . PressKey ( Key . LControl ) ;
InputManager . Key ( Key . Number4 ) ;
InputManager . ReleaseKey ( Key . LControl ) ;
} ) ;
AddUntilStep ( "touch device mod not activated" , ( ) = > Game . SelectedMods . Value , ( ) = > Has . None . InstanceOf < ModTouchDevice > ( ) ) ;
AddStep ( "touch beatmap wedge" , ( ) = >
{
var wedge = Game . ChildrenOfType < BeatmapInfoWedge > ( ) . Single ( ) ;
var touch = new Touch ( TouchSource . Touch2 , wedge . ScreenSpaceDrawQuad . Centre ) ;
InputManager . BeginTouch ( touch ) ;
InputManager . EndTouch ( touch ) ;
} ) ;
AddUntilStep ( "touch device mod not activated" , ( ) = > Game . SelectedMods . Value , ( ) = > Has . None . InstanceOf < ModTouchDevice > ( ) ) ;
AddStep ( "switch to osu! ruleset" , ( ) = >
{
InputManager . PressKey ( Key . LControl ) ;
InputManager . Key ( Key . Number1 ) ;
InputManager . ReleaseKey ( Key . LControl ) ;
} ) ;
AddUntilStep ( "touch device mod activated" , ( ) = > Game . SelectedMods . Value , ( ) = > Has . One . InstanceOf < ModTouchDevice > ( ) ) ;
2023-10-31 20:47:50 +08:00
AddStep ( "click beatmap wedge" , ( ) = >
{
InputManager . MoveMouseTo ( Game . ChildrenOfType < BeatmapInfoWedge > ( ) . Single ( ) ) ;
InputManager . Click ( MouseButton . Left ) ;
} ) ;
AddUntilStep ( "touch device mod not activated" , ( ) = > Game . SelectedMods . Value , ( ) = > Has . None . InstanceOf < ModTouchDevice > ( ) ) ;
2023-11-03 05:14:38 +08:00
}
2023-10-31 20:47:50 +08:00
2023-11-03 05:14:38 +08:00
[Test]
public void TestTouchScreenDetectionInGame ( )
{
2024-08-28 22:29:32 +08:00
BeatmapSetInfo beatmapSet = null ;
2023-11-03 05:14:38 +08:00
PushAndConfirm ( ( ) = > new TestPlaySongSelect ( ) ) ;
2024-08-28 22:29:32 +08:00
AddStep ( "import beatmap" , ( ) = > beatmapSet = BeatmapImportHelper . LoadQuickOszIntoOsu ( Game ) . GetResultSafely ( ) ) ;
AddUntilStep ( "wait for selected" , ( ) = > Game . Beatmap . Value . BeatmapSetInfo . Equals ( beatmapSet ) ) ;
2023-11-03 05:14:38 +08:00
AddStep ( "select" , ( ) = > InputManager . Key ( Key . Enter ) ) ;
2023-10-31 20:47:50 +08:00
Player player = null ;
AddUntilStep ( "wait for player" , ( ) = >
{
DismissAnyNotifications ( ) ;
return ( player = Game . ScreenStack . CurrentScreen as Player ) ! = null ;
} ) ;
AddUntilStep ( "wait for track playing" , ( ) = > Game . Beatmap . Value . Track . IsRunning ) ;
AddStep ( "touch" , ( ) = >
{
var touch = new Touch ( TouchSource . Touch2 , Game . ScreenSpaceDrawQuad . Centre ) ;
InputManager . BeginTouch ( touch ) ;
InputManager . EndTouch ( touch ) ;
} ) ;
AddUntilStep ( "touch device mod added to score" , ( ) = > player . Score . ScoreInfo . Mods , ( ) = > Has . One . InstanceOf < ModTouchDevice > ( ) ) ;
AddStep ( "exit player" , ( ) = > player . Exit ( ) ) ;
AddUntilStep ( "touch device mod still active" , ( ) = > Game . SelectedMods . Value , ( ) = > Has . One . InstanceOf < ModTouchDevice > ( ) ) ;
2023-10-30 21:08:56 +08:00
}
2024-01-09 04:33:25 +08:00
[Test]
public void TestExitSongSelectAndImmediatelyClickLogo ( )
{
Screens . Select . SongSelect songSelect = null ;
PushAndConfirm ( ( ) = > songSelect = new TestPlaySongSelect ( ) ) ;
AddUntilStep ( "wait for song select" , ( ) = > songSelect . BeatmapSetsLoaded ) ;
AddStep ( "import beatmap" , ( ) = > BeatmapImportHelper . LoadQuickOszIntoOsu ( Game ) . WaitSafely ( ) ) ;
AddUntilStep ( "wait for selected" , ( ) = > ! Game . Beatmap . IsDefault ) ;
AddStep ( "press escape and then click logo immediately" , ( ) = >
{
InputManager . Key ( Key . Escape ) ;
clickLogoWhenNotCurrent ( ) ;
} ) ;
void clickLogoWhenNotCurrent ( )
{
if ( songSelect . IsCurrentScreen ( ) )
Scheduler . AddOnce ( clickLogoWhenNotCurrent ) ;
else
{
InputManager . MoveMouseTo ( Game . ChildrenOfType < OsuLogo > ( ) . Single ( ) ) ;
InputManager . Click ( MouseButton . Left ) ;
}
}
}
2024-02-14 07:04:19 +08:00
[Test]
public void TestPresentBeatmapAfterDeletion ( )
{
BeatmapSetInfo beatmap = null ;
Screens . Select . SongSelect songSelect = null ;
PushAndConfirm ( ( ) = > songSelect = new TestPlaySongSelect ( ) ) ;
AddUntilStep ( "wait for song select" , ( ) = > songSelect . BeatmapSetsLoaded ) ;
AddStep ( "import beatmap" , ( ) = > BeatmapImportHelper . LoadQuickOszIntoOsu ( Game ) . WaitSafely ( ) ) ;
AddUntilStep ( "wait for selected" , ( ) = > ! Game . Beatmap . IsDefault ) ;
AddStep ( "delete selected beatmap" , ( ) = >
{
beatmap = Game . Beatmap . Value . BeatmapSetInfo ;
Game . BeatmapManager . Delete ( Game . Beatmap . Value . BeatmapSetInfo ) ;
} ) ;
AddUntilStep ( "nothing selected" , ( ) = > Game . Beatmap . IsDefault ) ;
AddStep ( "present deleted beatmap" , ( ) = > Game . PresentBeatmap ( beatmap ) ) ;
AddAssert ( "still nothing selected" , ( ) = > Game . Beatmap . IsDefault ) ;
}
2022-01-28 14:50:22 +08:00
private Func < Player > playToResults ( )
2023-10-12 14:42:16 +08:00
{
var player = playToCompletion ( ) ;
AddUntilStep ( "wait for results" , ( ) = > ( Game . ScreenStack . CurrentScreen as ResultsScreen ) ? . IsLoaded = = true ) ;
return player ;
}
private Func < Player > playToCompletion ( )
2022-01-28 14:50:22 +08:00
{
Player player = null ;
IWorkingBeatmap beatmap ( ) = > Game . Beatmap . Value ;
Screens . Select . SongSelect songSelect = null ;
PushAndConfirm ( ( ) = > songSelect = new TestPlaySongSelect ( ) ) ;
AddUntilStep ( "wait for song select" , ( ) = > songSelect . BeatmapSetsLoaded ) ;
AddStep ( "import beatmap" , ( ) = > BeatmapImportHelper . LoadQuickOszIntoOsu ( Game ) . WaitSafely ( ) ) ;
AddUntilStep ( "wait for selected" , ( ) = > ! Game . Beatmap . IsDefault ) ;
AddStep ( "set mods" , ( ) = > Game . SelectedMods . Value = new Mod [ ] { new OsuModNoFail ( ) , new OsuModDoubleTime { SpeedChange = { Value = 2 } } } ) ;
AddStep ( "press enter" , ( ) = > InputManager . Key ( Key . Enter ) ) ;
AddUntilStep ( "wait for player" , ( ) = >
{
2022-04-24 04:14:14 +08:00
DismissAnyNotifications ( ) ;
2022-01-28 14:50:22 +08:00
return ( player = Game . ScreenStack . CurrentScreen as Player ) ! = null ;
} ) ;
AddUntilStep ( "wait for track playing" , ( ) = > beatmap ( ) . Track . IsRunning ) ;
AddStep ( "seek to near end" , ( ) = > player . ChildrenOfType < GameplayClockContainer > ( ) . First ( ) . Seek ( beatmap ( ) . Beatmap . HitObjects [ ^ 1 ] . StartTime - 1000 ) ) ;
2023-10-12 14:42:16 +08:00
AddUntilStep ( "wait for complete" , ( ) = > player . GameplayState . HasPassed ) ;
2022-01-28 14:50:22 +08:00
return ( ) = > player ;
}
2021-09-10 17:16:10 +08:00
2019-10-10 10:58:43 +08:00
private void pushEscape ( ) = >
2020-11-05 22:41:56 +08:00
AddStep ( "Press escape" , ( ) = > InputManager . Key ( Key . Escape ) ) ;
2019-10-10 10:58:43 +08:00
2019-07-29 13:30:46 +08:00
private void exitViaEscapeAndConfirm ( )
{
2019-10-10 10:58:43 +08:00
pushEscape ( ) ;
2020-01-29 13:23:23 +08:00
ConfirmAtMainMenu ( ) ;
2019-07-29 13:30:46 +08:00
}
private void exitViaBackButtonAndConfirm ( )
{
2019-07-31 18:30:35 +08:00
AddStep ( "Move mouse to backButton" , ( ) = > InputManager . MoveMouseTo ( backButtonPosition ) ) ;
2019-07-29 13:30:46 +08:00
AddStep ( "Click back button" , ( ) = > InputManager . Click ( MouseButton . Left ) ) ;
2020-01-29 13:23:23 +08:00
ConfirmAtMainMenu ( ) ;
2019-07-29 13:30:46 +08:00
}
2022-11-24 13:32:20 +08:00
public partial class TestPlaySongSelect : PlaySongSelect
2019-07-29 13:30:46 +08:00
{
2022-05-11 04:29:57 +08:00
public ModSelectOverlay ModSelectOverlay = > ModSelect ;
2020-09-15 02:21:39 +08:00
public BeatmapOptionsOverlay BeatmapOptionsOverlay = > BeatmapOptions ;
2019-07-29 13:30:46 +08:00
}
}
}