diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneCatchModPerfect.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneCatchModPerfect.cs new file mode 100644 index 0000000000..f5bd3b1133 --- /dev/null +++ b/osu.Game.Rulesets.Catch.Tests/TestSceneCatchModPerfect.cs @@ -0,0 +1,54 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using NUnit.Framework; +using osu.Game.Rulesets.Catch.Mods; +using osu.Game.Rulesets.Catch.Objects; +using osu.Game.Rulesets.Objects; +using osu.Game.Rulesets.Objects.Types; +using osu.Game.Tests.Visual; +using osuTK; + +namespace osu.Game.Rulesets.Catch.Tests +{ + public class TestSceneCatchModPerfect : ModPerfectTestScene + { + public TestSceneCatchModPerfect() + : base(new CatchRuleset(), new CatchModPerfect()) + { + } + + [TestCase(false)] + [TestCase(true)] + public void TestBananaShower(bool shouldMiss) => CreateHitObjectTest(new HitObjectTestCase(new BananaShower { StartTime = 1000, EndTime = 3000 }, false), shouldMiss); + + [TestCase(false)] + [TestCase(true)] + public void TestFruit(bool shouldMiss) => CreateHitObjectTest(new HitObjectTestCase(new Fruit { StartTime = 1000 }), shouldMiss); + + [TestCase(false)] + [TestCase(true)] + public void TestTestJuiceStream(bool shouldMiss) + { + var stream = new JuiceStream + { + StartTime = 1000, + Path = new SliderPath(PathType.Linear, new[] + { + Vector2.Zero, + new Vector2(100, 0), + }) + }; + + CreateHitObjectTest(new HitObjectTestCase(stream), shouldMiss); + } + + // We only care about testing misses, hits are tested via JuiceStream + [TestCase(true)] + public void TestDroplet(bool shouldMiss) => CreateHitObjectTest(new HitObjectTestCase(new Droplet { StartTime = 1000 }), shouldMiss); + + // We only care about testing misses, hits are tested via JuiceStream + [TestCase(true)] + public void TestTinyDroplet(bool shouldMiss) => CreateHitObjectTest(new HitObjectTestCase(new TinyDroplet { StartTime = 1000 }), shouldMiss); + } +} diff --git a/osu.Game.Rulesets.Mania.Tests/TestSceneManiaModPerfect.cs b/osu.Game.Rulesets.Mania.Tests/TestSceneManiaModPerfect.cs new file mode 100644 index 0000000000..f49a19e218 --- /dev/null +++ b/osu.Game.Rulesets.Mania.Tests/TestSceneManiaModPerfect.cs @@ -0,0 +1,26 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using NUnit.Framework; +using osu.Game.Rulesets.Mania.Mods; +using osu.Game.Rulesets.Mania.Objects; +using osu.Game.Tests.Visual; + +namespace osu.Game.Rulesets.Mania.Tests +{ + public class TestSceneManiaModPerfect : ModPerfectTestScene + { + public TestSceneManiaModPerfect() + : base(new ManiaRuleset(), new ManiaModPerfect()) + { + } + + [TestCase(false)] + [TestCase(true)] + public void TestNote(bool shouldMiss) => CreateHitObjectTest(new HitObjectTestCase(new Note { StartTime = 1000 }), shouldMiss); + + [TestCase(false)] + [TestCase(true)] + public void TestHoldNote(bool shouldMiss) => CreateHitObjectTest(new HitObjectTestCase(new HoldNote { StartTime = 1000, EndTime = 3000 }), shouldMiss); + } +} diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneOsuModPerfect.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneOsuModPerfect.cs new file mode 100644 index 0000000000..02fd5b5a79 --- /dev/null +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneOsuModPerfect.cs @@ -0,0 +1,52 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using NUnit.Framework; +using osu.Game.Rulesets.Objects; +using osu.Game.Rulesets.Objects.Types; +using osu.Game.Rulesets.Osu.Mods; +using osu.Game.Rulesets.Osu.Objects; +using osu.Game.Tests.Visual; +using osuTK; + +namespace osu.Game.Rulesets.Osu.Tests +{ + public class TestSceneOsuModPerfect : ModPerfectTestScene + { + public TestSceneOsuModPerfect() + : base(new OsuRuleset(), new OsuModPerfect()) + { + } + + [TestCase(false)] + [TestCase(true)] + public void TestHitCircle(bool shouldMiss) => CreateHitObjectTest(new HitObjectTestCase(new HitCircle { StartTime = 1000 }), shouldMiss); + + [TestCase(false)] + [TestCase(true)] + public void TestSlider(bool shouldMiss) + { + var slider = new Slider + { + StartTime = 1000, + Path = new SliderPath(PathType.Linear, new[] { Vector2.Zero, new Vector2(100, 0), }) + }; + + CreateHitObjectTest(new HitObjectTestCase(slider), shouldMiss); + } + + [TestCase(false)] + [TestCase(true)] + public void TestSpinner(bool shouldMiss) + { + var spinner = new Spinner + { + StartTime = 1000, + EndTime = 3000, + Position = new Vector2(256, 192) + }; + + CreateHitObjectTest(new HitObjectTestCase(spinner), shouldMiss); + } + } +} diff --git a/osu.Game.Rulesets.Taiko.Tests/TestSceneTaikoModPerfect.cs b/osu.Game.Rulesets.Taiko.Tests/TestSceneTaikoModPerfect.cs new file mode 100644 index 0000000000..4069ee7983 --- /dev/null +++ b/osu.Game.Rulesets.Taiko.Tests/TestSceneTaikoModPerfect.cs @@ -0,0 +1,30 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using NUnit.Framework; +using osu.Game.Rulesets.Taiko.Mods; +using osu.Game.Rulesets.Taiko.Objects; +using osu.Game.Tests.Visual; + +namespace osu.Game.Rulesets.Taiko.Tests +{ + public class TestSceneTaikoModPerfect : ModPerfectTestScene + { + public TestSceneTaikoModPerfect() + : base(new TaikoRuleset(), new TaikoModPerfect()) + { + } + + [TestCase(false)] + [TestCase(true)] + public void TestHit(bool shouldMiss) => CreateHitObjectTest(new HitObjectTestCase(new CentreHit { StartTime = 1000 }), shouldMiss); + + [TestCase(false)] + [TestCase(true)] + public void TestDrumRoll(bool shouldMiss) => CreateHitObjectTest(new HitObjectTestCase(new DrumRoll { StartTime = 1000, EndTime = 3000 }), shouldMiss); + + [TestCase(false)] + [TestCase(true)] + public void TestSwell(bool shouldMiss) => CreateHitObjectTest(new HitObjectTestCase(new Swell { StartTime = 1000, EndTime = 3000 }), shouldMiss); + } +} diff --git a/osu.Game/Tests/Visual/ModPerfectTestScene.cs b/osu.Game/Tests/Visual/ModPerfectTestScene.cs new file mode 100644 index 0000000000..272b5366a9 --- /dev/null +++ b/osu.Game/Tests/Visual/ModPerfectTestScene.cs @@ -0,0 +1,66 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Extensions.TypeExtensions; +using osu.Game.Beatmaps; +using osu.Game.Rulesets; +using osu.Game.Rulesets.Mods; +using osu.Game.Rulesets.Objects; +using osu.Game.Scoring; + +namespace osu.Game.Tests.Visual +{ + public abstract class ModPerfectTestScene : ModSandboxTestScene + { + private readonly ModPerfect perfectMod; + + protected ModPerfectTestScene(Ruleset ruleset, ModPerfect perfectMod) + : base(ruleset) + { + this.perfectMod = perfectMod; + } + + protected void CreateHitObjectTest(HitObjectTestCase testCaseData, bool shouldMiss) => CreateModTest(new ModTestCaseData(testCaseData.HitObject.GetType().ReadableName(), perfectMod) + { + Beatmap = new Beatmap + { + BeatmapInfo = { Ruleset = Ruleset.Value }, + HitObjects = { testCaseData.HitObject } + }, + Autoplay = !shouldMiss, + PassCondition = () => ((PerfectModTestPlayer)Player).CheckFailed(shouldMiss && testCaseData.FailOnMiss) + }); + + protected sealed override TestPlayer CreateReplayPlayer(Score score) => new PerfectModTestPlayer(score); + + private class PerfectModTestPlayer : TestPlayer + { + public PerfectModTestPlayer(Score score) + : base(score) + { + } + + protected override bool AllowFail => true; + + public bool CheckFailed(bool failed) + { + if (!failed) + return ScoreProcessor.HasCompleted && !HealthProcessor.HasFailed; + + return ScoreProcessor.JudgedHits > 0 && HealthProcessor.HasFailed; + } + } + + protected class HitObjectTestCase + { + public readonly HitObject HitObject; + public readonly bool FailOnMiss; + + public HitObjectTestCase(HitObject hitObject, bool failOnMiss = true) + { + HitObject = hitObject; + FailOnMiss = failOnMiss; + } + } + } +}