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
2022-06-17 15:37:17 +08:00
#nullable disable
2017-12-13 18:56:16 +08:00
using System ;
using System.Collections.Generic ;
using System.Linq ;
2018-03-02 14:34:31 +08:00
using NUnit.Framework ;
2017-12-13 18:56:16 +08:00
using osu.Framework.Allocation ;
2021-11-22 13:29:46 +08:00
using osu.Framework.Extensions.IEnumerableExtensions ;
2017-12-13 18:56:16 +08:00
using osu.Framework.Graphics ;
2019-11-13 18:09:03 +08:00
using osu.Framework.Graphics.Containers ;
2022-11-20 17:07:32 +08:00
using osu.Framework.Testing ;
2022-01-27 15:38:02 +08:00
using osu.Framework.Utils ;
2017-12-13 18:56:16 +08:00
using osu.Game.Beatmaps ;
2017-12-14 11:59:35 +08:00
using osu.Game.Configuration ;
2018-03-09 22:09:28 +08:00
using osu.Game.Rulesets ;
2021-10-29 17:22:23 +08:00
using osu.Game.Rulesets.Osu ;
2017-12-13 18:56:16 +08:00
using osu.Game.Screens.Select ;
using osu.Game.Screens.Select.Carousel ;
2017-12-14 19:40:58 +08:00
using osu.Game.Screens.Select.Filter ;
2021-11-24 16:59:23 +08:00
using osu.Game.Tests.Resources ;
2020-06-25 19:01:29 +08:00
using osuTK.Input ;
2018-04-13 17:19:50 +08:00
2019-03-25 00:02:36 +08:00
namespace osu.Game.Tests.Visual.SongSelect
2017-12-13 18:56:16 +08:00
{
2018-03-02 14:34:31 +08:00
[TestFixture]
2020-06-25 19:01:29 +08:00
public partial class TestSceneBeatmapCarousel : OsuManualInputManagerTestScene
2017-12-13 18:56:16 +08:00
{
2017-12-13 20:08:12 +08:00
private TestBeatmapCarousel carousel ;
2018-03-09 22:09:28 +08:00
private RulesetStore rulesets ;
2018-04-13 17:19:50 +08:00
2017-12-14 19:40:58 +08:00
private readonly Stack < BeatmapSetInfo > selectedSets = new Stack < BeatmapSetInfo > ( ) ;
2021-11-22 13:26:51 +08:00
private readonly HashSet < Guid > eagerSelectedIDs = new HashSet < Guid > ( ) ;
2018-04-13 17:19:50 +08:00
2021-10-02 11:44:22 +08:00
private BeatmapInfo currentSelection = > carousel . SelectedBeatmapInfo ;
2018-04-13 17:19:50 +08:00
2017-12-15 23:33:09 +08:00
private const int set_count = 5 ;
2018-04-13 17:19:50 +08:00
2017-12-13 18:56:16 +08:00
[BackgroundDependencyLoader]
2018-03-09 22:09:28 +08:00
private void load ( RulesetStore rulesets )
2017-12-13 18:56:16 +08:00
{
2018-03-09 22:09:28 +08:00
this . rulesets = rulesets ;
2017-12-14 19:40:58 +08:00
}
2018-04-13 17:19:50 +08:00
2022-02-03 15:45:57 +08:00
[Test]
public void TestExternalRulesetChange ( )
{
createCarousel ( new List < BeatmapSetInfo > ( ) ) ;
AddStep ( "filter to ruleset 0" , ( ) = > carousel . Filter ( new FilterCriteria
{
Ruleset = rulesets . AvailableRulesets . ElementAt ( 0 ) ,
AllowConvertedBeatmaps = true ,
} , false ) ) ;
AddStep ( "add mixed ruleset beatmapset" , ( ) = >
{
var testMixed = TestResources . CreateTestBeatmapSetInfo ( 3 ) ;
for ( int i = 0 ; i < = 2 ; i + + )
{
testMixed . Beatmaps [ i ] . Ruleset = rulesets . AvailableRulesets . ElementAt ( i ) ;
}
carousel . UpdateBeatmapSet ( testMixed ) ;
} ) ;
AddUntilStep ( "wait for filtered difficulties" , ( ) = >
{
var visibleBeatmapPanels = carousel . Items . OfType < DrawableCarouselBeatmap > ( ) . Where ( p = > p . IsPresent ) . ToArray ( ) ;
return visibleBeatmapPanels . Length = = 1
& & visibleBeatmapPanels . Count ( p = > ( ( CarouselBeatmap ) p . Item ) . BeatmapInfo . Ruleset . OnlineID = = 0 ) = = 1 ;
} ) ;
AddStep ( "filter to ruleset 1" , ( ) = > carousel . Filter ( new FilterCriteria
{
Ruleset = rulesets . AvailableRulesets . ElementAt ( 1 ) ,
AllowConvertedBeatmaps = true ,
} , false ) ) ;
AddUntilStep ( "wait for filtered difficulties" , ( ) = >
{
var visibleBeatmapPanels = carousel . Items . OfType < DrawableCarouselBeatmap > ( ) . Where ( p = > p . IsPresent ) . ToArray ( ) ;
return visibleBeatmapPanels . Length = = 2
& & visibleBeatmapPanels . Count ( p = > ( ( CarouselBeatmap ) p . Item ) . BeatmapInfo . Ruleset . OnlineID = = 0 ) = = 1
& & visibleBeatmapPanels . Count ( p = > ( ( CarouselBeatmap ) p . Item ) . BeatmapInfo . Ruleset . OnlineID = = 1 ) = = 1 ;
} ) ;
AddStep ( "filter to ruleset 2" , ( ) = > carousel . Filter ( new FilterCriteria
{
Ruleset = rulesets . AvailableRulesets . ElementAt ( 2 ) ,
AllowConvertedBeatmaps = true ,
} , false ) ) ;
AddUntilStep ( "wait for filtered difficulties" , ( ) = >
{
var visibleBeatmapPanels = carousel . Items . OfType < DrawableCarouselBeatmap > ( ) . Where ( p = > p . IsPresent ) . ToArray ( ) ;
return visibleBeatmapPanels . Length = = 2
& & visibleBeatmapPanels . Count ( p = > ( ( CarouselBeatmap ) p . Item ) . BeatmapInfo . Ruleset . OnlineID = = 0 ) = = 1
& & visibleBeatmapPanels . Count ( p = > ( ( CarouselBeatmap ) p . Item ) . BeatmapInfo . Ruleset . OnlineID = = 2 ) = = 1 ;
} ) ;
}
2022-01-27 15:38:02 +08:00
[Test]
public void TestScrollPositionMaintainedOnAdd ( )
{
loadBeatmaps ( count : 1 , randomDifficulties : false ) ;
for ( int i = 0 ; i < 10 ; i + + )
{
AddRepeatStep ( "Add some sets" , ( ) = > carousel . UpdateBeatmapSet ( TestResources . CreateTestBeatmapSetInfo ( ) ) , 4 ) ;
checkSelectionIsCentered ( ) ;
}
}
2022-11-20 17:07:32 +08:00
[Test]
public void TestDeletion ( )
{
loadBeatmaps ( count : 5 , randomDifficulties : true ) ;
AddStep ( "remove first set" , ( ) = > carousel . RemoveBeatmapSet ( carousel . Items . Select ( item = > item . Item ) . OfType < CarouselBeatmapSet > ( ) . First ( ) . BeatmapSet ) ) ;
AddUntilStep ( "4 beatmap sets visible" , ( ) = > this . ChildrenOfType < DrawableCarouselBeatmapSet > ( ) . Count ( set = > set . Alpha > 0 ) = = 4 ) ;
}
2022-01-27 15:38:02 +08:00
[Test]
public void TestScrollPositionMaintainedOnDelete ( )
{
loadBeatmaps ( count : 50 , randomDifficulties : false ) ;
for ( int i = 0 ; i < 10 ; i + + )
{
AddRepeatStep ( "Remove some sets" , ( ) = >
carousel . RemoveBeatmapSet ( carousel . Items . Select ( item = > item . Item )
. OfType < CarouselBeatmapSet > ( )
. OrderBy ( item = > item . GetHashCode ( ) )
. First ( item = > item . State . Value ! = CarouselItemState . Selected & & item . Visible ) . BeatmapSet ) , 4 ) ;
checkSelectionIsCentered ( ) ;
}
}
2020-10-13 16:26:17 +08:00
[Test]
public void TestManyPanels ( )
{
loadBeatmaps ( count : 5000 , randomDifficulties : true ) ;
}
2020-06-25 19:01:29 +08:00
[Test]
public void TestKeyRepeat ( )
{
loadBeatmaps ( ) ;
advanceSelection ( false ) ;
AddStep ( "press down arrow" , ( ) = > InputManager . PressKey ( Key . Down ) ) ;
BeatmapInfo selection = null ;
checkSelectionIterating ( true ) ;
AddStep ( "press up arrow" , ( ) = > InputManager . PressKey ( Key . Up ) ) ;
checkSelectionIterating ( true ) ;
AddStep ( "release down arrow" , ( ) = > InputManager . ReleaseKey ( Key . Down ) ) ;
checkSelectionIterating ( true ) ;
AddStep ( "release up arrow" , ( ) = > InputManager . ReleaseKey ( Key . Up ) ) ;
checkSelectionIterating ( false ) ;
void checkSelectionIterating ( bool isIterating )
{
for ( int i = 0 ; i < 3 ; i + + )
{
2021-10-02 11:44:22 +08:00
AddStep ( "store selection" , ( ) = > selection = carousel . SelectedBeatmapInfo ) ;
2020-06-25 19:01:29 +08:00
if ( isIterating )
2022-01-07 23:40:14 +08:00
AddUntilStep ( "selection changed" , ( ) = > ! carousel . SelectedBeatmapInfo ? . Equals ( selection ) = = true ) ;
2020-06-25 19:01:29 +08:00
else
2022-09-07 13:40:51 +08:00
AddUntilStep ( "selection not changed" , ( ) = > carousel . SelectedBeatmapInfo ? . Equals ( selection ) = = true ) ;
2020-06-25 19:01:29 +08:00
}
}
}
2020-04-11 16:17:18 +08:00
[Test]
public void TestRecommendedSelection ( )
{
2020-07-13 16:05:29 +08:00
loadBeatmaps ( carouselAdjust : carousel = > carousel . GetRecommendedBeatmap = beatmaps = > beatmaps . LastOrDefault ( ) ) ;
2020-04-11 16:17:18 +08:00
2020-07-13 16:05:29 +08:00
AddStep ( "select last" , ( ) = > carousel . SelectBeatmap ( carousel . BeatmapSets . Last ( ) . Beatmaps . Last ( ) ) ) ;
2020-04-11 16:17:18 +08:00
// check recommended was selected
advanceSelection ( direction : 1 , diff : false ) ;
waitForSelection ( 1 , 3 ) ;
// change away from recommended
advanceSelection ( direction : - 1 , diff : true ) ;
waitForSelection ( 1 , 2 ) ;
// next set, check recommended
advanceSelection ( direction : 1 , diff : false ) ;
waitForSelection ( 2 , 3 ) ;
// next set, check recommended
advanceSelection ( direction : 1 , diff : false ) ;
waitForSelection ( 3 , 3 ) ;
// go back to first set and ensure user selection was retained
advanceSelection ( direction : - 1 , diff : false ) ;
advanceSelection ( direction : - 1 , diff : false ) ;
waitForSelection ( 1 , 2 ) ;
}
2017-12-14 19:40:58 +08:00
/// <summary>
/// Test keyboard traversal
/// </summary>
2019-09-25 01:42:12 +08:00
[Test]
public void TestTraversal ( )
2017-12-14 19:40:58 +08:00
{
2019-09-25 01:42:12 +08:00
loadBeatmaps ( ) ;
2020-07-13 19:03:07 +08:00
AddStep ( "select first" , ( ) = > carousel . SelectBeatmap ( carousel . BeatmapSets . First ( ) . Beatmaps . First ( ) ) ) ;
2019-09-29 12:23:18 +08:00
waitForSelection ( 1 , 1 ) ;
2018-04-13 17:19:50 +08:00
2017-12-13 20:08:12 +08:00
advanceSelection ( direction : 1 , diff : true ) ;
2019-09-29 12:23:18 +08:00
waitForSelection ( 1 , 2 ) ;
2018-04-13 17:19:50 +08:00
2017-12-13 20:08:12 +08:00
advanceSelection ( direction : - 1 , diff : false ) ;
2019-09-29 12:23:18 +08:00
waitForSelection ( set_count , 1 ) ;
2018-04-13 17:19:50 +08:00
2017-12-13 20:08:12 +08:00
advanceSelection ( direction : - 1 , diff : true ) ;
2019-09-29 12:23:18 +08:00
waitForSelection ( set_count - 1 , 3 ) ;
2018-04-13 17:19:50 +08:00
2017-12-13 20:08:12 +08:00
advanceSelection ( diff : false ) ;
advanceSelection ( diff : false ) ;
2019-09-29 12:23:18 +08:00
waitForSelection ( 1 , 2 ) ;
2018-04-13 17:19:50 +08:00
2017-12-16 15:14:37 +08:00
advanceSelection ( direction : - 1 , diff : true ) ;
2017-12-13 20:08:12 +08:00
advanceSelection ( direction : - 1 , diff : true ) ;
2019-09-29 12:23:18 +08:00
waitForSelection ( set_count , 3 ) ;
2017-12-14 19:40:58 +08:00
}
2018-04-13 17:19:50 +08:00
2020-03-28 19:10:20 +08:00
[TestCase(true)]
[TestCase(false)]
2020-03-29 23:05:07 +08:00
public void TestTraversalBeyondVisible ( bool forwards )
2020-03-27 02:32:43 +08:00
{
var sets = new List < BeatmapSetInfo > ( ) ;
2020-03-29 23:05:07 +08:00
const int total_set_count = 200 ;
2022-08-25 13:03:25 +08:00
AddStep ( "Populuate beatmap sets" , ( ) = >
{
sets . Clear ( ) ;
for ( int i = 0 ; i < total_set_count ; i + + )
sets . Add ( TestResources . CreateTestBeatmapSetInfo ( ) ) ;
} ) ;
2020-03-27 02:32:43 +08:00
loadBeatmaps ( sets ) ;
2020-03-29 23:05:07 +08:00
for ( int i = 1 ; i < total_set_count ; i + = i )
selectNextAndAssert ( i ) ;
2020-03-27 02:32:43 +08:00
void selectNextAndAssert ( int amount )
{
2020-03-29 23:05:07 +08:00
setSelected ( forwards ? 1 : total_set_count , 1 ) ;
AddStep ( $"{(forwards ? " Next " : " Previous ")} beatmap {amount} times" , ( ) = >
2020-03-27 02:32:43 +08:00
{
for ( int i = 0 ; i < amount ; i + + )
{
2020-03-28 19:10:20 +08:00
carousel . SelectNext ( forwards ? 1 : - 1 ) ;
2020-03-27 02:32:43 +08:00
}
} ) ;
2020-03-29 23:05:07 +08:00
waitForSelection ( forwards ? amount + 1 : total_set_count - amount ) ;
2020-03-27 02:32:43 +08:00
}
}
2020-03-29 03:02:55 +08:00
[Test]
2020-03-29 23:05:07 +08:00
public void TestTraversalBeyondVisibleDifficulties ( )
2020-03-29 03:02:55 +08:00
{
var sets = new List < BeatmapSetInfo > ( ) ;
2020-03-29 23:55:47 +08:00
const int total_set_count = 20 ;
2020-03-29 03:02:55 +08:00
2022-08-25 13:03:25 +08:00
AddStep ( "Populuate beatmap sets" , ( ) = >
{
sets . Clear ( ) ;
for ( int i = 0 ; i < total_set_count ; i + + )
sets . Add ( TestResources . CreateTestBeatmapSetInfo ( 3 ) ) ;
} ) ;
2020-03-29 03:02:55 +08:00
2020-03-29 23:05:07 +08:00
loadBeatmaps ( sets ) ;
2020-03-29 03:02:55 +08:00
// Selects next set once, difficulty index doesn't change
selectNextAndAssert ( 3 , true , 2 , 1 ) ;
2020-03-29 22:46:28 +08:00
// Selects next set 16 times (50 \ 3 == 16), difficulty index changes twice (50 % 3 == 2)
2020-03-29 03:02:55 +08:00
selectNextAndAssert ( 50 , true , 17 , 3 ) ;
2020-03-29 22:46:28 +08:00
// Travels around the carousel thrice (200 \ 60 == 3)
// continues to select 20 times (200 \ 60 == 20)
// selects next set 6 times (20 \ 3 == 6)
2020-03-29 03:02:55 +08:00
// difficulty index changes twice (20 % 3 == 2)
selectNextAndAssert ( 200 , true , 7 , 3 ) ;
// All same but in reverse
selectNextAndAssert ( 3 , false , 19 , 3 ) ;
selectNextAndAssert ( 50 , false , 4 , 1 ) ;
selectNextAndAssert ( 200 , false , 14 , 1 ) ;
2020-03-29 23:05:07 +08:00
void selectNextAndAssert ( int amount , bool forwards , int expectedSet , int expectedDiff )
{
// Select very first or very last difficulty
setSelected ( forwards ? 1 : 20 , forwards ? 1 : 3 ) ;
AddStep ( $"{(forwards ? " Next " : " Previous ")} difficulty {amount} times" , ( ) = >
{
for ( int i = 0 ; i < amount ; i + + )
carousel . SelectNext ( forwards ? 1 : - 1 , false ) ;
} ) ;
waitForSelection ( expectedSet , expectedDiff ) ;
}
2020-03-29 03:02:55 +08:00
}
2017-12-14 19:40:58 +08:00
/// <summary>
/// Test filtering
/// </summary>
2019-09-25 01:42:12 +08:00
[Test]
public void TestFiltering ( )
2017-12-14 19:40:58 +08:00
{
2019-09-25 01:42:12 +08:00
loadBeatmaps ( ) ;
2017-12-14 19:40:58 +08:00
// basic filtering
2017-12-15 23:33:09 +08:00
setSelected ( 1 , 1 ) ;
2018-04-13 17:19:50 +08:00
2021-11-24 16:59:23 +08:00
AddStep ( "Filter" , ( ) = > carousel . Filter ( new FilterCriteria { SearchText = carousel . BeatmapSets . ElementAt ( 2 ) . Metadata . Title } , false ) ) ;
2017-12-13 20:08:12 +08:00
checkVisibleItemCount ( diff : false , count : 1 ) ;
checkVisibleItemCount ( diff : true , count : 3 ) ;
2019-09-29 12:23:18 +08:00
waitForSelection ( 3 , 1 ) ;
2018-04-13 17:19:50 +08:00
2017-12-13 20:08:12 +08:00
advanceSelection ( diff : true , count : 4 ) ;
2019-09-29 12:23:18 +08:00
waitForSelection ( 3 , 2 ) ;
2018-04-13 17:19:50 +08:00
2017-12-13 20:08:12 +08:00
AddStep ( "Un-filter (debounce)" , ( ) = > carousel . Filter ( new FilterCriteria ( ) ) ) ;
2019-03-19 16:24:26 +08:00
AddUntilStep ( "Wait for debounce" , ( ) = > ! carousel . PendingFilterTask ) ;
2017-12-15 13:36:11 +08:00
checkVisibleItemCount ( diff : false , count : set_count ) ;
2017-12-13 20:08:12 +08:00
checkVisibleItemCount ( diff : true , count : 3 ) ;
2018-04-13 17:19:50 +08:00
2017-12-13 20:47:42 +08:00
// test filtering some difficulties (and keeping current beatmap set selected).
2018-04-13 17:19:50 +08:00
2017-12-13 20:47:42 +08:00
setSelected ( 1 , 2 ) ;
AddStep ( "Filter some difficulties" , ( ) = > carousel . Filter ( new FilterCriteria { SearchText = "Normal" } , false ) ) ;
2019-09-29 12:23:18 +08:00
waitForSelection ( 1 , 1 ) ;
2018-04-13 17:19:50 +08:00
2017-12-13 20:47:42 +08:00
AddStep ( "Un-filter" , ( ) = > carousel . Filter ( new FilterCriteria ( ) , false ) ) ;
2019-09-29 12:23:18 +08:00
waitForSelection ( 1 , 1 ) ;
2018-04-13 17:19:50 +08:00
2017-12-15 23:33:09 +08:00
AddStep ( "Filter all" , ( ) = > carousel . Filter ( new FilterCriteria { SearchText = "Dingo" } , false ) ) ;
2018-04-13 17:19:50 +08:00
2017-12-15 23:33:09 +08:00
checkVisibleItemCount ( false , 0 ) ;
checkVisibleItemCount ( true , 0 ) ;
AddAssert ( "Selection is null" , ( ) = > currentSelection = = null ) ;
2018-04-13 17:19:50 +08:00
2018-02-27 16:50:26 +08:00
advanceSelection ( true ) ;
AddAssert ( "Selection is null" , ( ) = > currentSelection = = null ) ;
2018-04-13 17:19:50 +08:00
2018-02-27 16:50:26 +08:00
advanceSelection ( false ) ;
AddAssert ( "Selection is null" , ( ) = > currentSelection = = null ) ;
2018-04-13 17:19:50 +08:00
2017-12-15 23:33:09 +08:00
AddStep ( "Un-filter" , ( ) = > carousel . Filter ( new FilterCriteria ( ) , false ) ) ;
2018-04-13 17:19:50 +08:00
2017-12-15 23:33:09 +08:00
AddAssert ( "Selection is non-null" , ( ) = > currentSelection ! = null ) ;
2019-09-21 05:06:20 +08:00
setSelected ( 1 , 3 ) ;
2019-10-03 16:21:14 +08:00
}
[Test]
public void TestFilterRange ( )
{
2021-11-24 16:59:23 +08:00
string searchText = null ;
2019-10-03 16:21:14 +08:00
loadBeatmaps ( ) ;
// buffer the selection
setSelected ( 3 , 2 ) ;
2022-09-07 13:40:51 +08:00
AddStep ( "get search text" , ( ) = > searchText = carousel . SelectedBeatmapSet ! . Metadata . Title ) ;
2021-11-24 16:59:23 +08:00
2019-10-03 16:21:14 +08:00
setSelected ( 1 , 3 ) ;
2019-09-21 05:06:20 +08:00
AddStep ( "Apply a range filter" , ( ) = > carousel . Filter ( new FilterCriteria
{
2021-11-24 16:59:23 +08:00
SearchText = searchText ,
2019-09-21 05:06:20 +08:00
StarDifficulty = new FilterCriteria . OptionalRange < double >
{
Min = 2 ,
Max = 5.5 ,
IsLowerInclusive = true
}
} , false ) ) ;
2019-10-03 16:21:14 +08:00
// should reselect the buffered selection.
waitForSelection ( 3 , 2 ) ;
2017-12-14 19:40:58 +08:00
}
2018-04-13 17:19:50 +08:00
2017-12-14 19:40:58 +08:00
/// <summary>
/// Test random non-repeating algorithm
/// </summary>
2019-09-25 01:42:12 +08:00
[Test]
public void TestRandom ( )
2017-12-14 19:40:58 +08:00
{
2019-09-25 01:42:12 +08:00
loadBeatmaps ( ) ;
2017-12-14 11:59:35 +08:00
setSelected ( 1 , 1 ) ;
2018-04-13 17:19:50 +08:00
2017-12-14 11:59:35 +08:00
nextRandom ( ) ;
ensureRandomDidntRepeat ( ) ;
nextRandom ( ) ;
ensureRandomDidntRepeat ( ) ;
nextRandom ( ) ;
ensureRandomDidntRepeat ( ) ;
2018-04-13 17:19:50 +08:00
2017-12-14 11:59:35 +08:00
prevRandom ( ) ;
ensureRandomFetchSuccess ( ) ;
prevRandom ( ) ;
ensureRandomFetchSuccess ( ) ;
2018-04-13 17:19:50 +08:00
2017-12-14 11:59:35 +08:00
nextRandom ( ) ;
ensureRandomDidntRepeat ( ) ;
nextRandom ( ) ;
ensureRandomDidntRepeat ( ) ;
2018-04-13 17:19:50 +08:00
2017-12-14 11:59:35 +08:00
nextRandom ( ) ;
AddAssert ( "ensure repeat" , ( ) = > selectedSets . Contains ( carousel . SelectedBeatmapSet ) ) ;
2018-04-13 17:19:50 +08:00
2021-11-24 16:59:23 +08:00
AddStep ( "Add set with 100 difficulties" , ( ) = > carousel . UpdateBeatmapSet ( TestResources . CreateTestBeatmapSetInfo ( 100 , rulesets . AvailableRulesets . ToArray ( ) ) ) ) ;
2018-01-03 21:38:43 +08:00
AddStep ( "Filter Extra" , ( ) = > carousel . Filter ( new FilterCriteria { SearchText = "Extra 10" } , false ) ) ;
checkInvisibleDifficultiesUnselectable ( ) ;
checkInvisibleDifficultiesUnselectable ( ) ;
checkInvisibleDifficultiesUnselectable ( ) ;
checkInvisibleDifficultiesUnselectable ( ) ;
checkInvisibleDifficultiesUnselectable ( ) ;
AddStep ( "Un-filter" , ( ) = > carousel . Filter ( new FilterCriteria ( ) , false ) ) ;
2017-12-14 19:40:58 +08:00
}
2018-04-13 17:19:50 +08:00
2017-12-14 19:40:58 +08:00
/// <summary>
/// Test adding and removing beatmap sets
/// </summary>
2019-09-25 01:42:12 +08:00
[Test]
public void TestAddRemove ( )
2017-12-14 19:40:58 +08:00
{
2019-09-25 01:42:12 +08:00
loadBeatmaps ( ) ;
2021-11-24 16:59:23 +08:00
var firstAdded = TestResources . CreateTestBeatmapSetInfo ( ) ;
var secondAdded = TestResources . CreateTestBeatmapSetInfo ( ) ;
AddStep ( "Add new set" , ( ) = > carousel . UpdateBeatmapSet ( firstAdded ) ) ;
AddStep ( "Add new set" , ( ) = > carousel . UpdateBeatmapSet ( secondAdded ) ) ;
2018-04-13 17:19:50 +08:00
2017-12-15 13:36:11 +08:00
checkVisibleItemCount ( false , set_count + 2 ) ;
2018-04-13 17:19:50 +08:00
2021-11-24 16:59:23 +08:00
AddStep ( "Remove set" , ( ) = > carousel . RemoveBeatmapSet ( firstAdded ) ) ;
2018-04-13 17:19:50 +08:00
2017-12-15 13:36:11 +08:00
checkVisibleItemCount ( false , set_count + 1 ) ;
2018-04-13 17:19:50 +08:00
2017-12-16 15:14:01 +08:00
setSelected ( set_count + 1 , 1 ) ;
2018-04-13 17:19:50 +08:00
2021-11-24 16:59:23 +08:00
AddStep ( "Remove set" , ( ) = > carousel . RemoveBeatmapSet ( secondAdded ) ) ;
2018-04-13 17:19:50 +08:00
2017-12-15 13:36:11 +08:00
checkVisibleItemCount ( false , set_count ) ;
2018-04-13 17:19:50 +08:00
2019-09-29 12:23:18 +08:00
waitForSelection ( set_count ) ;
2017-12-14 19:40:58 +08:00
}
2018-04-13 17:19:50 +08:00
2020-03-20 14:01:26 +08:00
[Test]
public void TestSelectionEnteringFromEmptyRuleset ( )
{
var sets = new List < BeatmapSetInfo > ( ) ;
AddStep ( "Create beatmaps for taiko only" , ( ) = >
{
2020-03-23 10:12:36 +08:00
sets . Clear ( ) ;
2021-11-24 16:59:23 +08:00
var rulesetBeatmapSet = TestResources . CreateTestBeatmapSetInfo ( 1 ) ;
2020-03-20 14:01:26 +08:00
var taikoRuleset = rulesets . AvailableRulesets . ElementAt ( 1 ) ;
2021-11-22 15:10:13 +08:00
rulesetBeatmapSet . Beatmaps . ForEach ( b = > b . Ruleset = taikoRuleset ) ;
2020-03-20 14:01:26 +08:00
sets . Add ( rulesetBeatmapSet ) ;
} ) ;
loadBeatmaps ( sets , ( ) = > new FilterCriteria { Ruleset = rulesets . AvailableRulesets . ElementAt ( 0 ) } ) ;
AddStep ( "Set non-empty mode filter" , ( ) = >
carousel . Filter ( new FilterCriteria { Ruleset = rulesets . AvailableRulesets . ElementAt ( 1 ) } , false ) ) ;
2021-10-02 11:44:22 +08:00
AddAssert ( "Something is selected" , ( ) = > carousel . SelectedBeatmapInfo ! = null ) ;
2020-03-20 14:01:26 +08:00
}
2022-09-01 18:59:20 +08:00
[Test]
public void TestSortingDateSubmitted ( )
{
var sets = new List < BeatmapSetInfo > ( ) ;
const string zzz_string = "zzzzz" ;
AddStep ( "Populuate beatmap sets" , ( ) = >
{
sets . Clear ( ) ;
for ( int i = 0 ; i < 20 ; i + + )
{
var set = TestResources . CreateTestBeatmapSetInfo ( 5 ) ;
if ( i > = 2 & & i < 10 )
set . DateSubmitted = DateTimeOffset . Now . AddMinutes ( i ) ;
if ( i < 5 )
set . Beatmaps . ForEach ( b = > b . Metadata . Artist = zzz_string ) ;
sets . Add ( set ) ;
}
} ) ;
loadBeatmaps ( sets ) ;
AddStep ( "Sort by date submitted" , ( ) = > carousel . Filter ( new FilterCriteria { Sort = SortMode . DateSubmitted } , false ) ) ;
checkVisibleItemCount ( diff : false , count : 8 ) ;
checkVisibleItemCount ( diff : true , count : 5 ) ;
AddStep ( "Sort by date submitted and string" , ( ) = > carousel . Filter ( new FilterCriteria
{
Sort = SortMode . DateSubmitted ,
SearchText = zzz_string
} , false ) ) ;
checkVisibleItemCount ( diff : false , count : 3 ) ;
checkVisibleItemCount ( diff : true , count : 5 ) ;
}
2019-09-25 01:42:12 +08:00
[Test]
public void TestSorting ( )
2017-12-14 19:40:58 +08:00
{
2021-11-24 16:59:23 +08:00
var sets = new List < BeatmapSetInfo > ( ) ;
const string zzz_string = "zzzzz" ;
2022-08-25 13:03:25 +08:00
AddStep ( "Populuate beatmap sets" , ( ) = >
2021-11-24 16:59:23 +08:00
{
2022-08-25 13:03:25 +08:00
sets . Clear ( ) ;
2021-11-24 16:59:23 +08:00
2022-08-25 13:03:25 +08:00
for ( int i = 0 ; i < 20 ; i + + )
{
var set = TestResources . CreateTestBeatmapSetInfo ( ) ;
2021-11-24 16:59:23 +08:00
2022-08-25 13:03:25 +08:00
if ( i = = 4 )
set . Beatmaps . ForEach ( b = > b . Metadata . Artist = zzz_string ) ;
2021-11-24 16:59:23 +08:00
2022-08-25 13:03:25 +08:00
if ( i = = 16 )
set . Beatmaps . ForEach ( b = > b . Metadata . Author . Username = zzz_string ) ;
sets . Add ( set ) ;
}
} ) ;
2021-11-24 16:59:23 +08:00
loadBeatmaps ( sets ) ;
2019-09-25 01:42:12 +08:00
2017-12-14 19:40:58 +08:00
AddStep ( "Sort by author" , ( ) = > carousel . Filter ( new FilterCriteria { Sort = SortMode . Author } , false ) ) ;
2021-11-24 16:59:23 +08:00
AddAssert ( $"Check {zzz_string} is at bottom" , ( ) = > carousel . BeatmapSets . Last ( ) . Metadata . Author . Username = = zzz_string ) ;
2017-12-15 13:36:11 +08:00
AddStep ( "Sort by artist" , ( ) = > carousel . Filter ( new FilterCriteria { Sort = SortMode . Artist } , false ) ) ;
2021-11-24 16:59:23 +08:00
AddAssert ( $"Check {zzz_string} is at bottom" , ( ) = > carousel . BeatmapSets . Last ( ) . Metadata . Artist = = zzz_string ) ;
2017-12-13 18:56:16 +08:00
}
2018-04-13 17:19:50 +08:00
2022-08-01 23:43:01 +08:00
/// <summary>
/// Ensures stability is maintained on different sort modes for items with equal properties.
/// </summary>
2019-10-28 05:55:46 +08:00
[Test]
public void TestSortingStability ( )
{
var sets = new List < BeatmapSetInfo > ( ) ;
2022-08-25 13:03:25 +08:00
int idOffset = 0 ;
2019-10-28 05:55:46 +08:00
2022-08-25 13:03:25 +08:00
AddStep ( "Populuate beatmap sets" , ( ) = >
2019-10-28 05:55:46 +08:00
{
2022-08-25 13:03:25 +08:00
sets . Clear ( ) ;
2021-11-22 13:29:46 +08:00
2022-08-25 13:03:25 +08:00
for ( int i = 0 ; i < 10 ; i + + )
{
var set = TestResources . CreateTestBeatmapSetInfo ( ) ;
2021-11-22 13:29:46 +08:00
2022-08-25 13:03:25 +08:00
// only need to set the first as they are a shared reference.
var beatmap = set . Beatmaps . First ( ) ;
2021-11-22 13:29:46 +08:00
2022-08-25 13:03:25 +08:00
beatmap . Metadata . Artist = $"artist {i / 2}" ;
beatmap . Metadata . Title = $"title {9 - i}" ;
sets . Add ( set ) ;
}
2019-10-28 05:55:46 +08:00
2022-08-25 13:03:25 +08:00
idOffset = sets . First ( ) . OnlineID ;
} ) ;
2021-11-24 16:59:23 +08:00
2019-10-28 05:55:46 +08:00
loadBeatmaps ( sets ) ;
AddStep ( "Sort by artist" , ( ) = > carousel . Filter ( new FilterCriteria { Sort = SortMode . Artist } , false ) ) ;
2022-07-26 15:24:16 +08:00
AddAssert ( "Items remain in original order" , ( ) = > carousel . BeatmapSets . Select ( ( set , index ) = > set . OnlineID = = idOffset + index ) . All ( b = > b ) ) ;
2019-10-28 05:55:46 +08:00
AddStep ( "Sort by title" , ( ) = > carousel . Filter ( new FilterCriteria { Sort = SortMode . Title } , false ) ) ;
2022-07-26 15:24:16 +08:00
AddAssert ( "Items are in reverse order" , ( ) = > carousel . BeatmapSets . Select ( ( set , index ) = > set . OnlineID = = idOffset + sets . Count - index - 1 ) . All ( b = > b ) ) ;
AddStep ( "Sort by artist" , ( ) = > carousel . Filter ( new FilterCriteria { Sort = SortMode . Artist } , false ) ) ;
AddAssert ( "Items reset to original order" , ( ) = > carousel . BeatmapSets . Select ( ( set , index ) = > set . OnlineID = = idOffset + index ) . All ( b = > b ) ) ;
2019-10-28 05:55:46 +08:00
}
2022-08-01 23:43:01 +08:00
/// <summary>
/// Ensures stability is maintained on different sort modes while a new item is added to the carousel.
/// </summary>
[Test]
public void TestSortingStabilityWithNewItems ( )
{
List < BeatmapSetInfo > sets = new List < BeatmapSetInfo > ( ) ;
2022-08-25 13:03:25 +08:00
int idOffset = 0 ;
2022-08-01 23:43:01 +08:00
2022-08-25 13:03:25 +08:00
AddStep ( "Populuate beatmap sets" , ( ) = >
2022-08-01 23:43:01 +08:00
{
2022-08-25 13:03:25 +08:00
sets . Clear ( ) ;
2022-08-01 23:43:01 +08:00
2022-08-25 13:03:25 +08:00
for ( int i = 0 ; i < 3 ; i + + )
{
var set = TestResources . CreateTestBeatmapSetInfo ( 3 ) ;
2022-08-01 23:43:01 +08:00
2022-08-25 13:03:25 +08:00
// only need to set the first as they are a shared reference.
var beatmap = set . Beatmaps . First ( ) ;
2022-08-01 23:43:01 +08:00
2022-08-25 13:03:25 +08:00
beatmap . Metadata . Artist = "same artist" ;
beatmap . Metadata . Title = "same title" ;
2022-08-01 23:43:01 +08:00
2022-08-25 13:03:25 +08:00
sets . Add ( set ) ;
}
idOffset = sets . First ( ) . OnlineID ;
} ) ;
2022-08-01 23:43:01 +08:00
loadBeatmaps ( sets ) ;
AddStep ( "Sort by artist" , ( ) = > carousel . Filter ( new FilterCriteria { Sort = SortMode . Artist } , false ) ) ;
2022-08-25 13:03:25 +08:00
assertOriginalOrderMaintained ( ) ;
2022-08-01 23:43:01 +08:00
AddStep ( "Add new item" , ( ) = >
{
var set = TestResources . CreateTestBeatmapSetInfo ( ) ;
// only need to set the first as they are a shared reference.
var beatmap = set . Beatmaps . First ( ) ;
beatmap . Metadata . Artist = "same artist" ;
beatmap . Metadata . Title = "same title" ;
carousel . UpdateBeatmapSet ( set ) ;
} ) ;
2022-08-25 13:03:25 +08:00
assertOriginalOrderMaintained ( ) ;
2022-08-01 23:43:01 +08:00
AddStep ( "Sort by title" , ( ) = > carousel . Filter ( new FilterCriteria { Sort = SortMode . Title } , false ) ) ;
2022-08-25 13:03:25 +08:00
assertOriginalOrderMaintained ( ) ;
void assertOriginalOrderMaintained ( )
{
AddAssert ( "Items remain in original order" ,
( ) = > carousel . BeatmapSets . Select ( s = > s . OnlineID ) , ( ) = > Is . EqualTo ( carousel . BeatmapSets . Select ( ( set , index ) = > idOffset + index ) ) ) ;
}
2022-08-01 23:43:01 +08:00
}
2019-10-07 14:13:58 +08:00
[Test]
public void TestSortingWithFiltered ( )
{
List < BeatmapSetInfo > sets = new List < BeatmapSetInfo > ( ) ;
2022-08-25 13:03:25 +08:00
AddStep ( "Populuate beatmap sets" , ( ) = >
2019-10-07 14:13:58 +08:00
{
2022-08-25 13:03:25 +08:00
sets . Clear ( ) ;
for ( int i = 0 ; i < 3 ; i + + )
{
var set = TestResources . CreateTestBeatmapSetInfo ( 3 ) ;
set . Beatmaps [ 0 ] . StarRating = 3 - i ;
set . Beatmaps [ 2 ] . StarRating = 6 + i ;
sets . Add ( set ) ;
}
} ) ;
2019-10-07 14:13:58 +08:00
loadBeatmaps ( sets ) ;
AddStep ( "Filter to normal" , ( ) = > carousel . Filter ( new FilterCriteria { Sort = SortMode . Difficulty , SearchText = "Normal" } , false ) ) ;
2021-11-22 16:15:26 +08:00
AddAssert ( "Check first set at end" , ( ) = > carousel . BeatmapSets . First ( ) . Equals ( sets . Last ( ) ) ) ;
AddAssert ( "Check last set at start" , ( ) = > carousel . BeatmapSets . Last ( ) . Equals ( sets . First ( ) ) ) ;
2019-10-07 14:13:58 +08:00
AddStep ( "Filter to insane" , ( ) = > carousel . Filter ( new FilterCriteria { Sort = SortMode . Difficulty , SearchText = "Insane" } , false ) ) ;
2021-11-22 16:15:26 +08:00
AddAssert ( "Check first set at start" , ( ) = > carousel . BeatmapSets . First ( ) . Equals ( sets . First ( ) ) ) ;
AddAssert ( "Check last set at end" , ( ) = > carousel . BeatmapSets . Last ( ) . Equals ( sets . Last ( ) ) ) ;
2019-10-07 14:13:58 +08:00
}
2019-09-25 01:42:12 +08:00
[Test]
public void TestRemoveAll ( )
2017-12-15 23:33:09 +08:00
{
2019-09-25 01:42:12 +08:00
loadBeatmaps ( ) ;
2017-12-15 23:33:09 +08:00
setSelected ( 2 , 1 ) ;
AddAssert ( "Selection is non-null" , ( ) = > currentSelection ! = null ) ;
2018-04-13 17:19:50 +08:00
2022-09-07 13:40:51 +08:00
AddStep ( "Remove selected" , ( ) = > carousel . RemoveBeatmapSet ( carousel . SelectedBeatmapSet ! ) ) ;
2019-09-29 12:23:18 +08:00
waitForSelection ( 2 ) ;
2018-04-13 17:19:50 +08:00
2017-12-16 16:32:21 +08:00
AddStep ( "Remove first" , ( ) = > carousel . RemoveBeatmapSet ( carousel . BeatmapSets . First ( ) ) ) ;
AddStep ( "Remove first" , ( ) = > carousel . RemoveBeatmapSet ( carousel . BeatmapSets . First ( ) ) ) ;
2019-09-29 12:23:18 +08:00
waitForSelection ( 1 ) ;
2018-04-13 17:19:50 +08:00
2019-03-19 16:24:26 +08:00
AddUntilStep ( "Remove all" , ( ) = >
2017-12-15 23:33:09 +08:00
{
2017-12-18 01:51:09 +08:00
if ( ! carousel . BeatmapSets . Any ( ) ) return true ;
2018-04-13 17:19:50 +08:00
2017-12-15 23:33:09 +08:00
carousel . RemoveBeatmapSet ( carousel . BeatmapSets . Last ( ) ) ;
2017-12-18 01:51:09 +08:00
return false ;
2019-03-19 16:24:26 +08:00
} ) ;
2018-04-13 17:19:50 +08:00
2017-12-23 19:53:11 +08:00
checkNoSelection ( ) ;
2017-12-15 23:33:09 +08:00
}
2018-04-13 17:19:50 +08:00
2019-09-25 01:42:12 +08:00
[Test]
public void TestEmptyTraversal ( )
2017-12-23 19:53:11 +08:00
{
2019-09-25 01:42:12 +08:00
loadBeatmaps ( new List < BeatmapSetInfo > ( ) ) ;
2017-12-23 19:53:11 +08:00
advanceSelection ( direction : 1 , diff : false ) ;
checkNoSelection ( ) ;
2018-04-13 17:19:50 +08:00
2017-12-23 19:53:11 +08:00
advanceSelection ( direction : 1 , diff : true ) ;
checkNoSelection ( ) ;
2018-04-13 17:19:50 +08:00
2017-12-23 19:53:11 +08:00
advanceSelection ( direction : - 1 , diff : false ) ;
checkNoSelection ( ) ;
2018-04-13 17:19:50 +08:00
2017-12-23 19:53:11 +08:00
advanceSelection ( direction : - 1 , diff : true ) ;
checkNoSelection ( ) ;
}
2018-04-13 17:19:50 +08:00
2019-09-25 01:42:12 +08:00
[Test]
public void TestHiding ( )
2017-12-26 10:57:18 +08:00
{
2019-11-15 10:46:32 +08:00
BeatmapSetInfo hidingSet = null ;
List < BeatmapSetInfo > hiddenList = new List < BeatmapSetInfo > ( ) ;
2019-09-25 01:42:12 +08:00
2019-11-15 10:46:32 +08:00
AddStep ( "create hidden set" , ( ) = >
{
2021-11-24 16:59:23 +08:00
hidingSet = TestResources . CreateTestBeatmapSetInfo ( 3 ) ;
2019-11-15 10:46:32 +08:00
hidingSet . Beatmaps [ 1 ] . Hidden = true ;
hiddenList . Clear ( ) ;
hiddenList . Add ( hidingSet ) ;
} ) ;
loadBeatmaps ( hiddenList ) ;
2019-09-25 01:42:12 +08:00
2017-12-26 10:57:18 +08:00
setSelected ( 1 , 1 ) ;
2018-04-13 17:19:50 +08:00
2017-12-26 10:57:18 +08:00
checkVisibleItemCount ( true , 2 ) ;
advanceSelection ( true ) ;
2019-09-29 12:23:18 +08:00
waitForSelection ( 1 , 3 ) ;
2018-04-13 17:19:50 +08:00
2017-12-26 10:57:18 +08:00
setHidden ( 3 ) ;
2019-09-29 12:23:18 +08:00
waitForSelection ( 1 , 1 ) ;
2018-04-13 17:19:50 +08:00
2017-12-26 10:57:18 +08:00
setHidden ( 2 , false ) ;
advanceSelection ( true ) ;
2019-09-29 12:23:18 +08:00
waitForSelection ( 1 , 2 ) ;
2018-04-13 17:19:50 +08:00
2017-12-26 10:57:18 +08:00
setHidden ( 1 ) ;
2019-09-29 12:23:18 +08:00
waitForSelection ( 1 , 2 ) ;
2018-04-13 17:19:50 +08:00
2017-12-26 10:57:18 +08:00
setHidden ( 2 ) ;
checkNoSelection ( ) ;
2018-04-13 17:19:50 +08:00
2017-12-26 10:57:18 +08:00
void setHidden ( int diff , bool hidden = true )
{
AddStep ( ( hidden ? "" : "un" ) + $"hide diff {diff}" , ( ) = >
{
hidingSet . Beatmaps [ diff - 1 ] . Hidden = hidden ;
carousel . UpdateBeatmapSet ( hidingSet ) ;
} ) ;
}
}
2018-04-13 17:19:50 +08:00
2019-09-25 01:42:12 +08:00
[Test]
public void TestSelectingFilteredRuleset ( )
2018-03-09 22:09:28 +08:00
{
2019-11-15 10:46:32 +08:00
BeatmapSetInfo testMixed = null ;
2022-02-03 15:04:05 +08:00
createCarousel ( new List < BeatmapSetInfo > ( ) ) ;
2019-11-13 18:09:03 +08:00
2018-03-09 22:09:28 +08:00
AddStep ( "add mixed ruleset beatmapset" , ( ) = >
{
2021-11-25 15:27:55 +08:00
testMixed = TestResources . CreateTestBeatmapSetInfo ( 3 ) ;
2019-11-15 10:46:32 +08:00
2018-03-09 22:09:28 +08:00
for ( int i = 0 ; i < = 2 ; i + + )
{
testMixed . Beatmaps [ i ] . Ruleset = rulesets . AvailableRulesets . ElementAt ( i ) ;
}
2018-04-13 17:19:50 +08:00
2018-03-09 22:09:28 +08:00
carousel . UpdateBeatmapSet ( testMixed ) ;
} ) ;
AddStep ( "filter to ruleset 0" , ( ) = >
carousel . Filter ( new FilterCriteria { Ruleset = rulesets . AvailableRulesets . ElementAt ( 0 ) } , false ) ) ;
AddStep ( "select filtered map skipping filtered" , ( ) = > carousel . SelectBeatmap ( testMixed . Beatmaps [ 1 ] , false ) ) ;
2022-09-07 13:40:51 +08:00
AddAssert ( "unfiltered beatmap not selected" , ( ) = > carousel . SelectedBeatmapInfo ? . Ruleset . OnlineID = = 0 ) ;
2018-04-13 17:19:50 +08:00
2018-03-09 22:09:28 +08:00
AddStep ( "remove mixed set" , ( ) = >
{
carousel . RemoveBeatmapSet ( testMixed ) ;
testMixed = null ;
} ) ;
2020-03-20 14:02:13 +08:00
BeatmapSetInfo testSingle = null ;
AddStep ( "add single ruleset beatmapset" , ( ) = >
2018-03-09 22:09:28 +08:00
{
2021-11-25 15:27:55 +08:00
testSingle = TestResources . CreateTestBeatmapSetInfo ( 3 ) ;
2020-03-20 14:02:13 +08:00
testSingle . Beatmaps . ForEach ( b = >
{
b . Ruleset = rulesets . AvailableRulesets . ElementAt ( 1 ) ;
} ) ;
carousel . UpdateBeatmapSet ( testSingle ) ;
2018-03-09 22:09:28 +08:00
} ) ;
AddStep ( "select filtered map skipping filtered" , ( ) = > carousel . SelectBeatmap ( testSingle . Beatmaps [ 0 ] , false ) ) ;
checkNoSelection ( ) ;
AddStep ( "remove single ruleset set" , ( ) = > carousel . RemoveBeatmapSet ( testSingle ) ) ;
}
2018-04-13 17:19:50 +08:00
2020-03-19 17:58:22 +08:00
[Test]
2022-10-25 03:50:56 +08:00
public void TestCarouselRemembersSelection ( )
2020-03-19 17:58:22 +08:00
{
List < BeatmapSetInfo > manySets = new List < BeatmapSetInfo > ( ) ;
2022-10-25 03:50:56 +08:00
AddStep ( "Populuate beatmap sets" , ( ) = >
2020-03-19 17:58:22 +08:00
{
2022-08-25 13:03:25 +08:00
manySets . Clear ( ) ;
2022-10-25 03:50:56 +08:00
for ( int i = 1 ; i < = 50 ; i + + )
manySets . Add ( TestResources . CreateTestBeatmapSetInfo ( 3 ) ) ;
2020-03-19 17:58:22 +08:00
} ) ;
loadBeatmaps ( manySets ) ;
2022-10-25 03:50:56 +08:00
advanceSelection ( direction : 1 , diff : false ) ;
2020-03-19 17:58:22 +08:00
2022-10-25 03:50:56 +08:00
for ( int i = 0 ; i < 5 ; i + + )
{
2020-03-19 17:58:22 +08:00
AddStep ( "Toggle non-matching filter" , ( ) = >
{
carousel . Filter ( new FilterCriteria { SearchText = Guid . NewGuid ( ) . ToString ( ) } , false ) ;
} ) ;
2022-10-25 03:50:56 +08:00
AddStep ( "Restore no filter" , ( ) = >
2020-03-19 17:58:22 +08:00
{
2022-10-25 03:50:56 +08:00
carousel . Filter ( new FilterCriteria ( ) , false ) ;
2022-09-07 13:40:51 +08:00
eagerSelectedIDs . Add ( carousel . SelectedBeatmapSet ! . ID ) ;
2020-03-19 17:58:22 +08:00
} ) ;
}
2022-10-25 03:50:56 +08:00
// always returns to same selection as long as it's available.
AddAssert ( "Selection was remembered" , ( ) = > eagerSelectedIDs . Count = = 1 ) ;
2018-04-02 16:56:35 +08:00
}
2018-04-13 17:19:50 +08:00
2020-01-24 18:40:20 +08:00
[Test]
public void TestFilteringByUserStarDifficulty ( )
{
BeatmapSetInfo set = null ;
loadBeatmaps ( new List < BeatmapSetInfo > ( ) ) ;
AddStep ( "add mixed difficulty set" , ( ) = >
{
2021-11-24 16:59:23 +08:00
set = TestResources . CreateTestBeatmapSetInfo ( 1 ) ;
2020-01-24 18:40:20 +08:00
set . Beatmaps . Clear ( ) ;
for ( int i = 1 ; i < = 15 ; i + + )
{
2022-01-10 13:52:59 +08:00
set . Beatmaps . Add ( new BeatmapInfo ( new OsuRuleset ( ) . RulesetInfo , new BeatmapDifficulty ( ) , new BeatmapMetadata ( ) )
2020-01-24 18:40:20 +08:00
{
2021-11-11 16:19:53 +08:00
DifficultyName = $"Stars: {i}" ,
2021-11-11 16:18:51 +08:00
StarRating = i ,
2020-01-24 18:40:20 +08:00
} ) ;
}
carousel . UpdateBeatmapSet ( set ) ;
} ) ;
AddStep ( "select added set" , ( ) = > carousel . SelectBeatmap ( set . Beatmaps [ 0 ] , false ) ) ;
AddStep ( "filter [5..]" , ( ) = > carousel . Filter ( new FilterCriteria { UserStarDifficulty = { Min = 5 } } ) ) ;
AddUntilStep ( "Wait for debounce" , ( ) = > ! carousel . PendingFilterTask ) ;
checkVisibleItemCount ( true , 11 ) ;
AddStep ( "filter to [0..7]" , ( ) = > carousel . Filter ( new FilterCriteria { UserStarDifficulty = { Max = 7 } } ) ) ;
AddUntilStep ( "Wait for debounce" , ( ) = > ! carousel . PendingFilterTask ) ;
checkVisibleItemCount ( true , 7 ) ;
AddStep ( "filter to [5..7]" , ( ) = > carousel . Filter ( new FilterCriteria { UserStarDifficulty = { Min = 5 , Max = 7 } } ) ) ;
AddUntilStep ( "Wait for debounce" , ( ) = > ! carousel . PendingFilterTask ) ;
checkVisibleItemCount ( true , 3 ) ;
AddStep ( "filter [2..2]" , ( ) = > carousel . Filter ( new FilterCriteria { UserStarDifficulty = { Min = 2 , Max = 2 } } ) ) ;
AddUntilStep ( "Wait for debounce" , ( ) = > ! carousel . PendingFilterTask ) ;
checkVisibleItemCount ( true , 1 ) ;
AddStep ( "filter to [0..]" , ( ) = > carousel . Filter ( new FilterCriteria { UserStarDifficulty = { Min = 0 } } ) ) ;
AddUntilStep ( "Wait for debounce" , ( ) = > ! carousel . PendingFilterTask ) ;
checkVisibleItemCount ( true , 15 ) ;
}
2022-10-25 03:55:09 +08:00
[Test]
public void TestCarouselSelectsNextWhenPreviousIsFiltered ( )
{
List < BeatmapSetInfo > sets = new List < BeatmapSetInfo > ( ) ;
// 10 sets that go osu! -> taiko -> catch -> osu! -> ...
for ( int i = 0 ; i < 10 ; i + + )
{
var rulesetInfo = rulesets . AvailableRulesets . ElementAt ( i % 3 ) ;
sets . Add ( TestResources . CreateTestBeatmapSetInfo ( 5 , new [ ] { rulesetInfo } ) ) ;
}
// Sort mode is important to keep the ruleset order
loadBeatmaps ( sets , ( ) = > new FilterCriteria { Sort = SortMode . Title } ) ;
setSelected ( 1 , 1 ) ;
for ( int i = 1 ; i < 10 ; i + + )
{
var rulesetInfo = rulesets . AvailableRulesets . ElementAt ( i % 3 ) ;
AddStep ( $"Set ruleset to {rulesetInfo.ShortName}" , ( ) = >
{
carousel . Filter ( new FilterCriteria { Ruleset = rulesetInfo , Sort = SortMode . Title } , false ) ;
} ) ;
waitForSelection ( i + 1 , 1 ) ;
}
}
[Test]
public void TestCarouselSelectsBackwardsWhenDistanceIsShorter ( )
{
List < BeatmapSetInfo > sets = new List < BeatmapSetInfo > ( ) ;
// 10 sets that go taiko, osu!, osu!, osu!, taiko, osu!, osu!, osu!, ...
for ( int i = 0 ; i < 10 ; i + + )
{
var rulesetInfo = rulesets . AvailableRulesets . ElementAt ( i % 4 = = 0 ? 1 : 0 ) ;
sets . Add ( TestResources . CreateTestBeatmapSetInfo ( 5 , new [ ] { rulesetInfo } ) ) ;
}
// Sort mode is important to keep the ruleset order
loadBeatmaps ( sets , ( ) = > new FilterCriteria { Sort = SortMode . Title } ) ;
for ( int i = 2 ; i < 10 ; i + = 4 )
{
setSelected ( i , 1 ) ;
AddStep ( "Set ruleset to taiko" , ( ) = >
{
carousel . Filter ( new FilterCriteria { Ruleset = rulesets . AvailableRulesets . ElementAt ( 1 ) , Sort = SortMode . Title } , false ) ;
} ) ;
waitForSelection ( i - 1 , 1 ) ;
AddStep ( "Remove ruleset filter" , ( ) = >
{
carousel . Filter ( new FilterCriteria { Sort = SortMode . Title } , false ) ;
} ) ;
}
}
2022-07-18 17:06:11 +08:00
private void loadBeatmaps ( List < BeatmapSetInfo > beatmapSets = null , Func < FilterCriteria > initialCriteria = null , Action < BeatmapCarousel > carouselAdjust = null , int? count = null ,
bool randomDifficulties = false )
2019-10-07 13:45:26 +08:00
{
2020-10-12 13:23:18 +08:00
bool changed = false ;
2019-11-13 18:09:03 +08:00
2022-02-03 15:04:05 +08:00
if ( beatmapSets = = null )
2019-10-07 13:45:26 +08:00
{
2022-02-03 15:04:05 +08:00
beatmapSets = new List < BeatmapSetInfo > ( ) ;
2019-10-07 13:45:26 +08:00
2022-02-03 15:04:05 +08:00
for ( int i = 1 ; i < = ( count ? ? set_count ) ; i + + )
2020-10-12 13:23:18 +08:00
{
2022-02-03 15:04:05 +08:00
beatmapSets . Add ( randomDifficulties
? TestResources . CreateTestBeatmapSetInfo ( )
: TestResources . CreateTestBeatmapSetInfo ( 3 ) ) ;
2020-10-12 13:23:18 +08:00
}
2022-02-03 15:04:05 +08:00
}
createCarousel ( beatmapSets , c = >
{
carouselAdjust ? . Invoke ( c ) ;
2019-10-07 13:45:26 +08:00
2020-03-20 14:01:26 +08:00
carousel . Filter ( initialCriteria ? . Invoke ( ) ? ? new FilterCriteria ( ) ) ;
2019-10-07 13:45:26 +08:00
carousel . BeatmapSetsChanged = ( ) = > changed = true ;
carousel . BeatmapSets = beatmapSets ;
} ) ;
AddUntilStep ( "Wait for load" , ( ) = > changed ) ;
}
2022-02-03 15:04:05 +08:00
private void createCarousel ( List < BeatmapSetInfo > beatmapSets , Action < BeatmapCarousel > carouselAdjust = null , Container target = null )
2019-11-13 18:09:03 +08:00
{
2019-11-13 18:42:33 +08:00
AddStep ( "Create carousel" , ( ) = >
2019-11-13 18:09:03 +08:00
{
2019-11-15 10:18:19 +08:00
selectedSets . Clear ( ) ;
eagerSelectedIDs . Clear ( ) ;
2020-07-13 16:05:29 +08:00
carousel = new TestBeatmapCarousel
2019-11-13 18:09:03 +08:00
{
RelativeSizeAxes = Axes . Both ,
} ;
2020-07-13 16:05:29 +08:00
carouselAdjust ? . Invoke ( carousel ) ;
2022-02-03 15:04:05 +08:00
carousel . BeatmapSets = beatmapSets ;
2020-07-13 16:05:29 +08:00
( target ? ? this ) . Child = carousel ;
2019-11-13 18:09:03 +08:00
} ) ;
}
2019-10-07 13:45:26 +08:00
private void ensureRandomFetchSuccess ( ) = >
2021-11-22 16:15:26 +08:00
AddAssert ( "ensure prev random fetch worked" , ( ) = > selectedSets . Peek ( ) . Equals ( carousel . SelectedBeatmapSet ) ) ;
2019-10-07 13:45:26 +08:00
private void waitForSelection ( int set , int? diff = null ) = >
AddUntilStep ( $"selected is set{set}{(diff.HasValue ? $" diff { diff . Value } " : " ")}" , ( ) = >
{
if ( diff ! = null )
2021-11-24 16:59:23 +08:00
return carousel . SelectedBeatmapInfo ? . Equals ( carousel . BeatmapSets . Skip ( set - 1 ) . First ( ) . Beatmaps . Skip ( diff . Value - 1 ) . First ( ) ) = = true ;
2019-10-07 13:45:26 +08:00
2021-10-02 11:44:22 +08:00
return carousel . BeatmapSets . Skip ( set - 1 ) . First ( ) . Beatmaps . Contains ( carousel . SelectedBeatmapInfo ) ;
2019-10-07 13:45:26 +08:00
} ) ;
private void setSelected ( int set , int diff ) = >
AddStep ( $"select set{set} diff{diff}" , ( ) = >
carousel . SelectBeatmap ( carousel . BeatmapSets . Skip ( set - 1 ) . First ( ) . Beatmaps . Skip ( diff - 1 ) . First ( ) ) ) ;
private void advanceSelection ( bool diff , int direction = 1 , int count = 1 )
{
if ( count = = 1 )
2019-11-11 19:53:22 +08:00
{
2019-10-07 13:45:26 +08:00
AddStep ( $"select {(direction > 0 ? " next " : " prev ")} {(diff ? " diff " : " set ")}" , ( ) = >
carousel . SelectNext ( direction , ! diff ) ) ;
2019-11-11 19:53:22 +08:00
}
2019-10-07 13:45:26 +08:00
else
{
AddRepeatStep ( $"select {(direction > 0 ? " next " : " prev ")} {(diff ? " diff " : " set ")}" , ( ) = >
carousel . SelectNext ( direction , ! diff ) , count ) ;
}
}
2021-05-27 15:12:49 +08:00
private void checkVisibleItemCount ( bool diff , int count )
{
// until step required as we are querying against alive items, which are loaded asynchronously inside DrawableCarouselBeatmapSet.
AddUntilStep ( $"{count} {(diff ? " diffs " : " sets ")} visible" , ( ) = >
2019-10-07 13:45:26 +08:00
carousel . Items . Count ( s = > ( diff ? s . Item is CarouselBeatmap : s . Item is CarouselBeatmapSet ) & & s . Item . Visible ) = = count ) ;
2021-05-27 15:12:49 +08:00
}
2019-10-07 13:45:26 +08:00
2022-01-27 15:38:02 +08:00
private void checkSelectionIsCentered ( )
{
AddAssert ( "Selected panel is centered" , ( ) = >
{
return Precision . AlmostEquals (
carousel . ScreenSpaceDrawQuad . Centre ,
carousel . Items
. First ( i = > i . Item . State . Value = = CarouselItemState . Selected )
. ScreenSpaceDrawQuad . Centre , 100 ) ;
} ) ;
}
2019-10-07 13:45:26 +08:00
private void checkNoSelection ( ) = > AddAssert ( "Selection is null" , ( ) = > currentSelection = = null ) ;
private void nextRandom ( ) = >
AddStep ( "select random next" , ( ) = >
{
carousel . RandomAlgorithm . Value = RandomSelectAlgorithm . RandomPermutation ;
2021-10-02 11:44:22 +08:00
if ( ! selectedSets . Any ( ) & & carousel . SelectedBeatmapInfo ! = null )
2019-10-07 13:45:26 +08:00
selectedSets . Push ( carousel . SelectedBeatmapSet ) ;
carousel . SelectNextRandom ( ) ;
selectedSets . Push ( carousel . SelectedBeatmapSet ) ;
} ) ;
private void ensureRandomDidntRepeat ( ) = >
AddAssert ( "ensure no repeats" , ( ) = > selectedSets . Distinct ( ) . Count ( ) = = selectedSets . Count ) ;
private void prevRandom ( ) = > AddStep ( "select random last" , ( ) = >
{
carousel . SelectPreviousRandom ( ) ;
selectedSets . Pop ( ) ;
} ) ;
private bool selectedBeatmapVisible ( )
{
2020-10-12 13:23:18 +08:00
var currentlySelected = carousel . Items . FirstOrDefault ( s = > s . Item is CarouselBeatmap & & s . Item . State . Value = = CarouselItemState . Selected ) ;
2019-10-07 13:45:26 +08:00
if ( currentlySelected = = null )
return true ;
return currentlySelected . Item . Visible ;
}
private void checkInvisibleDifficultiesUnselectable ( )
{
nextRandom ( ) ;
AddAssert ( "Selection is visible" , selectedBeatmapVisible ) ;
}
2017-12-13 20:08:12 +08:00
private partial class TestBeatmapCarousel : BeatmapCarousel
{
2018-07-18 09:12:14 +08:00
public bool PendingFilterTask = > PendingFilter ! = null ;
2020-03-12 14:26:22 +08:00
2020-10-13 16:09:54 +08:00
public IEnumerable < DrawableCarouselItem > Items
{
get
{
2020-11-26 17:28:52 +08:00
foreach ( var item in Scroll . Children )
2020-10-13 16:09:54 +08:00
{
yield return item ;
if ( item is DrawableCarouselBeatmapSet set )
{
2020-10-13 18:15:56 +08:00
foreach ( var difficulty in set . DrawableBeatmaps )
2020-10-13 16:09:54 +08:00
yield return difficulty ;
}
}
}
}
2017-12-13 20:08:12 +08:00
}
2017-12-13 18:56:16 +08:00
}
}