From 2f020f8682aece5fcf4b54f879c4492149485ff6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 19 Sep 2023 19:44:41 +0900 Subject: [PATCH] Add test coverage of storyboard preferring skin when specified --- .../TestSceneDrawableStoryboardSprite.cs | 176 +++++++++++++++--- 1 file changed, 150 insertions(+), 26 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneDrawableStoryboardSprite.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneDrawableStoryboardSprite.cs index ec4bb1a86b..d20c7c2f7a 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneDrawableStoryboardSprite.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneDrawableStoryboardSprite.cs @@ -2,17 +2,23 @@ // See the LICENCE file in the repository root for full licence text. using System.Collections.Generic; +using System.IO; using System.Linq; +using System.Threading; +using System.Threading.Tasks; using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Sprites; +using osu.Framework.IO.Stores; using osu.Framework.Testing; using osu.Game.Rulesets; +using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu; using osu.Game.Storyboards; using osu.Game.Storyboards.Drawables; +using osu.Game.Tests.Resources; using osuTK; namespace osu.Game.Tests.Visual.Gameplay @@ -21,17 +27,21 @@ namespace osu.Game.Tests.Visual.Gameplay { protected override Ruleset CreateRulesetForSkinProvider() => new OsuRuleset(); - [Cached] - private Storyboard storyboard { get; set; } = new Storyboard(); + [Cached(typeof(Storyboard))] + private TestStoryboard storyboard { get; set; } = new TestStoryboard(); private IEnumerable sprites => this.ChildrenOfType(); + private const string lookup_name = "hitcircleoverlay"; + [Test] public void TestSkinSpriteDisallowedByDefault() { - const string lookup_name = "hitcircleoverlay"; - - AddStep("allow skin lookup", () => storyboard.UseSkinSprites = false); + AddStep("disallow all lookups", () => + { + storyboard.UseSkinSprites = false; + storyboard.AlwaysProvideTexture = false; + }); AddStep("create sprites", () => SetContents(_ => createSprite(lookup_name, Anchor.TopLeft, Vector2.Zero))); @@ -40,11 +50,13 @@ namespace osu.Game.Tests.Visual.Gameplay } [Test] - public void TestAllowLookupFromSkin() + public void TestLookupFromStoryboard() { - const string lookup_name = "hitcircleoverlay"; - - AddStep("allow skin lookup", () => storyboard.UseSkinSprites = true); + AddStep("allow storyboard lookup", () => + { + storyboard.UseSkinSprites = false; + storyboard.AlwaysProvideTexture = true; + }); AddStep("create sprites", () => SetContents(_ => createSprite(lookup_name, Anchor.TopLeft, Vector2.Zero))); @@ -52,16 +64,54 @@ namespace osu.Game.Tests.Visual.Gameplay AddAssert("sprite found texture", () => sprites.Any(sprite => sprite.ChildrenOfType().All(s => s.Texture != null))); - AddAssert("skinnable sprite has correct size", () => - sprites.Any(sprite => sprite.ChildrenOfType().All(s => s.Size == new Vector2(128)))); + assertStoryboardSourced(); + } + + [Test] + public void TestSkinLookupPreferredOverStoryboard() + { + AddStep("allow all lookups", () => + { + storyboard.UseSkinSprites = true; + storyboard.AlwaysProvideTexture = true; + }); + + AddStep("create sprites", () => SetContents(_ => createSprite(lookup_name, Anchor.TopLeft, Vector2.Zero))); + + // Only checking for at least one sprite that succeeded, as not all skins in this test provide the hitcircleoverlay texture. + AddAssert("sprite found texture", () => + sprites.Any(sprite => sprite.ChildrenOfType().All(s => s.Texture != null))); + + assertSkinSourced(); + } + + [Test] + public void TestAllowLookupFromSkin() + { + AddStep("allow skin lookup", () => + { + storyboard.UseSkinSprites = true; + storyboard.AlwaysProvideTexture = false; + }); + + AddStep("create sprites", () => SetContents(_ => createSprite(lookup_name, Anchor.TopLeft, Vector2.Zero))); + + // Only checking for at least one sprite that succeeded, as not all skins in this test provide the hitcircleoverlay texture. + AddAssert("sprite found texture", () => + sprites.Any(sprite => sprite.ChildrenOfType().All(s => s.Texture != null))); + + assertSkinSourced(); } [Test] public void TestFlippedSprite() { - const string lookup_name = "hitcircleoverlay"; + AddStep("allow all lookups", () => + { + storyboard.UseSkinSprites = true; + storyboard.AlwaysProvideTexture = true; + }); - AddStep("allow skin lookup", () => storyboard.UseSkinSprites = true); AddStep("create sprites", () => SetContents(_ => createSprite(lookup_name, Anchor.TopLeft, Vector2.Zero))); AddStep("flip sprites", () => sprites.ForEach(s => { @@ -74,9 +124,12 @@ namespace osu.Game.Tests.Visual.Gameplay [Test] public void TestZeroScale() { - const string lookup_name = "hitcircleoverlay"; + AddStep("allow all lookups", () => + { + storyboard.UseSkinSprites = true; + storyboard.AlwaysProvideTexture = true; + }); - AddStep("allow skin lookup", () => storyboard.UseSkinSprites = true); AddStep("create sprites", () => SetContents(_ => createSprite(lookup_name, Anchor.TopLeft, Vector2.Zero))); AddAssert("sprites present", () => sprites.All(s => s.IsPresent)); AddStep("scale sprite", () => sprites.ForEach(s => s.VectorScale = new Vector2(0, 1))); @@ -86,9 +139,12 @@ namespace osu.Game.Tests.Visual.Gameplay [Test] public void TestNegativeScale() { - const string lookup_name = "hitcircleoverlay"; + AddStep("allow all lookups", () => + { + storyboard.UseSkinSprites = true; + storyboard.AlwaysProvideTexture = true; + }); - AddStep("allow skin lookup", () => storyboard.UseSkinSprites = true); AddStep("create sprites", () => SetContents(_ => createSprite(lookup_name, Anchor.TopLeft, Vector2.Zero))); AddStep("scale sprite", () => sprites.ForEach(s => s.VectorScale = new Vector2(-1))); AddAssert("origin flipped", () => sprites.All(s => s.Origin == Anchor.BottomRight)); @@ -97,9 +153,12 @@ namespace osu.Game.Tests.Visual.Gameplay [Test] public void TestNegativeScaleWithFlippedSprite() { - const string lookup_name = "hitcircleoverlay"; + AddStep("allow all lookups", () => + { + storyboard.UseSkinSprites = true; + storyboard.AlwaysProvideTexture = true; + }); - AddStep("allow skin lookup", () => storyboard.UseSkinSprites = true); AddStep("create sprites", () => SetContents(_ => createSprite(lookup_name, Anchor.TopLeft, Vector2.Zero))); AddStep("scale sprite", () => sprites.ForEach(s => s.VectorScale = new Vector2(-1))); AddAssert("origin flipped", () => sprites.All(s => s.Origin == Anchor.BottomRight)); @@ -111,13 +170,78 @@ namespace osu.Game.Tests.Visual.Gameplay AddAssert("origin back", () => sprites.All(s => s.Origin == Anchor.TopLeft)); } - private DrawableStoryboardSprite createSprite(string lookupName, Anchor origin, Vector2 initialPosition) - => new DrawableStoryboardSprite( - new StoryboardSprite(lookupName, origin, initialPosition) - ).With(s => + private DrawableStoryboard createSprite(string lookupName, Anchor origin, Vector2 initialPosition) + { + var layer = storyboard.GetLayer("Background"); + + var sprite = new StoryboardSprite(lookupName, origin, initialPosition); + sprite.AddLoop(Time.Current, 100).Alpha.Add(Easing.None, 0, 10000, 1, 1); + + layer.Elements.Clear(); + layer.Add(sprite); + + return storyboard.CreateDrawable(); + } + + private void assertStoryboardSourced() + { + AddAssert("sprite came from storyboard", () => + sprites.Any(sprite => sprite.ChildrenOfType().All(s => s.Size == new Vector2(200)))); + } + + private void assertSkinSourced() + { + AddAssert("sprite came from skin", () => + sprites.Any(sprite => sprite.ChildrenOfType().All(s => s.Size == new Vector2(128)))); + } + + private partial class TestStoryboard : Storyboard + { + public override DrawableStoryboard CreateDrawable(IReadOnlyList? mods = null) { - s.LifetimeStart = double.MinValue; - s.LifetimeEnd = double.MaxValue; - }); + return new TestDrawableStoryboard(this, mods); + } + + public bool AlwaysProvideTexture { get; set; } + + public override string GetStoragePathFromStoryboardPath(string path) => AlwaysProvideTexture ? path : string.Empty; + + private partial class TestDrawableStoryboard : DrawableStoryboard + { + private readonly bool alwaysProvideTexture; + + public TestDrawableStoryboard(TestStoryboard storyboard, IReadOnlyList? mods) + : base(storyboard, mods) + { + alwaysProvideTexture = storyboard.AlwaysProvideTexture; + } + + protected override IResourceStore CreateResourceLookupStore() => alwaysProvideTexture + ? new AlwaysReturnsTextureStore() + : new ResourceStore(); + + internal class AlwaysReturnsTextureStore : IResourceStore + { + private const string test_image = "Resources/Textures/test-image.png"; + + private readonly DllResourceStore store; + + public AlwaysReturnsTextureStore() + { + store = TestResources.GetStore(); + } + + public void Dispose() => store.Dispose(); + + public byte[] Get(string name) => store.Get(test_image); + + public Task GetAsync(string name, CancellationToken cancellationToken = new CancellationToken()) => store.GetAsync(test_image, cancellationToken); + + public Stream GetStream(string name) => store.GetStream(test_image); + + public IEnumerable GetAvailableResources() => store.GetAvailableResources(); + } + } + } } }