From 94bd9c2f73f0bb72af93ef175e4c169d1440c03b Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Mon, 11 Nov 2024 22:56:46 +0900 Subject: [PATCH 1/4] Refactor step buttons + enable NRT --- .../Visual/Testing/TestSceneStepButton.cs | 45 ++++- .../Visual/Testing/TestSceneTest.cs | 5 +- .../Testing/Drawables/Steps/AssertButton.cs | 19 +-- .../Testing/Drawables/Steps/LabelStep.cs | 17 ++ .../Drawables/Steps/RepeatStepButton.cs | 30 ++-- .../Drawables/Steps/SingleStepButton.cs | 19 +-- .../Testing/Drawables/Steps/StepButton.cs | 58 +++---- .../Drawables/Steps/ToggleStepButton.cs | 20 +-- .../Drawables/Steps/UntilStepButton.cs | 70 ++++---- osu.Framework/Testing/TestBrowser.cs | 3 +- osu.Framework/Testing/TestScene.cs | 161 +++++++++--------- 11 files changed, 242 insertions(+), 205 deletions(-) diff --git a/osu.Framework.Tests/Visual/Testing/TestSceneStepButton.cs b/osu.Framework.Tests/Visual/Testing/TestSceneStepButton.cs index 613421f7c7..2b8b7bedac 100644 --- a/osu.Framework.Tests/Visual/Testing/TestSceneStepButton.cs +++ b/osu.Framework.Tests/Visual/Testing/TestSceneStepButton.cs @@ -1,8 +1,7 @@ // 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 System.Diagnostics; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Testing.Drawables.Steps; @@ -22,12 +21,42 @@ public TestSceneStepButton() Spacing = new Vector2(5), Children = new Drawable[] { - new LabelStep { Text = nameof(LabelStep) }, - new AssertButton { Text = nameof(AssertButton), Assertion = () => true }, - new SingleStepButton { Text = nameof(SingleStepButton) }, - new RepeatStepButton(null) { Text = nameof(RepeatStepButton) }, - new ToggleStepButton(null) { Text = nameof(ToggleStepButton) }, - new UntilStepButton(() => true) { Text = nameof(UntilStepButton) }, + new LabelStep + { + Text = nameof(LabelStep), + IsSetupStep = false, + Test = this + }, + new AssertButton + { + Text = nameof(AssertButton), + IsSetupStep = false, + Assertion = () => true, + CallStack = new StackTrace() + }, + new SingleStepButton + { + Text = nameof(SingleStepButton), + IsSetupStep = false, + Action = () => { } + }, + new RepeatStepButton + { + Text = nameof(RepeatStepButton), + IsSetupStep = false + }, + new ToggleStepButton + { + Text = nameof(ToggleStepButton), + IsSetupStep = false, + Action = _ => { } + }, + new UntilStepButton + { + Text = nameof(UntilStepButton), + IsSetupStep = false, + Assertion = () => true + }, new StepSlider(nameof(StepSlider), 0, 10, 5), } }; diff --git a/osu.Framework.Tests/Visual/Testing/TestSceneTest.cs b/osu.Framework.Tests/Visual/Testing/TestSceneTest.cs index c93a996bc7..26ba31bf95 100644 --- a/osu.Framework.Tests/Visual/Testing/TestSceneTest.cs +++ b/osu.Framework.Tests/Visual/Testing/TestSceneTest.cs @@ -38,9 +38,10 @@ public virtual void SetUpSteps() if (DebugUtils.IsNUnitRunning && TestContext.CurrentContext.Test.MethodName == nameof(TestConstructor)) return; - AddStep(new SingleStepButton(true) + AddStep(new SingleStepButton { - Name = "set up dummy", + Text = "set up dummy", + IsSetupStep = true, Action = () => setupStepsDummyRun++ }); diff --git a/osu.Framework/Testing/Drawables/Steps/AssertButton.cs b/osu.Framework/Testing/Drawables/Steps/AssertButton.cs index e75e05fb03..16565b1274 100644 --- a/osu.Framework/Testing/Drawables/Steps/AssertButton.cs +++ b/osu.Framework/Testing/Drawables/Steps/AssertButton.cs @@ -1,8 +1,6 @@ // 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 System; using System.Diagnostics; using System.Text; @@ -13,15 +11,14 @@ namespace osu.Framework.Testing.Drawables.Steps { public partial class AssertButton : StepButton { - public Func Assertion; - public string ExtendedDescription; - public StackTrace CallStack; - private readonly Func getFailureMessage; + public required StackTrace CallStack { get; init; } + public required Func Assertion { get; init; } + public Func? GetFailureMessage { get; init; } + + public string? ExtendedDescription { get; init; } - public AssertButton(bool isSetupStep = false, Func getFailureMessage = null) - : base(isSetupStep) + public AssertButton() { - this.getFailureMessage = getFailureMessage; Action += checkAssert; LightColour = Color4.OrangeRed; } @@ -39,8 +36,8 @@ private void checkAssert() if (!string.IsNullOrEmpty(ExtendedDescription)) builder.Append($" {ExtendedDescription}"); - if (getFailureMessage != null) - builder.Append($": {getFailureMessage()}"); + if (GetFailureMessage != null) + builder.Append($": {GetFailureMessage()}"); throw new TracedException(builder.ToString(), CallStack); } diff --git a/osu.Framework/Testing/Drawables/Steps/LabelStep.cs b/osu.Framework/Testing/Drawables/Steps/LabelStep.cs index c6fcd61616..762c50343a 100644 --- a/osu.Framework/Testing/Drawables/Steps/LabelStep.cs +++ b/osu.Framework/Testing/Drawables/Steps/LabelStep.cs @@ -1,12 +1,18 @@ // 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 osu.Framework.Development; +using osu.Framework.Logging; using osuTK.Graphics; namespace osu.Framework.Testing.Drawables.Steps { public partial class LabelStep : StepButton { + public required TestScene Test { get; init; } + public new Action? Action { get; set; } + protected override Color4 IdleColour => new Color4(77, 77, 77, 255); protected override Color4 RunningColour => new Color4(128, 128, 128, 255); @@ -15,6 +21,17 @@ public LabelStep() { Light.Hide(); Height = 30; + base.Action = clickAction; + } + + private void clickAction() + { + Logger.Log($@"💨 {Test} {Text}"); + + if (!DebugUtils.IsNUnitRunning) + Test.RunAllSteps(startFromStep: this, stopCondition: s => s is LabelStep); + + Action?.Invoke(); } } } diff --git a/osu.Framework/Testing/Drawables/Steps/RepeatStepButton.cs b/osu.Framework/Testing/Drawables/Steps/RepeatStepButton.cs index 5a386b60af..20e7aa4e1f 100644 --- a/osu.Framework/Testing/Drawables/Steps/RepeatStepButton.cs +++ b/osu.Framework/Testing/Drawables/Steps/RepeatStepButton.cs @@ -1,45 +1,39 @@ // 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 System; namespace osu.Framework.Testing.Drawables.Steps { public partial class RepeatStepButton : StepButton { - private readonly int count; - private int invocations; + public int Count { get; init; } = 1; - public override int RequiredRepetitions => count; + public override int RequiredRepetitions => Count; - private string text; + private readonly string text = string.Empty; + private int invocations; - public new string Text + public RepeatStepButton() { - get => text; - set => base.Text = text = value; + updateText(); } - public RepeatStepButton(Action action, int count = 1, bool isSetupStep = false) - : base(isSetupStep) + public new string Text { - this.count = count; - Action = action; - - updateText(); + get => text; + init => base.Text = text = value; } public override void PerformStep(bool userTriggered = false) { - if (invocations == count && !userTriggered) throw new InvalidOperationException("Repeat step was invoked too many times"); + if (invocations == Count && !userTriggered) throw new InvalidOperationException("Repeat step was invoked too many times"); invocations++; base.PerformStep(userTriggered); - if (invocations >= count) // Allows for manual execution beyond the invocation limit. + if (invocations >= Count) // Allows for manual execution beyond the invocation limit. Success(); updateText(); @@ -53,7 +47,7 @@ public override void Reset() updateText(); } - private void updateText() => base.Text = $@"{Text} {invocations}/{count}"; + private void updateText() => base.Text = $@"{Text} {invocations}/{Count}"; public override string ToString() => "Repeat: " + base.ToString(); } diff --git a/osu.Framework/Testing/Drawables/Steps/SingleStepButton.cs b/osu.Framework/Testing/Drawables/Steps/SingleStepButton.cs index bc8806c971..203621e217 100644 --- a/osu.Framework/Testing/Drawables/Steps/SingleStepButton.cs +++ b/osu.Framework/Testing/Drawables/Steps/SingleStepButton.cs @@ -1,24 +1,23 @@ // 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 System; namespace osu.Framework.Testing.Drawables.Steps { public partial class SingleStepButton : StepButton { - public new Action Action; + public new required Action Action { get; init; } + + public SingleStepButton() + { + base.Action = clickAction; + } - public SingleStepButton(bool isSetupStep = false) - : base(isSetupStep) + private void clickAction() { - base.Action = () => - { - Action?.Invoke(); - Success(); - }; + Action(); + Success(); } } } diff --git a/osu.Framework/Testing/Drawables/Steps/StepButton.cs b/osu.Framework/Testing/Drawables/Steps/StepButton.cs index d85b9180ef..23d90f8a2a 100644 --- a/osu.Framework/Testing/Drawables/Steps/StepButton.cs +++ b/osu.Framework/Testing/Drawables/Steps/StepButton.cs @@ -1,8 +1,6 @@ // 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 System; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -16,42 +14,20 @@ namespace osu.Framework.Testing.Drawables.Steps { public abstract partial class StepButton : CompositeDrawable { - public virtual int RequiredRepetitions => 1; - - protected Box Light; - protected Box Background; - protected SpriteText SpriteText; - - public Action Action { get; set; } - - public LocalisableString Text - { - get => SpriteText.Text; - set => SpriteText.Text = value; - } - - private Color4 lightColour = Color4.BlueViolet; - - public Color4 LightColour - { - get => lightColour; - set - { - lightColour = value; - if (IsLoaded) Reset(); - } - } + public required bool IsSetupStep { get; init; } + public Action? Action { get; set; } - public readonly bool IsSetupStep; + public virtual int RequiredRepetitions => 1; protected virtual Color4 IdleColour => new Color4(0.15f, 0.15f, 0.15f, 1); - protected virtual Color4 RunningColour => new Color4(0.5f, 0.5f, 0.5f, 1); - protected StepButton(bool isSetupStep = false) - { - IsSetupStep = isSetupStep; + protected readonly Box Light; + protected readonly Box Background; + protected readonly SpriteText SpriteText; + protected StepButton() + { InternalChildren = new Drawable[] { Background = new Box @@ -85,6 +61,24 @@ protected StepButton(bool isSetupStep = false) Masking = true; } + public LocalisableString Text + { + get => SpriteText.Text; + set => SpriteText.Text = value; + } + + private Color4 lightColour = Color4.BlueViolet; + + public Color4 LightColour + { + get => lightColour; + set + { + lightColour = value; + if (IsLoaded) Reset(); + } + } + protected override void LoadComplete() { base.LoadComplete(); diff --git a/osu.Framework/Testing/Drawables/Steps/ToggleStepButton.cs b/osu.Framework/Testing/Drawables/Steps/ToggleStepButton.cs index 5d2b7d8857..41341b6f92 100644 --- a/osu.Framework/Testing/Drawables/Steps/ToggleStepButton.cs +++ b/osu.Framework/Testing/Drawables/Steps/ToggleStepButton.cs @@ -9,31 +9,31 @@ namespace osu.Framework.Testing.Drawables.Steps { public partial class ToggleStepButton : StepButton { - private readonly Action? reloadCallback; private static readonly Color4 off_colour = Color4.Red; private static readonly Color4 on_colour = Color4.YellowGreen; - public bool State; + public new required Action Action { get; init; } public override int RequiredRepetitions => 2; - public ToggleStepButton(Action? reloadCallback) + private bool state; + + public ToggleStepButton() { - this.reloadCallback = reloadCallback; - Action = clickAction; + base.Action = clickAction; LightColour = off_colour; } private void clickAction() { - State = !State; - Light.FadeColour(State ? on_colour : off_colour); - reloadCallback?.Invoke(State); + state = !state; + Light.FadeColour(state ? on_colour : off_colour); + Action(state); - if (!State) + if (!state) Success(); } - public override string ToString() => $"Toggle: {base.ToString()} ({(State ? "on" : "off")})"; + public override string ToString() => $"Toggle: {base.ToString()} ({(state ? "on" : "off")})"; } } diff --git a/osu.Framework/Testing/Drawables/Steps/UntilStepButton.cs b/osu.Framework/Testing/Drawables/Steps/UntilStepButton.cs index 54656d8953..75e63bef91 100644 --- a/osu.Framework/Testing/Drawables/Steps/UntilStepButton.cs +++ b/osu.Framework/Testing/Drawables/Steps/UntilStepButton.cs @@ -1,8 +1,6 @@ // 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 System; using System.Diagnostics; using System.Text; @@ -14,60 +12,58 @@ namespace osu.Framework.Testing.Drawables.Steps { public partial class UntilStepButton : StepButton { - private bool success; - - private int invocations; - private static readonly int max_attempt_milliseconds = FrameworkEnvironment.NoTestTimeout ? int.MaxValue : 10000; + public required Func Assertion { get; init; } + public Func? GetFailureMessage { get; init; } + public new Action? Action { get; set; } + public override int RequiredRepetitions => success ? 0 : int.MaxValue; - public new Action Action; + private readonly string text = string.Empty; + private bool success; + private int invocations; + private Stopwatch? elapsedTime; - private string text; + public UntilStepButton() + { + updateText(); + LightColour = Color4.Sienna; + base.Action = checkAssert; + } public new string Text { get => text; - set => base.Text = text = value; + init => base.Text = text = value; } - private Stopwatch elapsedTime; - - public UntilStepButton(Func waitUntilTrueDelegate, bool isSetupStep = false, Func getFailureMessage = null) - : base(isSetupStep) + private void checkAssert() { + invocations++; + elapsedTime ??= Stopwatch.StartNew(); + updateText(); - LightColour = Color4.Sienna; - base.Action = () => + if (Assertion()) { - invocations++; - - elapsedTime ??= Stopwatch.StartNew(); - - updateText(); - - if (waitUntilTrueDelegate()) - { - elapsedTime = null; - success = true; - Success(); - } - else if (!Debugger.IsAttached && elapsedTime.ElapsedMilliseconds >= max_attempt_milliseconds) - { - StringBuilder builder = new StringBuilder(); + elapsedTime = null; + success = true; + Success(); + } + else if (!Debugger.IsAttached && elapsedTime.ElapsedMilliseconds >= max_attempt_milliseconds) + { + StringBuilder builder = new StringBuilder(); - builder.Append($"\"{Text}\" timed out"); + builder.Append($"\"{Text}\" timed out"); - if (getFailureMessage != null) - builder.Append($": {getFailureMessage()}"); + if (GetFailureMessage != null) + builder.Append($": {GetFailureMessage()}"); - throw new AssertionException(builder.ToString()); - } + throw new AssertionException(builder.ToString()); + } - Action?.Invoke(); - }; + Action?.Invoke(); } public override void Reset() diff --git a/osu.Framework/Testing/TestBrowser.cs b/osu.Framework/Testing/TestBrowser.cs index 3290b01e3f..7ccfca25c6 100644 --- a/osu.Framework/Testing/TestBrowser.cs +++ b/osu.Framework/Testing/TestBrowser.cs @@ -521,9 +521,10 @@ void addSetUpSteps() if (setUpMethods.Any()) { - CurrentTest.AddStep(new SingleStepButton(true) + CurrentTest.AddStep(new SingleStepButton { Text = "[SetUp]", + IsSetupStep = true, LightColour = Color4.Teal, Action = () => setUpMethods.ForEach(s => s.Invoke(CurrentTest, null)) }); diff --git a/osu.Framework/Testing/TestScene.cs b/osu.Framework/Testing/TestScene.cs index c0dca8ec2f..d7678e1b9d 100644 --- a/osu.Framework/Testing/TestScene.cs +++ b/osu.Framework/Testing/TestScene.cs @@ -271,145 +271,154 @@ private void runNextStep(Action onCompletion, Action onError, Func runNextStep(onCompletion, onError, stopCondition), TimePerAction); } - public void AddStep(StepButton step) => schedule(() => StepsContainer.Add(step)); - - private bool addStepsAsSetupSteps; - public void ChangeBackgroundColour(ColourInfo colour) => backgroundFill.FadeColour(colour, 200, Easing.OutQuint); - public StepButton AddStep(string description, Action action) + private bool addStepsAsSetupSteps; + + public void AddStep(StepButton step) { - var step = new SingleStepButton(addStepsAsSetupSteps) + schedule(() => { - Text = description, - Action = action - }; - - AddStep(step); - - return step; + StepsContainer.Add(step); + }); } - public LabelStep AddLabel(string description) + public void AddStep([NotNull] string description, [NotNull] Action action) { - var step = new LabelStep + AddStep(new SingleStepButton { Text = description, - }; + Action = action, + IsSetupStep = addStepsAsSetupSteps + }); + } - step.Action = () => + public void AddLabel([NotNull] string description) + { + AddStep(new LabelStep { - Logger.Log($@"💨 {this} {description}"); - - // kinda hacky way to avoid this doesn't get triggered by automated runs. - if (step.IsHovered) - RunAllSteps(startFromStep: step, stopCondition: s => s is LabelStep); - }; - - AddStep(step); - - return step; + Text = description, + IsSetupStep = false, + Test = this, + }); } - protected void AddRepeatStep(string description, Action action, int invocationCount) => schedule(() => + protected void AddRepeatStep([NotNull] string description, [NotNull] Action action, int invocationCount) { - StepsContainer.Add(new RepeatStepButton(action, invocationCount, addStepsAsSetupSteps) + AddStep(new RepeatStepButton { Text = description, + IsSetupStep = addStepsAsSetupSteps, + Action = action, + Count = invocationCount }); - }); + } - protected void AddToggleStep(string description, Action action) => schedule(() => + protected void AddToggleStep([NotNull] string description, [NotNull] Action action) { - StepsContainer.Add(new ToggleStepButton(action) + AddStep(new ToggleStepButton { - Text = description + Text = description, + IsSetupStep = addStepsAsSetupSteps, + Action = action, }); - }); + } - protected void AddUntilStep(string description, Func waitUntilTrueDelegate) => schedule(() => + protected void AddUntilStep([CanBeNull] string description, [NotNull] Func waitUntilTrueDelegate) { - StepsContainer.Add(new UntilStepButton(waitUntilTrueDelegate, addStepsAsSetupSteps) + AddStep(new UntilStepButton { Text = description ?? @"Until", + IsSetupStep = addStepsAsSetupSteps, + Assertion = waitUntilTrueDelegate, }); - }); + } - protected void AddUntilStep(string description, ActualValueDelegate actualValue, Func constraint) => schedule(() => + protected void AddUntilStep([CanBeNull] string description, [NotNull] ActualValueDelegate actualValue, [NotNull] Func constraint) { ConstraintResult lastResult = null; - StepsContainer.Add( - new UntilStepButton( - () => - { - lastResult = constraint().Resolve().ApplyTo(actualValue()); - return lastResult.IsSuccess; - }, - addStepsAsSetupSteps, - () => - { - var writer = new TextMessageWriter(string.Empty); - lastResult.WriteMessageTo(writer); - return writer.ToString().TrimStart(); - }) + AddStep(new UntilStepButton + { + Text = description ?? @"Until", + IsSetupStep = addStepsAsSetupSteps, + Assertion = () => { - Text = description ?? @"Until", - }); - }); + lastResult = constraint().Resolve().ApplyTo(actualValue()); + return lastResult.IsSuccess; + }, + GetFailureMessage = () => + { + if (lastResult == null) + return string.Empty; + + var writer = new TextMessageWriter(string.Empty); + lastResult.WriteMessageTo(writer); + return writer.ToString().TrimStart(); + } + }); + } - protected void AddWaitStep(string description, int waitCount) => schedule(() => + protected void AddWaitStep([CanBeNull] string description, int waitCount) { - StepsContainer.Add(new RepeatStepButton(() => { }, waitCount, addStepsAsSetupSteps) + AddStep(new RepeatStepButton { Text = description ?? @"Wait", + IsSetupStep = addStepsAsSetupSteps, + Count = waitCount }); - }); + } - protected void AddSliderStep(string description, T min, T max, T start, Action valueChanged) where T : struct, INumber, IMinMaxValue => schedule(() => + protected void AddSliderStep([NotNull] string description, T min, T max, T start, [NotNull] Action valueChanged) where T : struct, INumber, IMinMaxValue { - StepsContainer.Add(new StepSlider(description, min, max, start) + schedule(() => { - ValueChanged = valueChanged, + StepsContainer.Add(new StepSlider(description, min, max, start) + { + ValueChanged = valueChanged, + }); }); - }); + } - protected void AddAssert(string description, Func assert, string extendedDescription = null) => schedule(() => + protected void AddAssert([NotNull] string description, [NotNull] Func assert, [CanBeNull] string extendedDescription = null) { - StepsContainer.Add(new AssertButton(addStepsAsSetupSteps) + AddStep(new AssertButton { Text = description, + IsSetupStep = addStepsAsSetupSteps, ExtendedDescription = extendedDescription, CallStack = new StackTrace(1), Assertion = assert, }); - }); + } - protected void AddAssert(string description, ActualValueDelegate actualValue, Func constraint, string extendedDescription = null) => schedule(() => + protected void AddAssert([NotNull] string description, [NotNull] ActualValueDelegate actualValue, [NotNull] Func constraint, [CanBeNull] string extendedDescription = null) { ConstraintResult lastResult = null; - StepsContainer.Add(new AssertButton(addStepsAsSetupSteps, () => - { - if (lastResult == null) - return string.Empty; - - var writer = new TextMessageWriter(string.Empty); - lastResult.WriteMessageTo(writer); - return writer.ToString().TrimStart(); - }) + AddStep(new AssertButton { Text = description, + IsSetupStep = addStepsAsSetupSteps, ExtendedDescription = extendedDescription, CallStack = new StackTrace(1), Assertion = () => { lastResult = constraint().Resolve().ApplyTo(actualValue()); return lastResult.IsSuccess; + }, + GetFailureMessage = () => + { + if (lastResult == null) + return string.Empty; + + var writer = new TextMessageWriter(string.Empty); + lastResult.WriteMessageTo(writer); + return writer.ToString().TrimStart(); } }); - }); + } internal void RunSetUpSteps() { From 42a01b939964d1f12a60f8f866fa635ed49fcfc7 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Mon, 11 Nov 2024 23:50:11 +0900 Subject: [PATCH 2/4] Give UntilStepButton a proper stacktrace --- .../Visual/Testing/TestSceneStepButton.cs | 3 ++- .../Testing/Drawables/Steps/AssertButton.cs | 14 ------------- .../Drawables/Steps/TracedException.cs | 21 +++++++++++++++++++ .../Drawables/Steps/UntilStepButton.cs | 4 ++-- osu.Framework/Testing/TestScene.cs | 2 ++ 5 files changed, 27 insertions(+), 17 deletions(-) create mode 100644 osu.Framework/Testing/Drawables/Steps/TracedException.cs diff --git a/osu.Framework.Tests/Visual/Testing/TestSceneStepButton.cs b/osu.Framework.Tests/Visual/Testing/TestSceneStepButton.cs index 2b8b7bedac..193cc4adc6 100644 --- a/osu.Framework.Tests/Visual/Testing/TestSceneStepButton.cs +++ b/osu.Framework.Tests/Visual/Testing/TestSceneStepButton.cs @@ -55,7 +55,8 @@ public TestSceneStepButton() { Text = nameof(UntilStepButton), IsSetupStep = false, - Assertion = () => true + Assertion = () => true, + CallStack = new StackTrace() }, new StepSlider(nameof(StepSlider), 0, 10, 5), } diff --git a/osu.Framework/Testing/Drawables/Steps/AssertButton.cs b/osu.Framework/Testing/Drawables/Steps/AssertButton.cs index 16565b1274..a57d2eb628 100644 --- a/osu.Framework/Testing/Drawables/Steps/AssertButton.cs +++ b/osu.Framework/Testing/Drawables/Steps/AssertButton.cs @@ -4,7 +4,6 @@ using System; using System.Diagnostics; using System.Text; -using NUnit.Framework; using osuTK.Graphics; namespace osu.Framework.Testing.Drawables.Steps @@ -44,18 +43,5 @@ private void checkAssert() } public override string ToString() => "Assert: " + base.ToString(); - - private class TracedException : AssertionException - { - private readonly StackTrace trace; - - public TracedException(string description, StackTrace trace) - : base(description) - { - this.trace = trace; - } - - public override string StackTrace => trace.ToString(); - } } } diff --git a/osu.Framework/Testing/Drawables/Steps/TracedException.cs b/osu.Framework/Testing/Drawables/Steps/TracedException.cs new file mode 100644 index 0000000000..bd2284e96b --- /dev/null +++ b/osu.Framework/Testing/Drawables/Steps/TracedException.cs @@ -0,0 +1,21 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Diagnostics; +using NUnit.Framework; + +namespace osu.Framework.Testing.Drawables.Steps +{ + internal class TracedException : AssertionException + { + private readonly StackTrace trace; + + public TracedException(string description, StackTrace trace) + : base(description) + { + this.trace = trace; + } + + public override string StackTrace => trace.ToString(); + } +} diff --git a/osu.Framework/Testing/Drawables/Steps/UntilStepButton.cs b/osu.Framework/Testing/Drawables/Steps/UntilStepButton.cs index 75e63bef91..b3c6bd6722 100644 --- a/osu.Framework/Testing/Drawables/Steps/UntilStepButton.cs +++ b/osu.Framework/Testing/Drawables/Steps/UntilStepButton.cs @@ -4,7 +4,6 @@ using System; using System.Diagnostics; using System.Text; -using NUnit.Framework; using osu.Framework.Graphics; using osuTK.Graphics; @@ -14,6 +13,7 @@ public partial class UntilStepButton : StepButton { private static readonly int max_attempt_milliseconds = FrameworkEnvironment.NoTestTimeout ? int.MaxValue : 10000; + public required StackTrace CallStack { get; init; } public required Func Assertion { get; init; } public Func? GetFailureMessage { get; init; } public new Action? Action { get; set; } @@ -60,7 +60,7 @@ private void checkAssert() if (GetFailureMessage != null) builder.Append($": {GetFailureMessage()}"); - throw new AssertionException(builder.ToString()); + throw new TracedException(builder.ToString(), CallStack); } Action?.Invoke(); diff --git a/osu.Framework/Testing/TestScene.cs b/osu.Framework/Testing/TestScene.cs index d7678e1b9d..9bdf41f8ba 100644 --- a/osu.Framework/Testing/TestScene.cs +++ b/osu.Framework/Testing/TestScene.cs @@ -331,6 +331,7 @@ protected void AddUntilStep([CanBeNull] string description, [NotNull] Func { Text = description ?? @"Until", IsSetupStep = addStepsAsSetupSteps, + CallStack = new StackTrace(1), Assertion = waitUntilTrueDelegate, }); } @@ -343,6 +344,7 @@ protected void AddUntilStep([CanBeNull] string description, [NotNull] ActualV { Text = description ?? @"Until", IsSetupStep = addStepsAsSetupSteps, + CallStack = new StackTrace(1), Assertion = () => { lastResult = constraint().Resolve().ApplyTo(actualValue()); From 3960655a4286d69038857413b3d47c3fef4bb813 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Mon, 11 Nov 2024 23:50:50 +0900 Subject: [PATCH 3/4] Further improve stacktrace output --- .../Testing/Drawables/Steps/AssertButton.cs | 4 +++- .../Drawables/Steps/TracedException.cs | 21 ------------------- .../Drawables/Steps/UntilStepButton.cs | 4 +++- osu.Framework/Testing/TestScene.cs | 11 +++++----- 4 files changed, 12 insertions(+), 28 deletions(-) delete mode 100644 osu.Framework/Testing/Drawables/Steps/TracedException.cs diff --git a/osu.Framework/Testing/Drawables/Steps/AssertButton.cs b/osu.Framework/Testing/Drawables/Steps/AssertButton.cs index a57d2eb628..d910acb964 100644 --- a/osu.Framework/Testing/Drawables/Steps/AssertButton.cs +++ b/osu.Framework/Testing/Drawables/Steps/AssertButton.cs @@ -3,7 +3,9 @@ using System; using System.Diagnostics; +using System.Runtime.ExceptionServices; using System.Text; +using NUnit.Framework; using osuTK.Graphics; namespace osu.Framework.Testing.Drawables.Steps @@ -38,7 +40,7 @@ private void checkAssert() if (GetFailureMessage != null) builder.Append($": {GetFailureMessage()}"); - throw new TracedException(builder.ToString(), CallStack); + throw ExceptionDispatchInfo.SetRemoteStackTrace(new AssertionException(builder.ToString()), CallStack.ToString()); } } diff --git a/osu.Framework/Testing/Drawables/Steps/TracedException.cs b/osu.Framework/Testing/Drawables/Steps/TracedException.cs deleted file mode 100644 index bd2284e96b..0000000000 --- a/osu.Framework/Testing/Drawables/Steps/TracedException.cs +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using System.Diagnostics; -using NUnit.Framework; - -namespace osu.Framework.Testing.Drawables.Steps -{ - internal class TracedException : AssertionException - { - private readonly StackTrace trace; - - public TracedException(string description, StackTrace trace) - : base(description) - { - this.trace = trace; - } - - public override string StackTrace => trace.ToString(); - } -} diff --git a/osu.Framework/Testing/Drawables/Steps/UntilStepButton.cs b/osu.Framework/Testing/Drawables/Steps/UntilStepButton.cs index b3c6bd6722..89447a9512 100644 --- a/osu.Framework/Testing/Drawables/Steps/UntilStepButton.cs +++ b/osu.Framework/Testing/Drawables/Steps/UntilStepButton.cs @@ -3,7 +3,9 @@ using System; using System.Diagnostics; +using System.Runtime.ExceptionServices; using System.Text; +using NUnit.Framework; using osu.Framework.Graphics; using osuTK.Graphics; @@ -60,7 +62,7 @@ private void checkAssert() if (GetFailureMessage != null) builder.Append($": {GetFailureMessage()}"); - throw new TracedException(builder.ToString(), CallStack); + throw ExceptionDispatchInfo.SetRemoteStackTrace(new AssertionException(builder.ToString()), CallStack.ToString()); } Action?.Invoke(); diff --git a/osu.Framework/Testing/TestScene.cs b/osu.Framework/Testing/TestScene.cs index 9bdf41f8ba..c781cd9619 100644 --- a/osu.Framework/Testing/TestScene.cs +++ b/osu.Framework/Testing/TestScene.cs @@ -331,7 +331,7 @@ protected void AddUntilStep([CanBeNull] string description, [NotNull] Func { Text = description ?? @"Until", IsSetupStep = addStepsAsSetupSteps, - CallStack = new StackTrace(1), + CallStack = new StackTrace(1, true), Assertion = waitUntilTrueDelegate, }); } @@ -344,7 +344,7 @@ protected void AddUntilStep([CanBeNull] string description, [NotNull] ActualV { Text = description ?? @"Until", IsSetupStep = addStepsAsSetupSteps, - CallStack = new StackTrace(1), + CallStack = new StackTrace(1, true), Assertion = () => { lastResult = constraint().Resolve().ApplyTo(actualValue()); @@ -390,12 +390,13 @@ protected void AddAssert([NotNull] string description, [NotNull] Func asse Text = description, IsSetupStep = addStepsAsSetupSteps, ExtendedDescription = extendedDescription, - CallStack = new StackTrace(1), + CallStack = new StackTrace(1, true), Assertion = assert, }); } - protected void AddAssert([NotNull] string description, [NotNull] ActualValueDelegate actualValue, [NotNull] Func constraint, [CanBeNull] string extendedDescription = null) + protected void AddAssert([NotNull] string description, [NotNull] ActualValueDelegate actualValue, [NotNull] Func constraint, + [CanBeNull] string extendedDescription = null) { ConstraintResult lastResult = null; @@ -404,7 +405,7 @@ protected void AddAssert([NotNull] string description, [NotNull] ActualValueD Text = description, IsSetupStep = addStepsAsSetupSteps, ExtendedDescription = extendedDescription, - CallStack = new StackTrace(1), + CallStack = new StackTrace(1, true), Assertion = () => { lastResult = constraint().Resolve().ApplyTo(actualValue()); From 43fdea246d371e897800e2f8f7d5f4d7222b7852 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Tue, 12 Nov 2024 01:06:22 +0900 Subject: [PATCH 4/4] Restore LabelStep implementation --- .../Visual/Testing/TestSceneStepButton.cs | 2 +- .../Testing/Drawables/Steps/LabelStep.cs | 15 ++------------- osu.Framework/Testing/TestScene.cs | 9 ++++++++- 3 files changed, 11 insertions(+), 15 deletions(-) diff --git a/osu.Framework.Tests/Visual/Testing/TestSceneStepButton.cs b/osu.Framework.Tests/Visual/Testing/TestSceneStepButton.cs index 193cc4adc6..602709ffc2 100644 --- a/osu.Framework.Tests/Visual/Testing/TestSceneStepButton.cs +++ b/osu.Framework.Tests/Visual/Testing/TestSceneStepButton.cs @@ -25,7 +25,7 @@ public TestSceneStepButton() { Text = nameof(LabelStep), IsSetupStep = false, - Test = this + Action = _ => { }, }, new AssertButton { diff --git a/osu.Framework/Testing/Drawables/Steps/LabelStep.cs b/osu.Framework/Testing/Drawables/Steps/LabelStep.cs index 762c50343a..5f1271a63a 100644 --- a/osu.Framework/Testing/Drawables/Steps/LabelStep.cs +++ b/osu.Framework/Testing/Drawables/Steps/LabelStep.cs @@ -2,16 +2,13 @@ // See the LICENCE file in the repository root for full licence text. using System; -using osu.Framework.Development; -using osu.Framework.Logging; using osuTK.Graphics; namespace osu.Framework.Testing.Drawables.Steps { public partial class LabelStep : StepButton { - public required TestScene Test { get; init; } - public new Action? Action { get; set; } + public new required Action Action { get; init; } protected override Color4 IdleColour => new Color4(77, 77, 77, 255); @@ -24,14 +21,6 @@ public LabelStep() base.Action = clickAction; } - private void clickAction() - { - Logger.Log($@"💨 {Test} {Text}"); - - if (!DebugUtils.IsNUnitRunning) - Test.RunAllSteps(startFromStep: this, stopCondition: s => s is LabelStep); - - Action?.Invoke(); - } + private void clickAction() => Action(this); } } diff --git a/osu.Framework/Testing/TestScene.cs b/osu.Framework/Testing/TestScene.cs index c781cd9619..4cc97bf25f 100644 --- a/osu.Framework/Testing/TestScene.cs +++ b/osu.Framework/Testing/TestScene.cs @@ -300,7 +300,14 @@ public void AddLabel([NotNull] string description) { Text = description, IsSetupStep = false, - Test = this, + Action = step => + { + Logger.Log($@"💨 {this} {description}"); + + // kinda hacky way to avoid this doesn't get triggered by automated runs. + if (step.IsHovered) + RunAllSteps(startFromStep: step, stopCondition: s => s is LabelStep); + }, }); }