// 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 NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Audio; using osu.Framework.Screens; using osu.Framework.Testing; using osu.Framework.Timing; using osu.Game.Beatmaps; using osu.Game.Rulesets; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Scoring; using osu.Game.Screens.Ranking; using osu.Game.Storyboards; using osuTK; namespace osu.Game.Tests.Visual.Gameplay { public partial class TestSceneCompletionCancellation : OsuPlayerTestScene { [Resolved] private AudioManager audio { get; set; } private int resultsDisplayWaitCount => (int)((Screens.Play.Player.RESULTS_DISPLAY_DELAY / TimePerAction) * 2); protected override bool AllowFail => false; protected override bool AllowBackwardsSeeks => true; [SetUpSteps] public override void SetUpSteps() { base.SetUpSteps(); // Ensure track has actually running before attempting to seek AddUntilStep("wait for track to start running", () => Beatmap.Value.Track.IsRunning); } [Test] public void TestCancelCompletionOnRewind() { complete(); cancel(); checkNoRanking(); } [Test] public void TestReCompleteAfterCancellation() { complete(); cancel(); complete(); AddUntilStep("attempted to push ranking", () => ((FakeRankingPushPlayer)Player).ResultsCreated); } /// /// Tests whether can still pause after cancelling completion by reverting back to true. /// [Test] [FlakyTest] /* * Fail rate around 0.45% * * TearDown : System.TimeoutException : "completion set by processor" timed out * --TearDown * at osu.Framework.Testing.Drawables.Steps.UntilStepButton.<>c__DisplayClass11_0.<.ctor>b__0() * at osu.Framework.Testing.Drawables.Steps.StepButton.PerformStep(Boolean userTriggered) * at osu.Framework.Testing.TestScene.runNextStep(Action onCompletion, Action`1 onError, Func`2 stopCondition) */ public void TestCanPauseAfterCancellation() { complete(); cancel(); AddStep("pause", () => Player.Pause()); AddAssert("paused successfully", () => Player.GameplayClockContainer.IsPaused.Value); checkNoRanking(); } private void complete() { AddStep("seek to completion", () => Beatmap.Value.Track.Seek(5000)); AddUntilStep("completion set by processor", () => Player.ScoreProcessor.HasCompleted.Value); } private void cancel() { AddStep("rewind to cancel", () => Beatmap.Value.Track.Seek(4000)); AddUntilStep("completion cleared by processor", () => !Player.ScoreProcessor.HasCompleted.Value); } private void checkNoRanking() { // wait to ensure there was no attempt of pushing the results screen. AddWaitStep("wait", resultsDisplayWaitCount); AddAssert("no attempt to push ranking", () => !((FakeRankingPushPlayer)Player).ResultsCreated); } protected override WorkingBeatmap CreateWorkingBeatmap(IBeatmap beatmap, Storyboard storyboard = null) => new ClockBackedTestWorkingBeatmap(beatmap, storyboard, new FramedClock(new ManualClock { Rate = 1 }), audio); protected override IBeatmap CreateBeatmap(RulesetInfo ruleset) { var beatmap = new Beatmap(); for (int i = 1; i <= 19; i++) { beatmap.HitObjects.Add(new HitCircle { Position = new Vector2(256, 192), StartTime = i * 250, }); } return beatmap; } protected override TestPlayer CreatePlayer(Ruleset ruleset) => new FakeRankingPushPlayer(); public partial class FakeRankingPushPlayer : TestPlayer { public bool ResultsCreated { get; private set; } protected override ResultsScreen CreateResults(ScoreInfo score) { var results = base.CreateResults(score); ResultsCreated = true; return results; } } } }