diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneSliderSnaking.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneSliderSnaking.cs index 1d500dcc14..744291ae09 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneSliderSnaking.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneSliderSnaking.cs @@ -37,11 +37,13 @@ namespace osu.Game.Rulesets.Osu.Tests private readonly BindableBool snakingIn = new BindableBool(); private readonly BindableBool snakingOut = new BindableBool(); + private IBeatmap beatmap; + private const double duration_of_span = 3605; private const double fade_in_modifier = -1200; protected override WorkingBeatmap CreateWorkingBeatmap(IBeatmap beatmap, Storyboard storyboard = null) - => new ClockBackedTestWorkingBeatmap(beatmap, storyboard, new FramedClock(new ManualClock { Rate = 1 }), audioManager); + => new ClockBackedTestWorkingBeatmap(this.beatmap = beatmap, storyboard, new FramedClock(new ManualClock { Rate = 1 }), audioManager); [BackgroundDependencyLoader] private void load(RulesetConfigCache configCache) @@ -51,8 +53,16 @@ namespace osu.Game.Rulesets.Osu.Tests config.BindWith(OsuRulesetSetting.SnakingOutSliders, snakingOut); } + private Slider slider; private DrawableSlider drawableSlider; + [SetUp] + public void Setup() => Schedule(() => + { + slider = null; + drawableSlider = null; + }); + [SetUpSteps] public override void SetUpSteps() { @@ -67,21 +77,19 @@ namespace osu.Game.Rulesets.Osu.Tests base.SetUpSteps(); AddUntilStep("wait for track to start running", () => Beatmap.Value.Track.IsRunning); - double startTime = hitObjects[sliderIndex].StartTime; - addSeekStep(startTime); - retrieveDrawableSlider((Slider)hitObjects[sliderIndex]); + retrieveSlider(sliderIndex); setSnaking(true); - ensureSnakingIn(startTime + fade_in_modifier); + addEnsureSnakingInSteps(() => slider.StartTime + fade_in_modifier); for (int i = 0; i < sliderIndex; i++) { // non-final repeats should not snake out - ensureNoSnakingOut(startTime, i); + addEnsureNoSnakingOutStep(() => slider.StartTime, i); } // final repeat should snake out - ensureSnakingOut(startTime, sliderIndex); + addEnsureSnakingOutSteps(() => slider.StartTime, sliderIndex); } [TestCase(0)] @@ -93,17 +101,15 @@ namespace osu.Game.Rulesets.Osu.Tests base.SetUpSteps(); AddUntilStep("wait for track to start running", () => Beatmap.Value.Track.IsRunning); - double startTime = hitObjects[sliderIndex].StartTime; - addSeekStep(startTime); - retrieveDrawableSlider((Slider)hitObjects[sliderIndex]); + retrieveSlider(sliderIndex); setSnaking(false); - ensureNoSnakingIn(startTime + fade_in_modifier); + addEnsureNoSnakingInSteps(() => slider.StartTime + fade_in_modifier); for (int i = 0; i <= sliderIndex; i++) { // no snaking out ever, including final repeat - ensureNoSnakingOut(startTime, i); + addEnsureNoSnakingOutStep(() => slider.StartTime, i); } } @@ -116,7 +122,7 @@ namespace osu.Game.Rulesets.Osu.Tests // repeat might have a chance to update its position depending on where in the frame its hit, // so some leniency is allowed here instead of checking strict equality - checkPositionChange(16600, sliderRepeat, positionAlmostSame); + addCheckPositionChangeSteps(() => 16600, getSliderRepeat, positionAlmostSame); } [Test] @@ -126,38 +132,46 @@ namespace osu.Game.Rulesets.Osu.Tests setSnaking(true); base.SetUpSteps(); - checkPositionChange(16600, sliderRepeat, positionDecreased); + addCheckPositionChangeSteps(() => 16600, getSliderRepeat, positionDecreased); } - private void retrieveDrawableSlider(Slider slider) => AddUntilStep($"retrieve slider @ {slider.StartTime}", () => - (drawableSlider = (DrawableSlider)Player.DrawableRuleset.Playfield.AllHitObjects.SingleOrDefault(d => d.HitObject == slider)) != null); - - private void ensureSnakingIn(double startTime) => checkPositionChange(startTime, sliderEnd, positionIncreased); - private void ensureNoSnakingIn(double startTime) => checkPositionChange(startTime, sliderEnd, positionRemainsSame); - - private void ensureSnakingOut(double startTime, int repeatIndex) + private void retrieveSlider(int index) { - var repeatTime = timeAtRepeat(startTime, repeatIndex); + AddStep("retrieve slider at index", () => slider = (Slider)beatmap.HitObjects[index]); + addSeekStep(() => slider); + retrieveDrawableSlider(() => slider); + } + private void retrieveDrawableSlider(Func getSliderFunc) + { + AddUntilStep("retrieve drawable slider", () => + (drawableSlider = (DrawableSlider)Player.DrawableRuleset.Playfield.AllHitObjects.SingleOrDefault(d => d.HitObject == getSliderFunc())) != null); + } + + private void addEnsureSnakingInSteps(Func startTime) => addCheckPositionChangeSteps(startTime, getSliderEnd, positionIncreased); + private void addEnsureNoSnakingInSteps(Func startTime) => addCheckPositionChangeSteps(startTime, getSliderEnd, positionRemainsSame); + + private void addEnsureSnakingOutSteps(Func startTime, int repeatIndex) + { if (repeatIndex % 2 == 0) - checkPositionChange(repeatTime, sliderStart, positionIncreased); + addCheckPositionChangeSteps(timeAtRepeat(startTime, repeatIndex), getSliderStart, positionIncreased); else - checkPositionChange(repeatTime, sliderEnd, positionDecreased); + addCheckPositionChangeSteps(timeAtRepeat(startTime, repeatIndex), getSliderEnd, positionDecreased); } - private void ensureNoSnakingOut(double startTime, int repeatIndex) => - checkPositionChange(timeAtRepeat(startTime, repeatIndex), positionAtRepeat(repeatIndex), positionRemainsSame); + private void addEnsureNoSnakingOutStep(Func startTime, int repeatIndex) + => addCheckPositionChangeSteps(timeAtRepeat(startTime, repeatIndex), positionAtRepeat(repeatIndex), positionRemainsSame); - private double timeAtRepeat(double startTime, int repeatIndex) => startTime + 100 + duration_of_span * repeatIndex; - private Func positionAtRepeat(int repeatIndex) => repeatIndex % 2 == 0 ? (Func)sliderStart : sliderEnd; + private Func timeAtRepeat(Func startTime, int repeatIndex) => () => startTime() + 100 + duration_of_span * repeatIndex; + private Func positionAtRepeat(int repeatIndex) => repeatIndex % 2 == 0 ? (Func)getSliderStart : getSliderEnd; - private List sliderCurve => ((PlaySliderBody)drawableSlider.Body.Drawable).CurrentCurve; - private Vector2 sliderStart() => sliderCurve.First(); - private Vector2 sliderEnd() => sliderCurve.Last(); + private List getSliderCurve() => ((PlaySliderBody)drawableSlider.Body.Drawable).CurrentCurve; + private Vector2 getSliderStart() => getSliderCurve().First(); + private Vector2 getSliderEnd() => getSliderCurve().Last(); - private Vector2 sliderRepeat() + private Vector2 getSliderRepeat() { - var drawable = Player.DrawableRuleset.Playfield.AllHitObjects.SingleOrDefault(d => d.HitObject == hitObjects[1]); + var drawable = Player.DrawableRuleset.Playfield.AllHitObjects.SingleOrDefault(d => d.HitObject == beatmap.HitObjects[1]); var repeat = drawable.ChildrenOfType>().First().Children.First(); return repeat.Position; } @@ -167,7 +181,7 @@ namespace osu.Game.Rulesets.Osu.Tests private bool positionDecreased(Vector2 previous, Vector2 current) => current.X < previous.X && current.Y < previous.Y; private bool positionAlmostSame(Vector2 previous, Vector2 current) => Precision.AlmostEquals(previous, current, 1); - private void checkPositionChange(double startTime, Func positionToCheck, Func positionAssertion) + private void addCheckPositionChangeSteps(Func startTime, Func positionToCheck, Func positionAssertion) { Vector2 previousPosition = Vector2.Zero; @@ -176,7 +190,7 @@ namespace osu.Game.Rulesets.Osu.Tests addSeekStep(startTime); AddStep($"save {positionDescription} position", () => previousPosition = positionToCheck.Invoke()); - addSeekStep(startTime + 100); + addSeekStep(() => startTime() + 100); AddAssert($"{positionDescription} {assertionDescription}", () => { var currentPosition = positionToCheck.Invoke(); @@ -193,19 +207,21 @@ namespace osu.Game.Rulesets.Osu.Tests }); } - private void addSeekStep(double time) + private void addSeekStep(Func slider) { - AddStep($"seek to {time}", () => Player.GameplayClockContainer.Seek(time)); - - AddUntilStep("wait for seek to finish", () => Precision.AlmostEquals(time, Player.DrawableRuleset.FrameStableClock.CurrentTime, 100)); + AddStep("seek to slider", () => Player.GameplayClockContainer.Seek(slider().StartTime)); + AddUntilStep("wait for seek to finish", () => Precision.AlmostEquals(slider().StartTime, Player.DrawableRuleset.FrameStableClock.CurrentTime, 100)); } - protected override IBeatmap CreateBeatmap(RulesetInfo ruleset) => new Beatmap + private void addSeekStep(Func time) { - HitObjects = hitObjects - }; + AddStep("seek to time", () => Player.GameplayClockContainer.Seek(time())); + AddUntilStep("wait for seek to finish", () => Precision.AlmostEquals(time(), Player.DrawableRuleset.FrameStableClock.CurrentTime, 100)); + } - private readonly List hitObjects = new List + protected override IBeatmap CreateBeatmap(RulesetInfo ruleset) => new Beatmap { HitObjects = createHitObjects() }; + + private List createHitObjects() => new List { new Slider {