2020-02-14 14:01:45 +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.
2020-02-14 14:36:47 +08:00
using System.Collections.Generic ;
2021-11-01 14:42:12 +08:00
using System.Diagnostics ;
2020-02-14 14:01:45 +08:00
using System.Linq ;
using NUnit.Framework ;
2020-06-02 13:31:43 +08:00
using osu.Framework.Allocation ;
using osu.Framework.Audio ;
2020-02-14 14:01:45 +08:00
using osu.Framework.Graphics ;
2020-02-14 15:48:30 +08:00
using osu.Framework.Graphics.Containers ;
2020-06-02 13:31:43 +08:00
using osu.Framework.Platform ;
2020-02-14 15:48:30 +08:00
using osu.Framework.Testing ;
2020-06-02 13:31:43 +08:00
using osu.Game.Beatmaps ;
2021-02-02 16:21:46 +08:00
using osu.Game.Beatmaps.Drawables ;
2021-11-25 22:15:28 +08:00
using osu.Game.Database ;
2020-02-14 15:48:30 +08:00
using osu.Game.Graphics.Containers ;
2021-11-04 17:02:44 +08:00
using osu.Game.Online.API.Requests.Responses ;
2020-12-25 12:38:11 +08:00
using osu.Game.Online.Rooms ;
2020-06-02 13:31:43 +08:00
using osu.Game.Rulesets ;
2020-02-14 16:57:25 +08:00
using osu.Game.Rulesets.Osu ;
2020-02-14 14:01:45 +08:00
using osu.Game.Rulesets.Osu.Mods ;
2020-12-25 23:50:00 +08:00
using osu.Game.Screens.OnlinePlay ;
2020-02-14 16:57:25 +08:00
using osu.Game.Tests.Beatmaps ;
2021-11-26 16:40:45 +08:00
using osu.Game.Users.Drawables ;
2020-02-14 14:01:45 +08:00
using osuTK ;
2020-02-14 15:48:30 +08:00
using osuTK.Input ;
2020-02-14 14:01:45 +08:00
namespace osu.Game.Tests.Visual.Multiplayer
{
2020-03-23 09:01:33 +08:00
public class TestSceneDrawableRoomPlaylist : OsuManualInputManagerTestScene
2020-02-14 14:01:45 +08:00
{
2020-02-20 07:37:23 +08:00
private TestPlaylist playlist ;
2020-02-14 14:01:45 +08:00
2020-06-02 13:31:43 +08:00
private BeatmapManager manager ;
private RulesetStore rulesets ;
2021-11-25 22:15:28 +08:00
[Cached(typeof(UserLookupCache))]
private readonly TestUserLookupCache userLookupCache = new TestUserLookupCache ( ) ;
2020-06-02 13:31:43 +08:00
[BackgroundDependencyLoader]
private void load ( GameHost host , AudioManager audio )
{
Dependencies . Cache ( rulesets = new RulesetStore ( ContextFactory ) ) ;
2021-05-31 17:37:32 +08:00
Dependencies . Cache ( manager = new BeatmapManager ( LocalStorage , ContextFactory , rulesets , null , audio , Resources , host , Beatmap . Default ) ) ;
2020-06-02 13:31:43 +08:00
}
2020-02-14 14:01:45 +08:00
[Test]
2020-02-14 14:36:47 +08:00
public void TestNonEditableNonSelectable ( )
2020-02-14 14:01:45 +08:00
{
createPlaylist ( false , false ) ;
2020-02-14 15:48:30 +08:00
moveToItem ( 0 ) ;
assertHandleVisibility ( 0 , false ) ;
assertDeleteButtonVisibility ( 0 , false ) ;
2020-02-14 15:55:05 +08:00
AddStep ( "click" , ( ) = > InputManager . Click ( MouseButton . Left ) ) ;
AddAssert ( "no item selected" , ( ) = > playlist . SelectedItem . Value = = null ) ;
2020-02-14 14:01:45 +08:00
}
[Test]
2020-02-14 14:36:47 +08:00
public void TestEditable ( )
2020-02-14 14:01:45 +08:00
{
createPlaylist ( true , false ) ;
2020-02-14 15:48:30 +08:00
moveToItem ( 0 ) ;
assertHandleVisibility ( 0 , true ) ;
assertDeleteButtonVisibility ( 0 , true ) ;
2020-02-14 15:55:05 +08:00
AddStep ( "click" , ( ) = > InputManager . Click ( MouseButton . Left ) ) ;
AddAssert ( "no item selected" , ( ) = > playlist . SelectedItem . Value = = null ) ;
2020-02-14 14:01:45 +08:00
}
2021-11-16 16:08:21 +08:00
[Test]
public void TestMarkInvalid ( )
{
createPlaylist ( true , true ) ;
AddStep ( "mark item 0 as invalid" , ( ) = > playlist . Items [ 0 ] . MarkInvalid ( ) ) ;
moveToItem ( 0 ) ;
2020-02-14 15:55:05 +08:00
AddStep ( "click" , ( ) = > InputManager . Click ( MouseButton . Left ) ) ;
AddAssert ( "no item selected" , ( ) = > playlist . SelectedItem . Value = = null ) ;
2020-02-14 14:01:45 +08:00
}
[Test]
2020-02-14 14:36:47 +08:00
public void TestSelectable ( )
2020-02-14 14:01:45 +08:00
{
createPlaylist ( false , true ) ;
2020-02-14 15:48:30 +08:00
moveToItem ( 0 ) ;
assertHandleVisibility ( 0 , false ) ;
assertDeleteButtonVisibility ( 0 , false ) ;
AddStep ( "click" , ( ) = > InputManager . Click ( MouseButton . Left ) ) ;
AddAssert ( "item 0 is selected" , ( ) = > playlist . SelectedItem . Value = = playlist . Items [ 0 ] ) ;
2020-02-14 14:01:45 +08:00
}
[Test]
2020-02-14 14:36:47 +08:00
public void TestEditableSelectable ( )
2020-02-14 14:01:45 +08:00
{
createPlaylist ( true , true ) ;
2020-02-14 15:48:30 +08:00
moveToItem ( 0 ) ;
assertHandleVisibility ( 0 , true ) ;
assertDeleteButtonVisibility ( 0 , true ) ;
AddStep ( "click" , ( ) = > InputManager . Click ( MouseButton . Left ) ) ;
AddAssert ( "item 0 is selected" , ( ) = > playlist . SelectedItem . Value = = playlist . Items [ 0 ] ) ;
}
[Test]
public void TestSelectionNotLostAfterRearrangement ( )
{
createPlaylist ( true , true ) ;
moveToItem ( 0 ) ;
AddStep ( "click" , ( ) = > InputManager . Click ( MouseButton . Left ) ) ;
moveToDragger ( 0 ) ;
AddStep ( "begin drag" , ( ) = > InputManager . PressButton ( MouseButton . Left ) ) ;
moveToDragger ( 1 , new Vector2 ( 0 , 5 ) ) ;
AddStep ( "end drag" , ( ) = > InputManager . ReleaseButton ( MouseButton . Left ) ) ;
AddAssert ( "item 1 is selected" , ( ) = > playlist . SelectedItem . Value = = playlist . Items [ 1 ] ) ;
}
[Test]
public void TestItemRemovedOnDeletion ( )
{
PlaylistItem selectedItem = null ;
createPlaylist ( true , true ) ;
moveToItem ( 0 ) ;
AddStep ( "click" , ( ) = > InputManager . Click ( MouseButton . Left ) ) ;
AddStep ( "retrieve selection" , ( ) = > selectedItem = playlist . SelectedItem . Value ) ;
moveToDeleteButton ( 0 ) ;
AddStep ( "click delete button" , ( ) = > InputManager . Click ( MouseButton . Left ) ) ;
AddAssert ( "item removed" , ( ) = > ! playlist . Items . Contains ( selectedItem ) ) ;
}
[Test]
public void TestNextItemSelectedAfterDeletion ( )
{
createPlaylist ( true , true ) ;
moveToItem ( 0 ) ;
AddStep ( "click" , ( ) = > InputManager . Click ( MouseButton . Left ) ) ;
moveToDeleteButton ( 0 ) ;
AddStep ( "click delete button" , ( ) = > InputManager . Click ( MouseButton . Left ) ) ;
AddAssert ( "item 0 is selected" , ( ) = > playlist . SelectedItem . Value = = playlist . Items [ 0 ] ) ;
}
[Test]
public void TestLastItemSelectedAfterLastItemDeleted ( )
{
createPlaylist ( true , true ) ;
AddWaitStep ( "wait for flow" , 5 ) ; // Items may take 1 update frame to flow. A wait count of 5 is guaranteed to result in the flow being updated as desired.
AddStep ( "scroll to bottom" , ( ) = > playlist . ChildrenOfType < ScrollContainer < Drawable > > ( ) . First ( ) . ScrollToEnd ( false ) ) ;
moveToItem ( 19 ) ;
AddStep ( "click" , ( ) = > InputManager . Click ( MouseButton . Left ) ) ;
moveToDeleteButton ( 19 ) ;
AddStep ( "click delete button" , ( ) = > InputManager . Click ( MouseButton . Left ) ) ;
AddAssert ( "item 18 is selected" , ( ) = > playlist . SelectedItem . Value = = playlist . Items [ 18 ] ) ;
}
[Test]
public void TestSelectionResetWhenAllItemsDeleted ( )
{
createPlaylist ( true , true ) ;
AddStep ( "remove all but one item" , ( ) = >
{
playlist . Items . RemoveRange ( 1 , playlist . Items . Count - 1 ) ;
} ) ;
moveToItem ( 0 ) ;
AddStep ( "click" , ( ) = > InputManager . Click ( MouseButton . Left ) ) ;
moveToDeleteButton ( 0 ) ;
AddStep ( "click delete button" , ( ) = > InputManager . Click ( MouseButton . Left ) ) ;
2020-02-14 15:55:05 +08:00
AddAssert ( "no item selected" , ( ) = > playlist . SelectedItem . Value = = null ) ;
2020-02-14 15:48:30 +08:00
}
// Todo: currently not possible due to bindable list shortcomings (https://github.com/ppy/osu-framework/issues/3081)
// [Test]
public void TestNextItemSelectedAfterExternalDeletion ( )
{
createPlaylist ( true , true ) ;
moveToItem ( 0 ) ;
AddStep ( "click" , ( ) = > InputManager . Click ( MouseButton . Left ) ) ;
AddStep ( "remove item 0" , ( ) = > playlist . Items . RemoveAt ( 0 ) ) ;
AddAssert ( "item 0 is selected" , ( ) = > playlist . SelectedItem . Value = = playlist . Items [ 0 ] ) ;
2020-02-14 14:01:45 +08:00
}
2020-02-15 23:22:14 +08:00
[Test]
public void TestChangeBeatmapAndRemove ( )
{
createPlaylist ( true , true ) ;
AddStep ( "change beatmap of first item" , ( ) = > playlist . Items [ 0 ] . BeatmapID = 30 ) ;
moveToDeleteButton ( 0 ) ;
AddStep ( "click delete button" , ( ) = > InputManager . Click ( MouseButton . Left ) ) ;
}
2020-06-02 13:31:43 +08:00
[Test]
2021-01-18 00:17:14 +08:00
public void TestDownloadButtonHiddenWhenBeatmapExists ( )
2020-06-02 13:31:43 +08:00
{
2021-10-28 16:10:04 +08:00
var beatmap = new TestBeatmap ( new OsuRuleset ( ) . RulesetInfo ) . BeatmapInfo ;
AddStep ( "import beatmap" , ( ) = > manager . Import ( beatmap . BeatmapSet ) . Wait ( ) ) ;
createPlaylist ( beatmap ) ;
2020-06-02 13:31:43 +08:00
2021-01-18 01:08:58 +08:00
assertDownloadButtonVisible ( false ) ;
2021-01-18 00:17:14 +08:00
AddStep ( "delete beatmap set" , ( ) = > manager . Delete ( manager . QueryBeatmapSets ( _ = > true ) . Single ( ) ) ) ;
2021-01-18 01:08:58 +08:00
assertDownloadButtonVisible ( true ) ;
2021-01-18 00:17:14 +08:00
AddStep ( "undelete beatmap set" , ( ) = > manager . Undelete ( manager . QueryBeatmapSets ( _ = > true ) . Single ( ) ) ) ;
2021-01-18 01:08:58 +08:00
assertDownloadButtonVisible ( false ) ;
void assertDownloadButtonVisible ( bool visible ) = > AddUntilStep ( $"download button {(visible ? " shown " : " hidden ")}" ,
2021-11-27 22:08:03 +08:00
( ) = > playlist . ChildrenOfType < BeatmapDownloadButton > ( ) . Single ( ) . Alpha = = ( visible ? 1 : 0 ) ) ;
2020-06-02 13:31:43 +08:00
}
[Test]
public void TestDownloadButtonVisibleInitiallyWhenBeatmapDoesNotExist ( )
{
2021-11-01 14:42:12 +08:00
var byOnlineId = CreateAPIBeatmap ( ) ;
2021-11-01 15:43:39 +08:00
byOnlineId . OnlineID = 1337 ; // Some random ID that does not exist locally.
2020-06-02 13:31:43 +08:00
2021-11-01 14:42:12 +08:00
var byChecksum = CreateAPIBeatmap ( ) ;
byChecksum . Checksum = "1337" ; // Some random checksum that does not exist locally.
2020-06-02 13:31:43 +08:00
createPlaylist ( byOnlineId , byChecksum ) ;
2021-11-27 22:08:03 +08:00
AddAssert ( "download buttons shown" , ( ) = > playlist . ChildrenOfType < BeatmapDownloadButton > ( ) . All ( d = > d . IsPresent ) ) ;
2020-06-02 13:31:43 +08:00
}
2021-01-13 16:57:29 +08:00
[Test]
public void TestExplicitBeatmapItem ( )
{
2021-11-01 14:42:12 +08:00
var beatmap = CreateAPIBeatmap ( ) ;
2021-11-01 15:43:39 +08:00
2021-11-01 14:42:12 +08:00
Debug . Assert ( beatmap . BeatmapSet ! = null ) ;
beatmap . BeatmapSet . HasExplicitContent = true ;
2021-01-13 16:57:29 +08:00
createPlaylist ( beatmap ) ;
}
2021-10-22 20:04:52 +08:00
[Test]
public void TestExpiredItems ( )
{
AddStep ( "create playlist" , ( ) = >
{
Child = playlist = new TestPlaylist ( false , false )
{
Anchor = Anchor . Centre ,
Origin = Anchor . Centre ,
Size = new Vector2 ( 500 , 300 ) ,
Items =
{
new PlaylistItem
{
ID = 0 ,
Beatmap = { Value = new TestBeatmap ( new OsuRuleset ( ) . RulesetInfo ) . BeatmapInfo } ,
Ruleset = { Value = new OsuRuleset ( ) . RulesetInfo } ,
Expired = true ,
RequiredMods =
{
new OsuModHardRock ( ) ,
new OsuModDoubleTime ( ) ,
new OsuModAutoplay ( )
}
} ,
new PlaylistItem
{
ID = 1 ,
Beatmap = { Value = new TestBeatmap ( new OsuRuleset ( ) . RulesetInfo ) . BeatmapInfo } ,
Ruleset = { Value = new OsuRuleset ( ) . RulesetInfo } ,
RequiredMods =
{
new OsuModHardRock ( ) ,
new OsuModDoubleTime ( ) ,
new OsuModAutoplay ( )
}
}
}
} ;
} ) ;
AddUntilStep ( "wait for items to load" , ( ) = > playlist . ItemMap . Values . All ( i = > i . IsLoaded ) ) ;
}
2021-11-26 16:40:45 +08:00
[TestCase(false)]
[TestCase(true)]
public void TestWithOwner ( bool withOwner )
{
createPlaylist ( false , false , withOwner ) ;
AddAssert ( "owner visible" , ( ) = > playlist . ChildrenOfType < UpdateableAvatar > ( ) . All ( a = > a . IsPresent = = withOwner ) ) ;
}
2020-02-14 15:48:30 +08:00
private void moveToItem ( int index , Vector2 ? offset = null )
2021-02-02 16:21:46 +08:00
= > AddStep ( $"move mouse to item {index}" , ( ) = > InputManager . MoveMouseTo ( playlist . ChildrenOfType < DifficultyIcon > ( ) . ElementAt ( index ) , offset ) ) ;
2020-02-14 15:48:30 +08:00
private void moveToDragger ( int index , Vector2 ? offset = null ) = > AddStep ( $"move mouse to dragger {index}" , ( ) = >
{
var item = playlist . ChildrenOfType < OsuRearrangeableListItem < PlaylistItem > > ( ) . ElementAt ( index ) ;
InputManager . MoveMouseTo ( item . ChildrenOfType < OsuRearrangeableListItem < PlaylistItem > . PlaylistItemHandle > ( ) . Single ( ) , offset ) ;
} ) ;
private void moveToDeleteButton ( int index , Vector2 ? offset = null ) = > AddStep ( $"move mouse to delete button {index}" , ( ) = >
{
var item = playlist . ChildrenOfType < OsuRearrangeableListItem < PlaylistItem > > ( ) . ElementAt ( index ) ;
2021-02-02 16:21:46 +08:00
InputManager . MoveMouseTo ( item . ChildrenOfType < DrawableRoomPlaylistItem . PlaylistRemoveButton > ( ) . ElementAt ( 0 ) , offset ) ;
2020-02-14 15:48:30 +08:00
} ) ;
private void assertHandleVisibility ( int index , bool visible )
= > AddAssert ( $"handle {index} {(visible ? " is " : " is not ")} visible" ,
( ) = > ( playlist . ChildrenOfType < OsuRearrangeableListItem < PlaylistItem > . PlaylistItemHandle > ( ) . ElementAt ( index ) . Alpha > 0 ) = = visible ) ;
private void assertDeleteButtonVisibility ( int index , bool visible )
2021-10-22 20:04:52 +08:00
= > AddAssert ( $"delete button {index} {(visible ? " is " : " is not ")} visible" ,
( ) = > ( playlist . ChildrenOfType < DrawableRoomPlaylistItem . PlaylistRemoveButton > ( ) . ElementAt ( 2 + index * 2 ) . Alpha > 0 ) = = visible ) ;
2020-02-14 15:48:30 +08:00
2021-11-26 16:40:45 +08:00
private void createPlaylist ( bool allowEdit , bool allowSelection , bool showItemOwner = false )
2020-02-14 14:01:45 +08:00
{
2020-02-20 07:37:23 +08:00
AddStep ( "create playlist" , ( ) = >
2020-02-14 14:01:45 +08:00
{
2021-11-26 16:40:45 +08:00
Child = playlist = new TestPlaylist ( allowEdit , allowSelection , showItemOwner )
2020-02-20 07:37:23 +08:00
{
Anchor = Anchor . Centre ,
Origin = Anchor . Centre ,
Size = new Vector2 ( 500 , 300 )
} ;
2020-02-14 14:01:45 +08:00
2020-02-20 07:37:23 +08:00
for ( int i = 0 ; i < 20 ; i + + )
2020-02-14 14:01:45 +08:00
{
2020-02-20 07:37:23 +08:00
playlist . Items . Add ( new PlaylistItem
2020-02-14 14:01:45 +08:00
{
2020-02-20 07:37:23 +08:00
ID = i ,
2021-11-25 22:15:28 +08:00
OwnerID = 2 ,
2021-02-02 15:57:27 +08:00
Beatmap =
{
Value = i % 2 = = 1
? new TestBeatmap ( new OsuRuleset ( ) . RulesetInfo ) . BeatmapInfo
: new BeatmapInfo
{
Metadata = new BeatmapMetadata
{
Artist = "Artist" ,
2021-11-04 17:02:44 +08:00
Author = new APIUser { Username = "Creator name here" } ,
2021-02-02 15:57:27 +08:00
Title = "Long title used to check background colour" ,
} ,
BeatmapSet = new BeatmapSetInfo ( )
}
} ,
2020-02-20 07:37:23 +08:00
Ruleset = { Value = new OsuRuleset ( ) . RulesetInfo } ,
RequiredMods =
{
new OsuModHardRock ( ) ,
new OsuModDoubleTime ( ) ,
new OsuModAutoplay ( )
}
} ) ;
}
} ) ;
AddUntilStep ( "wait for items to load" , ( ) = > playlist . ItemMap . Values . All ( i = > i . IsLoaded ) ) ;
}
2021-11-01 14:42:12 +08:00
private void createPlaylist ( params IBeatmapInfo [ ] beatmaps )
2020-06-02 13:31:43 +08:00
{
AddStep ( "create playlist" , ( ) = >
{
Child = playlist = new TestPlaylist ( false , false )
{
Anchor = Anchor . Centre ,
Origin = Anchor . Centre ,
Size = new Vector2 ( 500 , 300 )
} ;
int index = 0 ;
foreach ( var b in beatmaps )
{
playlist . Items . Add ( new PlaylistItem
{
ID = index + + ,
2021-11-25 22:15:28 +08:00
OwnerID = 2 ,
2020-06-02 13:31:43 +08:00
Beatmap = { Value = b } ,
Ruleset = { Value = new OsuRuleset ( ) . RulesetInfo } ,
RequiredMods =
{
new OsuModHardRock ( ) ,
new OsuModDoubleTime ( ) ,
new OsuModAutoplay ( )
}
} ) ;
}
} ) ;
AddUntilStep ( "wait for items to load" , ( ) = > playlist . ItemMap . Values . All ( i = > i . IsLoaded ) ) ;
}
2020-02-20 07:37:23 +08:00
private class TestPlaylist : DrawableRoomPlaylist
{
public new IReadOnlyDictionary < PlaylistItem , RearrangeableListItem < PlaylistItem > > ItemMap = > base . ItemMap ;
2021-11-26 16:40:45 +08:00
public TestPlaylist ( bool allowEdit , bool allowSelection , bool showItemOwner = false )
: base ( allowEdit , allowSelection , showItemOwner : showItemOwner )
2020-02-20 07:37:23 +08:00
{
2020-02-14 14:01:45 +08:00
}
2020-02-20 07:37:23 +08:00
}
2020-02-14 14:01:45 +08:00
}
}