1
0
mirror of https://github.com/ppy/osu.git synced 2025-03-16 00:37:19 +08:00

Add test coverage for grouped selection

This commit is contained in:
Dean Herbert 2025-02-01 14:55:48 +09:00
parent 645c26ca19
commit 9c34819ff4
No known key found for this signature in database
4 changed files with 217 additions and 68 deletions

View File

@ -21,6 +21,7 @@ using osu.Game.Screens.SelectV2;
using osu.Game.Tests.Beatmaps; using osu.Game.Tests.Beatmaps;
using osu.Game.Tests.Resources; using osu.Game.Tests.Resources;
using osuTK.Graphics; using osuTK.Graphics;
using osuTK.Input;
using BeatmapCarousel = osu.Game.Screens.SelectV2.BeatmapCarousel; using BeatmapCarousel = osu.Game.Screens.SelectV2.BeatmapCarousel;
namespace osu.Game.Tests.Visual.SongSelect namespace osu.Game.Tests.Visual.SongSelect
@ -53,7 +54,7 @@ namespace osu.Game.Tests.Visual.SongSelect
} }
[SetUpSteps] [SetUpSteps]
public void SetUpSteps() public virtual void SetUpSteps()
{ {
RemoveAllBeatmaps(); RemoveAllBeatmaps();
@ -135,6 +136,53 @@ namespace osu.Game.Tests.Visual.SongSelect
protected void WaitForSorting() => AddUntilStep("sorting finished", () => Carousel.IsFiltering, () => Is.False); protected void WaitForSorting() => AddUntilStep("sorting finished", () => Carousel.IsFiltering, () => Is.False);
protected void WaitForScrolling() => AddUntilStep("scroll finished", () => Scroll.Current, () => Is.EqualTo(Scroll.Target)); protected void WaitForScrolling() => AddUntilStep("scroll finished", () => Scroll.Current, () => Is.EqualTo(Scroll.Target));
protected void SelectNextPanel() => AddStep("select next panel", () => InputManager.Key(Key.Down));
protected void SelectPrevPanel() => AddStep("select prev panel", () => InputManager.Key(Key.Up));
protected void SelectNextGroup() => AddStep("select next group", () => InputManager.Key(Key.Right));
protected void SelectPrevGroup() => AddStep("select prev group", () => InputManager.Key(Key.Left));
protected void Select() => AddStep("select", () => InputManager.Key(Key.Enter));
protected void CheckNoSelection() => AddAssert("has no selection", () => Carousel.CurrentSelection, () => Is.Null);
protected void CheckHasSelection() => AddAssert("has selection", () => Carousel.CurrentSelection, () => Is.Not.Null);
protected void WaitForGroupSelection(int group, int panel)
{
AddUntilStep($"selected is group{group} panel{panel}", () =>
{
var groupingFilter = Carousel.Filters.OfType<BeatmapCarouselFilterGrouping>().Single();
GroupDefinition g = groupingFilter.GroupItems.Keys.ElementAt(group);
CarouselItem item = groupingFilter.GroupItems[g].ElementAt(panel);
return ReferenceEquals(Carousel.CurrentSelection, item.Model);
});
}
protected void WaitForSelection(int set, int? diff = null)
{
AddUntilStep($"selected is set{set}{(diff.HasValue ? $" diff{diff.Value}" : "")}", () =>
{
if (diff != null)
return ReferenceEquals(Carousel.CurrentSelection, BeatmapSets[set].Beatmaps[diff.Value]);
return BeatmapSets[set].Beatmaps.Contains(Carousel.CurrentSelection);
});
}
protected void ClickVisiblePanel<T>(int index)
where T : Drawable
{
AddStep($"click panel at index {index}", () =>
{
Carousel.ChildrenOfType<T>()
.Where(p => ((ICarouselPanel)p).Item?.IsVisible == true)
.Reverse()
.ElementAt(index)
.TriggerClick();
});
}
/// <summary> /// <summary>
/// Add requested beatmap sets count to list. /// Add requested beatmap sets count to list.
/// </summary> /// </summary>

View File

@ -0,0 +1,121 @@
// 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.
using System.Linq;
using NUnit.Framework;
using osu.Framework.Testing;
using osu.Game.Beatmaps;
using osu.Game.Screens.Select;
using osu.Game.Screens.Select.Filter;
using osu.Game.Screens.SelectV2;
namespace osu.Game.Tests.Visual.SongSelect
{
[TestFixture]
public partial class TestSceneBeatmapCarouselV2GroupSelection : BeatmapCarouselV2TestScene
{
public override void SetUpSteps()
{
RemoveAllBeatmaps();
CreateCarousel();
SortBy(new FilterCriteria { Sort = SortMode.Difficulty });
}
[Test]
public void TestOpenCloseGroupWithNoSelection()
{
AddBeatmaps(10, 5);
WaitForDrawablePanels();
AddAssert("no beatmaps visible", () => Carousel.ChildrenOfType<BeatmapPanel>().Count(p => p.Alpha > 0), () => Is.Zero);
CheckNoSelection();
ClickVisiblePanel<GroupPanel>(0);
AddUntilStep("some beatmaps visible", () => Carousel.ChildrenOfType<BeatmapPanel>().Count(p => p.Alpha > 0), () => Is.GreaterThan(0));
CheckNoSelection();
ClickVisiblePanel<GroupPanel>(0);
AddUntilStep("no beatmaps visible", () => Carousel.ChildrenOfType<BeatmapPanel>().Count(p => p.Alpha > 0), () => Is.Zero);
CheckNoSelection();
}
[Test]
public void TestCarouselRemembersSelection()
{
AddBeatmaps(10);
WaitForDrawablePanels();
SelectNextGroup();
object? selection = null;
AddStep("store drawable selection", () => selection = getSelectedPanel()?.Item?.Model);
CheckHasSelection();
AddAssert("drawable selection non-null", () => selection, () => Is.Not.Null);
AddAssert("drawable selection matches carousel selection", () => selection, () => Is.EqualTo(Carousel.CurrentSelection));
RemoveAllBeatmaps();
AddUntilStep("no drawable selection", getSelectedPanel, () => Is.Null);
AddBeatmaps(10);
WaitForDrawablePanels();
CheckHasSelection();
AddAssert("no drawable selection", getSelectedPanel, () => Is.Null);
AddStep("add previous selection", () => BeatmapSets.Add(((BeatmapInfo)selection!).BeatmapSet!));
AddAssert("selection matches original carousel selection", () => selection, () => Is.EqualTo(Carousel.CurrentSelection));
AddUntilStep("drawable selection restored", () => getSelectedPanel()?.Item?.Model, () => Is.EqualTo(selection));
AddAssert("carousel item is visible", () => getSelectedPanel()?.Item?.IsVisible, () => Is.True);
ClickVisiblePanel<GroupPanel>(0);
AddUntilStep("carousel item not visible", getSelectedPanel, () => Is.Null);
ClickVisiblePanel<GroupPanel>(0);
AddUntilStep("carousel item is visible", () => getSelectedPanel()?.Item?.IsVisible, () => Is.True);
BeatmapPanel? getSelectedPanel() => Carousel.ChildrenOfType<BeatmapPanel>().SingleOrDefault(p => p.Selected.Value);
}
[Test]
public void TestKeyboardSelection()
{
AddBeatmaps(10, 3);
WaitForDrawablePanels();
SelectNextPanel();
SelectNextPanel();
SelectNextPanel();
SelectNextPanel();
CheckNoSelection();
// open first group
Select();
CheckNoSelection();
AddUntilStep("some beatmaps visible", () => Carousel.ChildrenOfType<BeatmapPanel>().Count(p => p.Alpha > 0), () => Is.GreaterThan(0));
SelectNextPanel();
Select();
WaitForGroupSelection(0, 0);
SelectNextGroup();
WaitForGroupSelection(0, 1);
SelectNextGroup();
WaitForGroupSelection(0, 2);
SelectPrevGroup();
WaitForGroupSelection(0, 1);
SelectPrevGroup();
WaitForGroupSelection(0, 0);
SelectPrevGroup();
WaitForGroupSelection(2, 9);
}
}
}

View File

@ -22,10 +22,10 @@ namespace osu.Game.Tests.Visual.SongSelect
{ {
AddBeatmaps(10); AddBeatmaps(10);
WaitForDrawablePanels(); WaitForDrawablePanels();
checkNoSelection(); CheckNoSelection();
select(); Select();
checkNoSelection(); CheckNoSelection();
AddStep("press down arrow", () => InputManager.PressKey(Key.Down)); AddStep("press down arrow", () => InputManager.PressKey(Key.Down));
checkSelectionIterating(false); checkSelectionIterating(false);
@ -39,8 +39,8 @@ namespace osu.Game.Tests.Visual.SongSelect
AddStep("release up arrow", () => InputManager.ReleaseKey(Key.Up)); AddStep("release up arrow", () => InputManager.ReleaseKey(Key.Up));
checkSelectionIterating(false); checkSelectionIterating(false);
select(); Select();
checkHasSelection(); CheckHasSelection();
} }
/// <summary> /// <summary>
@ -52,7 +52,7 @@ namespace osu.Game.Tests.Visual.SongSelect
{ {
AddBeatmaps(10); AddBeatmaps(10);
WaitForDrawablePanels(); WaitForDrawablePanels();
checkNoSelection(); CheckNoSelection();
AddStep("press right arrow", () => InputManager.PressKey(Key.Right)); AddStep("press right arrow", () => InputManager.PressKey(Key.Right));
checkSelectionIterating(true); checkSelectionIterating(true);
@ -73,13 +73,13 @@ namespace osu.Game.Tests.Visual.SongSelect
AddBeatmaps(10); AddBeatmaps(10);
WaitForDrawablePanels(); WaitForDrawablePanels();
selectNextGroup(); SelectNextGroup();
object? selection = null; object? selection = null;
AddStep("store drawable selection", () => selection = getSelectedPanel()?.Item?.Model); AddStep("store drawable selection", () => selection = getSelectedPanel()?.Item?.Model);
checkHasSelection(); CheckHasSelection();
AddAssert("drawable selection non-null", () => selection, () => Is.Not.Null); AddAssert("drawable selection non-null", () => selection, () => Is.Not.Null);
AddAssert("drawable selection matches carousel selection", () => selection, () => Is.EqualTo(Carousel.CurrentSelection)); AddAssert("drawable selection matches carousel selection", () => selection, () => Is.EqualTo(Carousel.CurrentSelection));
@ -89,13 +89,14 @@ namespace osu.Game.Tests.Visual.SongSelect
AddBeatmaps(10); AddBeatmaps(10);
WaitForDrawablePanels(); WaitForDrawablePanels();
checkHasSelection(); CheckHasSelection();
AddAssert("no drawable selection", getSelectedPanel, () => Is.Null); AddAssert("no drawable selection", getSelectedPanel, () => Is.Null);
AddStep("add previous selection", () => BeatmapSets.Add(((BeatmapInfo)selection!).BeatmapSet!)); AddStep("add previous selection", () => BeatmapSets.Add(((BeatmapInfo)selection!).BeatmapSet!));
AddAssert("selection matches original carousel selection", () => selection, () => Is.EqualTo(Carousel.CurrentSelection));
AddUntilStep("drawable selection restored", () => getSelectedPanel()?.Item?.Model, () => Is.EqualTo(selection)); AddUntilStep("drawable selection restored", () => getSelectedPanel()?.Item?.Model, () => Is.EqualTo(selection));
AddAssert("drawable selection matches carousel selection", () => selection, () => Is.EqualTo(Carousel.CurrentSelection)); AddAssert("carousel item is visible", () => getSelectedPanel()?.Item?.IsVisible, () => Is.True);
BeatmapPanel? getSelectedPanel() => Carousel.ChildrenOfType<BeatmapPanel>().SingleOrDefault(p => p.Selected.Value); BeatmapPanel? getSelectedPanel() => Carousel.ChildrenOfType<BeatmapPanel>().SingleOrDefault(p => p.Selected.Value);
} }
@ -108,10 +109,10 @@ namespace osu.Game.Tests.Visual.SongSelect
AddBeatmaps(total_set_count); AddBeatmaps(total_set_count);
WaitForDrawablePanels(); WaitForDrawablePanels();
selectNextGroup(); SelectNextGroup();
waitForSelection(0, 0); WaitForSelection(0, 0);
selectPrevGroup(); SelectPrevGroup();
waitForSelection(total_set_count - 1, 0); WaitForSelection(total_set_count - 1, 0);
} }
[Test] [Test]
@ -122,10 +123,10 @@ namespace osu.Game.Tests.Visual.SongSelect
AddBeatmaps(total_set_count); AddBeatmaps(total_set_count);
WaitForDrawablePanels(); WaitForDrawablePanels();
selectPrevGroup(); SelectPrevGroup();
waitForSelection(total_set_count - 1, 0); WaitForSelection(total_set_count - 1, 0);
selectNextGroup(); SelectNextGroup();
waitForSelection(0, 0); WaitForSelection(0, 0);
} }
[Test] [Test]
@ -134,71 +135,50 @@ namespace osu.Game.Tests.Visual.SongSelect
AddBeatmaps(10, 3); AddBeatmaps(10, 3);
WaitForDrawablePanels(); WaitForDrawablePanels();
selectNextPanel(); SelectNextPanel();
selectNextPanel(); SelectNextPanel();
selectNextPanel(); SelectNextPanel();
selectNextPanel(); SelectNextPanel();
checkNoSelection(); CheckNoSelection();
select(); Select();
waitForSelection(3, 0); WaitForSelection(3, 0);
selectNextPanel(); SelectNextPanel();
waitForSelection(3, 0); WaitForSelection(3, 0);
select(); Select();
waitForSelection(3, 1); WaitForSelection(3, 1);
selectNextPanel(); SelectNextPanel();
waitForSelection(3, 1); WaitForSelection(3, 1);
select(); Select();
waitForSelection(3, 2); WaitForSelection(3, 2);
selectNextPanel(); SelectNextPanel();
waitForSelection(3, 2); WaitForSelection(3, 2);
select(); Select();
waitForSelection(4, 0); WaitForSelection(4, 0);
} }
[Test] [Test]
public void TestEmptyTraversal() public void TestEmptyTraversal()
{ {
selectNextPanel(); SelectNextPanel();
checkNoSelection(); CheckNoSelection();
selectNextGroup(); SelectNextGroup();
checkNoSelection(); CheckNoSelection();
selectPrevPanel(); SelectPrevPanel();
checkNoSelection(); CheckNoSelection();
selectPrevGroup(); SelectPrevGroup();
checkNoSelection(); CheckNoSelection();
} }
private void waitForSelection(int set, int? diff = null)
{
AddUntilStep($"selected is set{set}{(diff.HasValue ? $" diff{diff.Value}" : "")}", () =>
{
if (diff != null)
return ReferenceEquals(Carousel.CurrentSelection, BeatmapSets[set].Beatmaps[diff.Value]);
return BeatmapSets[set].Beatmaps.Contains(Carousel.CurrentSelection);
});
}
private void selectNextPanel() => AddStep("select next panel", () => InputManager.Key(Key.Down));
private void selectPrevPanel() => AddStep("select prev panel", () => InputManager.Key(Key.Up));
private void selectNextGroup() => AddStep("select next group", () => InputManager.Key(Key.Right));
private void selectPrevGroup() => AddStep("select prev group", () => InputManager.Key(Key.Left));
private void select() => AddStep("select", () => InputManager.Key(Key.Enter));
private void checkNoSelection() => AddAssert("has no selection", () => Carousel.CurrentSelection, () => Is.Null);
private void checkHasSelection() => AddAssert("has selection", () => Carousel.CurrentSelection, () => Is.Not.Null);
private void checkSelectionIterating(bool isIterating) private void checkSelectionIterating(bool isIterating)
{ {
object? selection = null; object? selection = null;

View File

@ -131,7 +131,7 @@ namespace osu.Game.Screens.SelectV2
/// ///
/// A filter may add, mutate or remove items. /// A filter may add, mutate or remove items.
/// </remarks> /// </remarks>
protected IEnumerable<ICarouselFilter> Filters { get; init; } = Enumerable.Empty<ICarouselFilter>(); public IEnumerable<ICarouselFilter> Filters { get; init; } = Enumerable.Empty<ICarouselFilter>();
/// <summary> /// <summary>
/// All items which are to be considered for display in this carousel. /// All items which are to be considered for display in this carousel.