From 8d0dd3961e056b2670f67412a48cfdf000ec1694 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Tue, 19 Apr 2022 03:25:18 +0300 Subject: [PATCH] Add failing test cases --- .../LegacyMainCirclePieceTest.cs | 133 ++++++++++++++++++ .../Skinning/Legacy/LegacyMainCirclePiece.cs | 19 ++- 2 files changed, 146 insertions(+), 6 deletions(-) create mode 100644 osu.Game.Rulesets.Osu.Tests/LegacyMainCirclePieceTest.cs diff --git a/osu.Game.Rulesets.Osu.Tests/LegacyMainCirclePieceTest.cs b/osu.Game.Rulesets.Osu.Tests/LegacyMainCirclePieceTest.cs new file mode 100644 index 0000000000..200dd2f593 --- /dev/null +++ b/osu.Game.Rulesets.Osu.Tests/LegacyMainCirclePieceTest.cs @@ -0,0 +1,133 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using NUnit.Framework; +using osu.Framework.Audio.Sample; +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Framework.Graphics.OpenGL.Textures; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Graphics.Textures; +using osu.Framework.Testing; +using osu.Game.Audio; +using osu.Game.Rulesets.Osu.Skinning.Legacy; +using osu.Game.Skinning; +using osu.Game.Tests.Visual; + +#nullable enable + +namespace osu.Game.Rulesets.Osu.Tests +{ + [HeadlessTest] + public class LegacyMainCirclePieceTest : OsuTestScene + { + private static readonly object?[][] texture_priority_cases = + { + // default priority lookup + new object?[] + { + // available textures + new[] { @"hitcircle", @"hitcircleoverlay" }, + // priority lookup + @"", + // expected circle and overlay + @"hitcircle", @"hitcircleoverlay", + }, + // custom priority lookup + new object?[] + { + new[] { @"hitcircle", @"hitcircleoverlay", @"sliderstartcircle", @"sliderstartcircleoverlay" }, + @"sliderstartcircle", + @"sliderstartcircle", @"sliderstartcircleoverlay", + }, + // when no sprites are available for the specified prefix, fall back to "hitcircle"/"hitcircleoverlay". + new object?[] + { + new[] { @"hitcircle", @"hitcircleoverlay" }, + @"sliderstartcircle", + @"hitcircle", @"hitcircleoverlay", + }, + // when a circle is available for the specified prefix but no overlay exists, no overlay is displayed. + new object?[] + { + new[] { @"hitcircle", @"hitcircleoverlay", @"sliderstartcircle" }, + @"sliderstartcircle", + @"sliderstartcircle", null + }, + // when no circle is available for the specified prefix but an overlay exists, the overlay is ignored. + new object?[] + { + new[] { @"hitcircle", @"hitcircleoverlay", @"sliderstartcircleoverlay" }, + @"sliderstartcircle", + @"hitcircle", @"hitcircleoverlay", + } + }; + + [TestCaseSource(nameof(texture_priority_cases))] + public void TestTexturePriorities(string[] textureFilenames, string priorityLookup, string? expectedCircle, string? expectedOverlay) + { + Sprite? circleSprite = null; + Sprite? overlaySprite = null; + + AddStep("load circle piece", () => + { + Child = new DependencyProvidingContainer + { + CachedDependencies = new (Type, object)[] + { + (typeof(ISkinSource), new TestSkin(textureFilenames)) + }, + Child = new LegacyMainCirclePiece(priorityLookup, false), + }; + + var sprites = this.ChildrenOfType().Where(s => s.Texture.AssetName != null).DistinctBy(s => s.Texture.AssetName).ToArray(); + Debug.Assert(sprites.Length <= 2); + + circleSprite = sprites.ElementAtOrDefault(0); + overlaySprite = sprites.ElementAtOrDefault(1); + }); + + AddAssert("check circle sprite", () => circleSprite?.Texture?.AssetName == expectedCircle); + AddAssert("check overlay sprite", () => overlaySprite?.Texture?.AssetName == expectedOverlay); + } + + private class TestSkin : ISkinSource + { + private readonly string[] textureFilenames; + + public TestSkin(string[] textureFilenames) + { + this.textureFilenames = textureFilenames; + } + + public Texture? GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT) + { + if (textureFilenames.Contains(componentName)) + return new Texture(1, 1) { AssetName = componentName }; + + return null; + } + + public event Action SourceChanged + { + add { } + remove { } + } + + public IEnumerable AllSources { get; } = Enumerable.Empty(); + public Drawable? GetDrawableComponent(ISkinComponent component) => null; + public ISample? GetSample(ISampleInfo sampleInfo) => null; + + public IBindable? GetConfig(TLookup lookup) + where TLookup : notnull + where TValue : notnull + => null; + + public ISkin? FindProvider(Func lookupFunction) => lookupFunction(this) ? this : null; + } + } +} diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyMainCirclePiece.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyMainCirclePiece.cs index c6007885be..829dbb02f1 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyMainCirclePiece.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyMainCirclePiece.cs @@ -1,6 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using JetBrains.Annotations; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; @@ -43,7 +44,8 @@ public LegacyMainCirclePiece(string priorityLookup = null, bool hasNumber = true private readonly Bindable accentColour = new Bindable(); private readonly IBindable indexInCurrentCombo = new Bindable(); - [Resolved] + [Resolved(canBeNull: true)] + [CanBeNull] private DrawableHitObject drawableObject { get; set; } [Resolved] @@ -107,8 +109,11 @@ private void load() if (overlayAboveNumber) OverlayLayer.ChangeChildDepth(hitCircleOverlay, float.MinValue); - accentColour.BindTo(drawableObject.AccentColour); - indexInCurrentCombo.BindTo(drawableOsuObject.IndexInCurrentComboBindable); + if (drawableOsuObject != null) + { + accentColour.BindTo(drawableOsuObject.AccentColour); + indexInCurrentCombo.BindTo(drawableOsuObject.IndexInCurrentComboBindable); + } Texture getTextureWithFallback(string name) { @@ -149,15 +154,17 @@ protected override void LoadComplete() if (hasNumber) indexInCurrentCombo.BindValueChanged(index => hitCircleText.Text = (index.NewValue + 1).ToString(), true); - drawableObject.ApplyCustomUpdateState += updateStateTransforms; - updateStateTransforms(drawableObject, drawableObject.State.Value); + if (drawableObject != null) + drawableObject.ApplyCustomUpdateState += updateStateTransforms; + + updateStateTransforms(drawableObject, drawableObject?.State.Value ?? ArmedState.Idle); } private void updateStateTransforms(DrawableHitObject drawableHitObject, ArmedState state) { const double legacy_fade_duration = 240; - using (BeginAbsoluteSequence(drawableObject.HitStateUpdateTime)) + using (BeginAbsoluteSequence(drawableObject?.HitStateUpdateTime ?? 0)) { switch (state) {