mirror of
https://github.com/ppy/osu.git
synced 2026-05-17 01:43:01 +08:00
809298ddeb
## [Rewrite `BackgroundMusicManager` to not run into framework breakage](https://github.com/ppy/osu/commit/622216d8911832c39fa4e126b2810e4e0f46cbf7) The attempted proper fix to this was https://github.com/ppy/osu-framework/pull/6727. Unfortunately when presented with [the framework bump](https://github.com/ppy/osu/pull/37217) with that change, CI says "you're stupid" and fails on some disposal idiocy that of course is undebuggable and irreproducible: The active test run was aborted. Reason: Test host process crashed : Unhandled exception. System.AggregateException: One or more errors occurred. (Object reference not set to an instance of an object.) ---> System.NullReferenceException: Object reference not set to an instance of an object. at osu.Framework.Audio.Sample.SampleChannelBass.Dispose(Boolean disposing) at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state) --- End of stack trace from previous location --- at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state) at System.Threading.Tasks.Task.ExecuteWithThreadLocal(Task& currentTaskSlot, Thread threadPoolThread) --- End of inner exception stack trace --- at osu.Framework.Audio.AudioCollectionManager`1.UpdateChildren() at osu.Framework.Audio.AudioCollectionManager`1.UpdateChildren() at osu.Framework.Audio.AudioCollectionManager`1.UpdateChildren() at osu.Framework.Audio.AudioCollectionManager`1.UpdateChildren() at osu.Framework.Threading.AudioThread.OnExit() at osu.Framework.Threading.GameThread.setExitState(GameThreadState exitState) at osu.Framework.Threading.GameThread.RunSingleFrame() at osu.Framework.Threading.GameThread.<createThread>g__runWork|70_0() at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state) --- End of stack trace from previous location --- at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state) (https://github.com/ppy/osu/actions/runs/24019928154/job/70046733058?pr=37217#step:5:119) I no longer have the energy for any of this shit. @nekodex would appreciate if you could check that I actually haven't broken anything with the bgm here. Seems okay to me in test scenes at least. ## [Apply lowest-effort maybe-fixing changes to a bunch of flaking tests](https://github.com/ppy/osu/commit/7bd3ca4adfcce5b90add11565a13f3fe9177ad5e) None of the failures are reproducible locally, of course. I'm tired of this. If anyone else wants to subject themselves to actually investigating any of these, by all means, godspeed and good luck.
167 lines
7.1 KiB
C#
167 lines
7.1 KiB
C#
// 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.Extensions;
|
|
using osu.Framework.Testing;
|
|
using osu.Game.Beatmaps;
|
|
using osu.Game.Database;
|
|
using osu.Game.Localisation;
|
|
using osu.Game.Online.Chat;
|
|
using osu.Game.Rulesets;
|
|
using osu.Game.Rulesets.Osu;
|
|
using osu.Game.Screens.Edit;
|
|
using osu.Game.Screens.Menu;
|
|
using osu.Game.Screens.Select;
|
|
using osu.Game.Tests.Resources;
|
|
|
|
namespace osu.Game.Tests.Visual.Editing
|
|
{
|
|
public partial class TestSceneOpenEditorTimestamp : OsuGameTestScene
|
|
{
|
|
private Editor? editor => Game.ScreenStack.CurrentScreen as Editor;
|
|
private EditorBeatmap editorBeatmap => editor.ChildrenOfType<EditorBeatmap>().Single();
|
|
private EditorClock editorClock => editor.ChildrenOfType<EditorClock>().Single();
|
|
|
|
[Test]
|
|
public void TestErrorNotifications()
|
|
{
|
|
RulesetInfo rulesetInfo = new OsuRuleset().RulesetInfo;
|
|
|
|
addStepClickLink("00:00:000", waitForSeek: false);
|
|
AddUntilStep("received 'must be in edit'",
|
|
() => Game.Notifications.AllNotifications.Count(x => x.Text == EditorStrings.MustBeInEditorToHandleLinks),
|
|
() => Is.EqualTo(1));
|
|
|
|
AddStep("enter song select", () => Game.ChildrenOfType<ButtonSystem>().Single().OnSolo?.Invoke());
|
|
AddUntilStep("entered song select", () => Game.ScreenStack.CurrentScreen is SoloSongSelect songSelect && songSelect.CarouselItemsPresented);
|
|
|
|
addStepClickLink("00:00:000 (1)", waitForSeek: false);
|
|
AddUntilStep("received 'must be in edit'",
|
|
() => Game.Notifications.AllNotifications.Count(x => x.Text == EditorStrings.MustBeInEditorToHandleLinks),
|
|
() => Is.EqualTo(2));
|
|
|
|
setUpEditor(rulesetInfo);
|
|
AddAssert("ruleset is osu!", () => editorBeatmap.BeatmapInfo.Ruleset.Equals(rulesetInfo));
|
|
|
|
addStepClickLink("00:000", "invalid link", waitForSeek: false);
|
|
AddUntilStep("received 'failed to process'",
|
|
() => Game.Notifications.AllNotifications.Count(x => x.Text == EditorStrings.FailedToParseEditorLink),
|
|
() => Is.EqualTo(1));
|
|
|
|
addStepClickLink("50000:00:000", "too long link", waitForSeek: false);
|
|
AddUntilStep("received 'failed to process'",
|
|
() => Game.Notifications.AllNotifications.Count(x => x.Text == EditorStrings.FailedToParseEditorLink),
|
|
() => Is.EqualTo(2));
|
|
}
|
|
|
|
[Test]
|
|
public void TestHandleCurrentScreenChanges()
|
|
{
|
|
RulesetInfo rulesetInfo = new OsuRuleset().RulesetInfo;
|
|
|
|
setUpEditor(rulesetInfo);
|
|
AddAssert("is osu! ruleset", () => editorBeatmap.BeatmapInfo.Ruleset.Equals(rulesetInfo));
|
|
|
|
addStepClickLink("100:00:000", "long link");
|
|
AddUntilStep("moved to end of track", () => editorClock.CurrentTime, () => Is.EqualTo(editorClock.TrackLength));
|
|
|
|
addStepScreenModeTo(EditorScreenMode.SongSetup);
|
|
addStepClickLink("00:00:000");
|
|
assertOnScreenAt(EditorScreenMode.SongSetup, 0);
|
|
|
|
addStepClickLink("00:05:000 (0|0)");
|
|
assertMovedScreenTo(EditorScreenMode.Compose);
|
|
|
|
addStepScreenModeTo(EditorScreenMode.Design);
|
|
addStepClickLink("00:10:000");
|
|
assertOnScreenAt(EditorScreenMode.Design, 10_000);
|
|
|
|
addStepClickLink("00:15:000 (1)");
|
|
assertMovedScreenTo(EditorScreenMode.Compose);
|
|
|
|
addStepScreenModeTo(EditorScreenMode.Timing);
|
|
addStepClickLink("00:20:000");
|
|
assertOnScreenAt(EditorScreenMode.Timing, 20_000);
|
|
|
|
addStepClickLink("00:25:000 (0,1)");
|
|
assertMovedScreenTo(EditorScreenMode.Compose);
|
|
|
|
addStepScreenModeTo(EditorScreenMode.Verify);
|
|
addStepClickLink("00:30:000");
|
|
assertOnScreenAt(EditorScreenMode.Verify, 30_000);
|
|
|
|
addStepClickLink("00:35:000 (0,1)");
|
|
assertMovedScreenTo(EditorScreenMode.Compose);
|
|
|
|
addStepClickLink("00:00:000");
|
|
assertOnScreenAt(EditorScreenMode.Compose, 0);
|
|
}
|
|
|
|
[Test]
|
|
public void TestUrlDecodingOfArgs()
|
|
{
|
|
setUpEditor(new OsuRuleset().RulesetInfo);
|
|
AddAssert("is osu! ruleset", () => editorBeatmap.BeatmapInfo.Ruleset.Equals(new OsuRuleset().RulesetInfo));
|
|
|
|
AddStep("jump to encoded link", () => Game.HandleLink("osu://edit/00:14:142%20(1)"));
|
|
|
|
AddUntilStep("wait for seek", () => editorClock.SeekingOrStopped.Value);
|
|
|
|
AddAssert("time is correct", () => editorClock.CurrentTime, () => Is.EqualTo(14_142));
|
|
AddAssert("selected object is correct", () => editorBeatmap.SelectedHitObjects.Single().StartTime, () => Is.EqualTo(14_142));
|
|
}
|
|
|
|
private void addStepClickLink(string timestamp, string step = "", bool waitForSeek = true)
|
|
{
|
|
AddStep($"{step} {timestamp}", () =>
|
|
Game.HandleLink(new LinkDetails(LinkAction.OpenEditorTimestamp, timestamp))
|
|
);
|
|
|
|
if (waitForSeek)
|
|
AddUntilStep("wait for seek", () => editorClock.SeekingOrStopped.Value);
|
|
}
|
|
|
|
private void addStepScreenModeTo(EditorScreenMode screenMode) =>
|
|
AddStep("change screen to " + screenMode, () => editor!.Mode.Value = screenMode);
|
|
|
|
private void assertOnScreenAt(EditorScreenMode screen, double time)
|
|
{
|
|
AddAssert($"stayed on {screen} at {time}", () =>
|
|
editor!.Mode.Value == screen
|
|
&& editorClock.CurrentTime == time
|
|
);
|
|
}
|
|
|
|
private void assertMovedScreenTo(EditorScreenMode screen, string text = "moved to") =>
|
|
AddAssert($"{text} {screen}", () => editor!.Mode.Value == screen);
|
|
|
|
private void setUpEditor(RulesetInfo ruleset)
|
|
{
|
|
BeatmapSetInfo? beatmapSet = null;
|
|
|
|
AddStep("Import test beatmap", () =>
|
|
Game.BeatmapManager.Import(TestResources.GetTestBeatmapForImport()).WaitSafely()
|
|
);
|
|
AddUntilStep("Retrieve beatmap", () =>
|
|
{
|
|
beatmapSet = Game.BeatmapManager.QueryBeatmapSet(set => !set.Protected)?.Value.Detach();
|
|
return beatmapSet != null;
|
|
});
|
|
AddStep("Present beatmap", () => Game.PresentBeatmap(beatmapSet));
|
|
AddUntilStep("Wait for song select", () =>
|
|
Game.Beatmap.Value.BeatmapSetInfo.Equals(beatmapSet)
|
|
&& Game.ScreenStack.CurrentScreen is SoloSongSelect songSelect
|
|
&& songSelect.CarouselItemsPresented
|
|
);
|
|
AddStep("Switch ruleset", () => Game.Ruleset.Value = ruleset);
|
|
AddStep("Open editor for ruleset", () =>
|
|
((SoloSongSelect)Game.ScreenStack.CurrentScreen)
|
|
.Edit(beatmapSet!.Beatmaps.Last(beatmap => beatmap.Ruleset.Name == ruleset.Name))
|
|
);
|
|
AddUntilStep("Wait for editor open", () => editor?.ReadyForUse == true);
|
|
}
|
|
}
|
|
}
|