From 5111bad86ce647bc34c2873b7d9407a73323a477 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 12 Aug 2022 14:15:12 +0900 Subject: [PATCH 1/3] Refactor `TestScenePlaylistOverlay` to use realm for testing Removes the dual-purpose flow which existed only for testing. --- .../UserInterface/TestScenePlaylistOverlay.cs | 48 ++++++++++++------- osu.Game/Overlays/Music/PlaylistOverlay.cs | 6 +-- 2 files changed, 33 insertions(+), 21 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestScenePlaylistOverlay.cs b/osu.Game.Tests/Visual/UserInterface/TestScenePlaylistOverlay.cs index ee5ef2f364..652afa80be 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestScenePlaylistOverlay.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestScenePlaylistOverlay.cs @@ -1,18 +1,20 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - +using System.Collections.Generic; using System.Linq; using NUnit.Framework; -using osu.Framework.Bindables; +using osu.Framework.Allocation; +using osu.Framework.Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Platform; using osu.Framework.Testing; using osu.Game.Beatmaps; +using osu.Game.Collections; using osu.Game.Database; -using osu.Game.Graphics.Containers; using osu.Game.Overlays.Music; +using osu.Game.Rulesets; using osu.Game.Tests.Resources; using osuTK; using osuTK.Input; @@ -21,13 +23,27 @@ namespace osu.Game.Tests.Visual.UserInterface { public class TestScenePlaylistOverlay : OsuManualInputManagerTestScene { - private readonly BindableList> beatmapSets = new BindableList>(); + protected override bool UseFreshStoragePerRun => true; - private PlaylistOverlay playlistOverlay; + private PlaylistOverlay playlistOverlay = null!; - private Live first; + private Live first = null!; - private const int item_count = 100; + private BeatmapManager beatmapManager = null!; + + private const int item_count = 20; + + private List beatmapSets => beatmapManager.GetAllUsableBeatmapSets(); + + [BackgroundDependencyLoader] + private void load(GameHost host) + { + Dependencies.Cache(new RealmRulesetStore(Realm)); + Dependencies.Cache(beatmapManager = new BeatmapManager(LocalStorage, Realm, null, Audio, Resources, host, Beatmap.Default)); + Dependencies.Cache(Realm); + + beatmapManager.Import(TestResources.GetQuickTestBeatmapForImport()).WaitSafely(); + } [SetUp] public void Setup() => Schedule(() => @@ -46,16 +62,12 @@ public void Setup() => Schedule(() => } }; - beatmapSets.Clear(); - for (int i = 0; i < item_count; i++) { - beatmapSets.Add(TestResources.CreateTestBeatmapSetInfo().ToLiveUnmanaged()); + beatmapManager.Import(TestResources.CreateTestBeatmapSetInfo()); } - first = beatmapSets.First(); - - playlistOverlay.BeatmapSets.BindTo(beatmapSets); + first = beatmapSets.First().ToLive(Realm); }); [Test] @@ -70,9 +82,13 @@ public void TestRearrangeItems() AddUntilStep("wait for animations to complete", () => !playlistOverlay.Transforms.Any()); + PlaylistItem firstItem = null!; + AddStep("hold 1st item handle", () => { - var handle = this.ChildrenOfType>.PlaylistItemHandle>().First(); + firstItem = this.ChildrenOfType().First(); + var handle = firstItem.ChildrenOfType().First(); + InputManager.MoveMouseTo(handle.ScreenSpaceDrawQuad.Centre); InputManager.PressButton(MouseButton.Left); }); @@ -83,7 +99,7 @@ public void TestRearrangeItems() InputManager.MoveMouseTo(item.ScreenSpaceDrawQuad.BottomLeft); }); - AddAssert("song 1 is 5th", () => beatmapSets[4].Equals(first)); + AddAssert("first is moved", () => playlistOverlay.ChildrenOfType().Single().Items.ElementAt(4).Value.Equals(firstItem.Model.Value)); AddStep("release handle", () => InputManager.ReleaseButton(MouseButton.Left)); } diff --git a/osu.Game/Overlays/Music/PlaylistOverlay.cs b/osu.Game/Overlays/Music/PlaylistOverlay.cs index e33fc8064f..9fe2fd5279 100644 --- a/osu.Game/Overlays/Music/PlaylistOverlay.cs +++ b/osu.Game/Overlays/Music/PlaylistOverlay.cs @@ -26,8 +26,6 @@ public class PlaylistOverlay : VisibilityContainer private const float transition_duration = 600; private const float playlist_height = 510; - public IBindableList> BeatmapSets => beatmapSets; - private readonly BindableList> beatmapSets = new BindableList>(); private readonly Bindable beatmap = new Bindable(); @@ -104,9 +102,7 @@ protected override void LoadComplete() { base.LoadComplete(); - // tests might bind externally, in which case we don't want to involve realm. - if (beatmapSets.Count == 0) - beatmapSubscription = realm.RegisterForNotifications(r => r.All().Where(s => !s.DeletePending), beatmapsChanged); + beatmapSubscription = realm.RegisterForNotifications(r => r.All().Where(s => !s.DeletePending), beatmapsChanged); list.Items.BindTo(beatmapSets); beatmap.BindValueChanged(working => list.SelectedSet.Value = working.NewValue.BeatmapSetInfo.ToLive(realm), true); From a90967715cdaa1b8b9830f37ef3c8681999cf64b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 12 Aug 2022 14:44:19 +0900 Subject: [PATCH 2/3] Add test coverage of new imports not correctly being filtered by collection filter --- osu.Game.Tests/Resources/TestResources.cs | 5 +- .../UserInterface/TestScenePlaylistOverlay.cs | 66 ++++++++++++++++++- 2 files changed, 67 insertions(+), 4 deletions(-) diff --git a/osu.Game.Tests/Resources/TestResources.cs b/osu.Game.Tests/Resources/TestResources.cs index ee29cc8644..6bce03869d 100644 --- a/osu.Game.Tests/Resources/TestResources.cs +++ b/osu.Game.Tests/Resources/TestResources.cs @@ -128,6 +128,8 @@ IEnumerable getBeatmaps(int count) var rulesetInfo = getRuleset(); + string hash = Guid.NewGuid().ToString().ComputeMD5Hash(); + yield return new BeatmapInfo { OnlineID = beatmapId, @@ -136,7 +138,8 @@ IEnumerable getBeatmaps(int count) Length = length, BeatmapSet = beatmapSet, BPM = bpm, - Hash = Guid.NewGuid().ToString().ComputeMD5Hash(), + Hash = hash, + MD5Hash = hash, Ruleset = rulesetInfo, Metadata = metadata.DeepClone(), Difficulty = new BeatmapDifficulty diff --git a/osu.Game.Tests/Visual/UserInterface/TestScenePlaylistOverlay.cs b/osu.Game.Tests/Visual/UserInterface/TestScenePlaylistOverlay.cs index 652afa80be..e67eebf721 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestScenePlaylistOverlay.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestScenePlaylistOverlay.cs @@ -27,8 +27,6 @@ public class TestScenePlaylistOverlay : OsuManualInputManagerTestScene private PlaylistOverlay playlistOverlay = null!; - private Live first = null!; - private BeatmapManager beatmapManager = null!; private const int item_count = 20; @@ -67,7 +65,7 @@ public void Setup() => Schedule(() => beatmapManager.Import(TestResources.CreateTestBeatmapSetInfo()); } - first = beatmapSets.First().ToLive(Realm); + beatmapSets.First().ToLive(Realm); }); [Test] @@ -117,6 +115,68 @@ public void TestFiltering() () => playlistOverlay.ChildrenOfType() .Where(item => item.MatchingFilter) .All(item => item.FilterTerms.Any(term => term.ToString().Contains("10")))); + + AddStep("Import new non-matching beatmap", () => + { + var testBeatmapSetInfo = TestResources.CreateTestBeatmapSetInfo(1); + testBeatmapSetInfo.Beatmaps.Single().Metadata.Title = "no guid"; + beatmapManager.Import(testBeatmapSetInfo); + }); + + AddStep("Force realm refresh", () => Realm.Run(r => r.Refresh())); + + AddAssert("results filtered correctly", + () => playlistOverlay.ChildrenOfType() + .Where(item => item.MatchingFilter) + .All(item => item.FilterTerms.Any(term => term.ToString().Contains("10")))); + } + + [Test] + public void TestCollectionFiltering() + { + NowPlayingCollectionDropdown collectionDropdown() => playlistOverlay.ChildrenOfType().Single(); + + AddStep("Add collection", () => + { + Dependencies.Get().Write(r => + { + r.RemoveAll(); + r.Add(new BeatmapCollection("wang")); + }); + }); + + AddUntilStep("wait for dropdown to have new collection", () => collectionDropdown().Items.Count() == 2); + + AddStep("Filter to collection", () => + { + collectionDropdown().Current.Value = collectionDropdown().Items.Last(); + }); + + AddUntilStep("No items present", () => !playlistOverlay.ChildrenOfType().Any(i => i.MatchingFilter)); + + AddStep("Import new non-matching beatmap", () => + { + beatmapManager.Import(TestResources.CreateTestBeatmapSetInfo(1)); + }); + + AddStep("Force realm refresh", () => Realm.Run(r => r.Refresh())); + + AddUntilStep("No items matching", () => !playlistOverlay.ChildrenOfType().Any(i => i.MatchingFilter)); + + BeatmapSetInfo collectionAddedBeatmapSet = null!; + + AddStep("Import new matching beatmap", () => + { + collectionAddedBeatmapSet = TestResources.CreateTestBeatmapSetInfo(1); + + beatmapManager.Import(collectionAddedBeatmapSet); + Realm.Write(r => r.All().First().BeatmapMD5Hashes.Add(collectionAddedBeatmapSet.Beatmaps.First().MD5Hash)); + }); + + AddStep("Force realm refresh", () => Realm.Run(r => r.Refresh())); + + AddUntilStep("Only matching item", + () => playlistOverlay.ChildrenOfType().Where(i => i.MatchingFilter).Select(i => i.Model.ID), () => Is.EquivalentTo(new[] { collectionAddedBeatmapSet.ID })); } } } From b76e5757e17100c171df813235dc43d104e52c04 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 12 Aug 2022 14:44:05 +0900 Subject: [PATCH 3/3] Fix `InSelectedCollection` not being applied to newly imported beatmaps --- osu.Game/Overlays/Music/Playlist.cs | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/osu.Game/Overlays/Music/Playlist.cs b/osu.Game/Overlays/Music/Playlist.cs index 2bb0ff1085..15fc54a337 100644 --- a/osu.Game/Overlays/Music/Playlist.cs +++ b/osu.Game/Overlays/Music/Playlist.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using System; using System.Linq; using osu.Framework.Bindables; @@ -17,10 +15,12 @@ namespace osu.Game.Overlays.Music { public class Playlist : OsuRearrangeableListContainer> { - public Action> RequestSelection; + public Action>? RequestSelection; public readonly Bindable> SelectedSet = new Bindable>(); + private FilterCriteria currentCriteria = new FilterCriteria(); + public new MarginPadding Padding { get => base.Padding; @@ -31,26 +31,22 @@ public void Filter(FilterCriteria criteria) { var items = (SearchContainer>>)ListContainer; - string[] currentCollectionHashes = criteria.Collection?.PerformRead(c => c.BeatmapMD5Hashes.ToArray()); + string[]? currentCollectionHashes = criteria.Collection?.PerformRead(c => c.BeatmapMD5Hashes.ToArray()); foreach (var item in items.OfType()) { - if (currentCollectionHashes == null) - item.InSelectedCollection = true; - else - { - item.InSelectedCollection = item.Model.Value.Beatmaps.Select(b => b.MD5Hash) - .Any(currentCollectionHashes.Contains); - } + item.InSelectedCollection = currentCollectionHashes == null || item.Model.Value.Beatmaps.Select(b => b.MD5Hash).Any(currentCollectionHashes.Contains); } items.SearchTerm = criteria.SearchText; + currentCriteria = criteria; } - public Live FirstVisibleSet => Items.FirstOrDefault(i => ((PlaylistItem)ItemMap[i]).MatchingFilter); + public Live? FirstVisibleSet => Items.FirstOrDefault(i => ((PlaylistItem)ItemMap[i]).MatchingFilter); protected override OsuRearrangeableListItem> CreateOsuDrawable(Live item) => new PlaylistItem(item) { + InSelectedCollection = currentCriteria.Collection?.PerformRead(c => item.Value.Beatmaps.Select(b => b.MD5Hash).Any(c.BeatmapMD5Hashes.Contains)) != false, SelectedSet = { BindTarget = SelectedSet }, RequestSelection = set => RequestSelection?.Invoke(set) };