2019-01-24 16:43:03 +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.
2018-04-13 17:19:50 +08:00
using System ;
using System.Collections.Generic ;
using System.IO ;
using System.Linq ;
using System.Text ;
using NUnit.Framework ;
using osu.Framework.Allocation ;
2019-05-31 13:40:53 +08:00
using osu.Framework.Audio ;
2019-02-21 18:04:31 +08:00
using osu.Framework.Bindables ;
2018-04-13 17:19:50 +08:00
using osu.Framework.Extensions ;
using osu.Framework.MathUtils ;
2019-01-22 19:37:41 +08:00
using osu.Framework.Platform ;
2019-02-15 16:01:06 +08:00
using osu.Framework.Screens ;
2018-04-13 17:19:50 +08:00
using osu.Game.Beatmaps ;
using osu.Game.Database ;
using osu.Game.Rulesets ;
2018-08-14 13:18:46 +08:00
using osu.Game.Rulesets.Mods ;
using osu.Game.Rulesets.Osu.Mods ;
using osu.Game.Rulesets.Taiko ;
2018-04-13 17:19:50 +08:00
using osu.Game.Screens.Select ;
using osu.Game.Screens.Select.Carousel ;
using osu.Game.Screens.Select.Filter ;
2019-03-25 00:02:36 +08:00
namespace osu.Game.Tests.Visual.SongSelect
2018-04-13 17:19:50 +08:00
{
[TestFixture]
2019-05-15 03:37:25 +08:00
public class TestScenePlaySongSelect : ScreenTestScene
2018-04-13 17:19:50 +08:00
{
private BeatmapManager manager ;
private RulesetStore rulesets ;
private WorkingBeatmap defaultBeatmap ;
2018-07-19 13:07:55 +08:00
private DatabaseContextFactory factory ;
2018-04-13 17:19:50 +08:00
public override IReadOnlyList < Type > RequiredTypes = > new [ ]
{
2019-03-25 00:02:36 +08:00
typeof ( Screens . Select . SongSelect ) ,
2018-04-13 17:19:50 +08:00
typeof ( BeatmapCarousel ) ,
typeof ( CarouselItem ) ,
typeof ( CarouselGroup ) ,
typeof ( CarouselGroupEagerSelect ) ,
typeof ( CarouselBeatmap ) ,
typeof ( CarouselBeatmapSet ) ,
typeof ( DrawableCarouselItem ) ,
typeof ( CarouselItemState ) ,
typeof ( DrawableCarouselBeatmap ) ,
typeof ( DrawableCarouselBeatmapSet ) ,
} ;
private class TestSongSelect : PlaySongSelect
{
2019-01-10 14:25:07 +08:00
public Action StartRequested ;
2018-08-14 13:18:46 +08:00
public new Bindable < RulesetInfo > Ruleset = > base . Ruleset ;
2018-04-13 17:19:50 +08:00
public WorkingBeatmap CurrentBeatmap = > Beatmap . Value ;
public WorkingBeatmap CurrentBeatmapDetailsBeatmap = > BeatmapDetails . Beatmap ;
public new BeatmapCarousel Carousel = > base . Carousel ;
2019-01-10 14:25:07 +08:00
protected override bool OnStart ( )
{
StartRequested ? . Invoke ( ) ;
return base . OnStart ( ) ;
}
2018-04-13 17:19:50 +08:00
}
2018-07-18 11:58:45 +08:00
private TestSongSelect songSelect ;
2018-07-23 04:47:25 +08:00
protected override void Dispose ( bool isDisposing )
{
factory . ResetDatabase ( ) ;
base . Dispose ( isDisposing ) ;
}
2018-04-13 17:19:50 +08:00
[BackgroundDependencyLoader]
2019-05-31 13:40:53 +08:00
private void load ( GameHost host , AudioManager audio )
2018-04-13 17:19:50 +08:00
{
2018-07-19 13:07:55 +08:00
factory = new DatabaseContextFactory ( LocalStorage ) ;
2018-07-18 15:43:46 +08:00
factory . ResetDatabase ( ) ;
2018-04-13 17:19:50 +08:00
2018-07-20 23:02:55 +08:00
using ( var usage = factory . Get ( ) )
usage . Migrate ( ) ;
2018-07-18 15:43:46 +08:00
factory . ResetDatabase ( ) ;
using ( var usage = factory . Get ( ) )
usage . Migrate ( ) ;
2018-04-13 17:19:50 +08:00
2018-06-06 19:25:40 +08:00
Dependencies . Cache ( rulesets = new RulesetStore ( factory ) ) ;
2019-05-31 13:40:53 +08:00
Dependencies . Cache ( manager = new BeatmapManager ( LocalStorage , factory , rulesets , null , audio , host , defaultBeatmap = Beatmap . Default ) ) ;
2018-04-13 17:19:50 +08:00
2018-07-18 11:58:45 +08:00
Beatmap . SetDefault ( ) ;
}
2018-04-13 17:19:50 +08:00
2018-07-18 11:58:45 +08:00
[SetUp]
2019-02-15 20:50:40 +08:00
public virtual void SetUp ( ) = >
Schedule ( ( ) = > { manager ? . Delete ( manager . GetAllUsableBeatmapSets ( ) ) ; } ) ;
2018-04-13 17:19:50 +08:00
2018-07-20 10:32:00 +08:00
[Test]
2018-07-18 11:58:45 +08:00
public void TestDummy ( )
{
2019-02-15 20:50:40 +08:00
createSongSelect ( ) ;
2018-04-13 17:19:50 +08:00
AddAssert ( "dummy selected" , ( ) = > songSelect . CurrentBeatmap = = defaultBeatmap ) ;
2019-03-19 16:24:26 +08:00
AddUntilStep ( "dummy shown on wedge" , ( ) = > songSelect . CurrentBeatmapDetailsBeatmap = = defaultBeatmap ) ;
2018-04-13 17:19:50 +08:00
2018-07-18 11:58:45 +08:00
addManyTestMaps ( ) ;
2019-03-19 16:24:26 +08:00
AddWaitStep ( "wait for select" , 3 ) ;
2018-07-18 11:58:45 +08:00
2018-04-13 17:19:50 +08:00
AddAssert ( "random map selected" , ( ) = > songSelect . CurrentBeatmap ! = defaultBeatmap ) ;
2018-07-18 11:58:45 +08:00
}
2018-04-13 17:19:50 +08:00
2018-07-20 10:32:00 +08:00
[Test]
2018-07-18 11:58:45 +08:00
public void TestSorting ( )
{
2019-02-15 20:50:40 +08:00
createSongSelect ( ) ;
2018-07-18 11:58:45 +08:00
addManyTestMaps ( ) ;
2019-03-19 16:24:26 +08:00
AddWaitStep ( "wait for add" , 3 ) ;
2018-07-18 11:58:45 +08:00
2018-04-13 17:19:50 +08:00
AddAssert ( "random map selected" , ( ) = > songSelect . CurrentBeatmap ! = defaultBeatmap ) ;
AddStep ( @"Sort by Artist" , delegate { songSelect . FilterControl . Sort = SortMode . Artist ; } ) ;
AddStep ( @"Sort by Title" , delegate { songSelect . FilterControl . Sort = SortMode . Title ; } ) ;
AddStep ( @"Sort by Author" , delegate { songSelect . FilterControl . Sort = SortMode . Author ; } ) ;
AddStep ( @"Sort by Difficulty" , delegate { songSelect . FilterControl . Sort = SortMode . Difficulty ; } ) ;
}
2018-07-18 11:58:45 +08:00
[Test]
2018-07-25 22:45:07 +08:00
[Ignore("needs fixing")]
2018-08-14 13:19:26 +08:00
public void TestImportUnderDifferentRuleset ( )
2018-04-13 17:19:50 +08:00
{
2019-02-15 20:50:40 +08:00
createSongSelect ( ) ;
2018-07-20 10:32:00 +08:00
changeRuleset ( 2 ) ;
2019-06-10 17:34:24 +08:00
addRulesetImportStep ( 0 ) ;
2019-03-19 16:24:26 +08:00
AddUntilStep ( "no selection" , ( ) = > songSelect . Carousel . SelectedBeatmap = = null ) ;
2018-07-20 10:32:00 +08:00
}
2018-07-19 17:51:08 +08:00
2018-07-20 10:32:00 +08:00
[Test]
2018-08-14 13:19:26 +08:00
public void TestImportUnderCurrentRuleset ( )
2018-07-20 10:32:00 +08:00
{
2019-02-15 20:50:40 +08:00
createSongSelect ( ) ;
2018-07-20 10:32:00 +08:00
changeRuleset ( 2 ) ;
2019-06-10 17:34:24 +08:00
addRulesetImportStep ( 2 ) ;
addRulesetImportStep ( 1 ) ;
2019-03-19 16:24:26 +08:00
AddUntilStep ( "has selection" , ( ) = > songSelect . Carousel . SelectedBeatmap . RulesetID = = 2 ) ;
2018-07-19 17:51:08 +08:00
2018-07-20 10:32:00 +08:00
changeRuleset ( 1 ) ;
2019-03-19 16:24:26 +08:00
AddUntilStep ( "has selection" , ( ) = > songSelect . Carousel . SelectedBeatmap . RulesetID = = 1 ) ;
2018-07-19 17:51:08 +08:00
2018-07-20 10:32:00 +08:00
changeRuleset ( 0 ) ;
2019-03-19 16:24:26 +08:00
AddUntilStep ( "no selection" , ( ) = > songSelect . Carousel . SelectedBeatmap = = null ) ;
2018-07-18 11:58:45 +08:00
}
2018-08-14 13:18:46 +08:00
[Test]
public void TestRulesetChangeResetsMods ( )
{
2019-02-15 20:50:40 +08:00
createSongSelect ( ) ;
2018-08-14 13:18:46 +08:00
changeRuleset ( 0 ) ;
changeMods ( new OsuModHardRock ( ) ) ;
int actionIndex = 0 ;
int modChangeIndex = 0 ;
int rulesetChangeIndex = 0 ;
AddStep ( "change ruleset" , ( ) = >
{
2019-04-10 11:03:57 +08:00
Mods . ValueChanged + = onModChange ;
2018-08-14 13:18:46 +08:00
songSelect . Ruleset . ValueChanged + = onRulesetChange ;
Ruleset . Value = new TaikoRuleset ( ) . RulesetInfo ;
2019-04-10 11:03:57 +08:00
Mods . ValueChanged - = onModChange ;
2018-08-14 13:18:46 +08:00
songSelect . Ruleset . ValueChanged - = onRulesetChange ;
} ) ;
AddAssert ( "mods changed before ruleset" , ( ) = > modChangeIndex < rulesetChangeIndex ) ;
2019-04-10 11:03:57 +08:00
AddAssert ( "empty mods" , ( ) = > ! Mods . Value . Any ( ) ) ;
2018-08-14 13:18:46 +08:00
2019-04-10 16:13:12 +08:00
void onModChange ( ValueChangedEvent < IReadOnlyList < Mod > > e ) = > modChangeIndex = actionIndex + + ;
2019-02-21 17:56:34 +08:00
void onRulesetChange ( ValueChangedEvent < RulesetInfo > e ) = > rulesetChangeIndex = actionIndex - - ;
2018-08-14 13:18:46 +08:00
}
2019-01-10 14:25:07 +08:00
[Test]
public void TestStartAfterUnMatchingFilterDoesNotStart ( )
{
2019-02-15 20:50:40 +08:00
createSongSelect ( ) ;
2019-01-10 14:25:07 +08:00
addManyTestMaps ( ) ;
2019-03-19 16:24:26 +08:00
AddUntilStep ( "has selection" , ( ) = > songSelect . Carousel . SelectedBeatmap ! = null ) ;
2019-01-10 14:25:07 +08:00
bool startRequested = false ;
AddStep ( "set filter and finalize" , ( ) = >
{
songSelect . StartRequested = ( ) = > startRequested = true ;
songSelect . Carousel . Filter ( new FilterCriteria { SearchText = "somestringthatshouldn'tbematchable" } ) ;
songSelect . FinaliseSelection ( ) ;
songSelect . StartRequested = null ;
} ) ;
AddAssert ( "start not requested" , ( ) = > ! startRequested ) ;
}
2019-06-12 15:45:29 +08:00
[Test]
public void TestAddNewBeatmapWhileSelectingRandom ( )
{
const int test_count = 10 ;
int beatmapChangedCount = 0 ;
int debounceCount = 0 ;
createSongSelect ( ) ;
AddStep ( "Setup counters" , ( ) = >
{
beatmapChangedCount = 0 ;
debounceCount = 0 ;
songSelect . Carousel . SelectionChanged + = _ = > beatmapChangedCount + + ;
} ) ;
AddRepeatStep ( $"Create beatmaps {test_count} times" , ( ) = >
{
importForRuleset ( 0 ) ;
Scheduler . AddDelayed ( ( ) = >
{
// Wait for debounce
songSelect . Carousel . SelectNextRandom ( ) ;
+ + debounceCount ;
} , 400 ) ;
} , test_count ) ;
AddUntilStep ( "Debounce limit reached" , ( ) = > debounceCount = = test_count ) ;
// The selected beatmap should have changed an additional 2 times since both initially loading songselect and the first import also triggers selectionChanged
AddAssert ( $"Beatmap changed {test_count + 2} times" , ( ) = > beatmapChangedCount = = test_count + 2 ) ;
}
[Test]
public void TestHideSetSelectsCorrectBeatmap ( )
{
int? previousID = null ;
createSongSelect ( ) ;
addRulesetImportStep ( 0 ) ;
AddStep ( "Move to last difficulty" , ( ) = > songSelect . Carousel . SelectBeatmap ( songSelect . Carousel . BeatmapSets . First ( ) . Beatmaps . Last ( ) ) ) ;
AddStep ( "Store current ID" , ( ) = > previousID = songSelect . Carousel . SelectedBeatmap . ID ) ;
AddStep ( "Hide first beatmap" , ( ) = > manager . Hide ( songSelect . Carousel . SelectedBeatmapSet . Beatmaps . First ( ) ) ) ;
AddAssert ( "Selected beatmap has not changed" , ( ) = > songSelect . Carousel . SelectedBeatmap . ID = = previousID ) ;
}
private void addRulesetImportStep ( int id ) = > AddStep ( $"import test map for ruleset {id}" , ( ) = > importForRuleset ( id ) ) ;
private void importForRuleset ( int id ) = > manager . Import ( createTestBeatmapSet ( getImportId ( ) , rulesets . AvailableRulesets . Where ( r = > r . ID = = id ) . ToArray ( ) ) ) . Wait ( ) ;
2018-07-20 10:32:00 +08:00
private static int importId ;
private int getImportId ( ) = > + + importId ;
2019-04-10 11:03:57 +08:00
private void changeMods ( params Mod [ ] mods ) = > AddStep ( $"change mods to {string.Join(" , ", mods.Select(m => m.Acronym))}" , ( ) = > Mods . Value = mods ) ;
2018-08-14 13:18:46 +08:00
2018-07-20 10:32:00 +08:00
private void changeRuleset ( int id ) = > AddStep ( $"change ruleset to {id}" , ( ) = > Ruleset . Value = rulesets . AvailableRulesets . First ( r = > r . ID = = id ) ) ;
2019-02-15 20:50:40 +08:00
private void createSongSelect ( )
{
AddStep ( "create song select" , ( ) = > LoadScreen ( songSelect = new TestSongSelect ( ) ) ) ;
2019-03-19 16:24:26 +08:00
AddUntilStep ( "wait for present" , ( ) = > songSelect . IsCurrentScreen ( ) ) ;
2019-02-15 20:50:40 +08:00
}
2018-07-18 11:58:45 +08:00
private void addManyTestMaps ( )
{
AddStep ( "import test maps" , ( ) = >
{
var usableRulesets = rulesets . AvailableRulesets . Where ( r = > r . ID ! = 2 ) . ToArray ( ) ;
for ( int i = 0 ; i < 100 ; i + = 10 )
2019-06-10 11:46:21 +08:00
manager . Import ( createTestBeatmapSet ( i , usableRulesets ) ) . Wait ( ) ;
2018-07-18 11:58:45 +08:00
} ) ;
}
2018-07-20 10:32:00 +08:00
private BeatmapSetInfo createTestBeatmapSet ( int setId , RulesetInfo [ ] rulesets )
2018-07-18 11:58:45 +08:00
{
int j = 0 ;
RulesetInfo getRuleset ( ) = > rulesets [ j + + % rulesets . Length ] ;
var beatmaps = new List < BeatmapInfo > ( ) ;
for ( int i = 0 ; i < 6 ; i + + )
{
2018-07-20 10:32:00 +08:00
int beatmapId = setId * 10 + i ;
2018-07-18 11:58:45 +08:00
beatmaps . Add ( new BeatmapInfo
{
Ruleset = getRuleset ( ) ,
OnlineBeatmapID = beatmapId ,
Path = "normal.osu" ,
Version = $"{beatmapId}" ,
BaseDifficulty = new BeatmapDifficulty
{
OverallDifficulty = 3.5f ,
}
} ) ;
}
2018-04-13 17:19:50 +08:00
return new BeatmapSetInfo
{
2018-07-18 11:58:45 +08:00
OnlineBeatmapSetID = setId ,
2018-04-13 17:19:50 +08:00
Hash = new MemoryStream ( Encoding . UTF8 . GetBytes ( Guid . NewGuid ( ) . ToString ( ) ) ) . ComputeMD5Hash ( ) ,
Metadata = new BeatmapMetadata
{
// Create random metadata, then we can check if sorting works based on these
2018-07-18 11:58:45 +08:00
Artist = "Some Artist " + RNG . Next ( 0 , 9 ) ,
Title = $"Some Song (set id {setId})" ,
2018-04-13 17:19:50 +08:00
AuthorString = "Some Guy " + RNG . Next ( 0 , 9 ) ,
} ,
2018-07-18 11:58:45 +08:00
Beatmaps = beatmaps
2018-04-13 17:19:50 +08:00
} ;
}
}
}