From a2ba58c0f95759f4ee4644b5b2c9c74eef219d52 Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Thu, 1 Dec 2022 10:53:23 +0600 Subject: [PATCH] Added some tests for composition animations --- .../Animations/KeyFrameAnimationInstance.cs | 7 +- .../Composition/CompositionAnimationTests.cs | 104 ++++++++++++++++++ 2 files changed, 110 insertions(+), 1 deletion(-) create mode 100644 tests/Avalonia.Base.UnitTests/Composition/CompositionAnimationTests.cs diff --git a/src/Avalonia.Base/Rendering/Composition/Animations/KeyFrameAnimationInstance.cs b/src/Avalonia.Base/Rendering/Composition/Animations/KeyFrameAnimationInstance.cs index 570c6a6d07..70462dd37b 100644 --- a/src/Avalonia.Base/Rendering/Composition/Animations/KeyFrameAnimationInstance.cs +++ b/src/Avalonia.Base/Rendering/Composition/Animations/KeyFrameAnimationInstance.cs @@ -130,7 +130,12 @@ namespace Avalonia.Rendering.Composition.Animations right = _keyFrames[c + 1]; } else if (c == 0) - return ExpressionVariant.Create(GetKeyFrame(ref ctx, kf)); + { + // The current progress is before the first frame, we implicitly use the starting value + // as the first frame in this case + right = _keyFrames[c]; + break; + } else break; } diff --git a/tests/Avalonia.Base.UnitTests/Composition/CompositionAnimationTests.cs b/tests/Avalonia.Base.UnitTests/Composition/CompositionAnimationTests.cs new file mode 100644 index 0000000000..9b38422dde --- /dev/null +++ b/tests/Avalonia.Base.UnitTests/Composition/CompositionAnimationTests.cs @@ -0,0 +1,104 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Reflection; +using Avalonia.Animation.Easings; +using Avalonia.Base.UnitTests.Rendering; +using Avalonia.Rendering; +using Avalonia.Rendering.Composition; +using Avalonia.Rendering.Composition.Expressions; +using Avalonia.Rendering.Composition.Server; +using Avalonia.Threading; +using Xunit; +using Xunit.Sdk; + +namespace Avalonia.Base.UnitTests.Composition; + +public class CompositionAnimationTests +{ + + class AnimationDataProvider : DataAttribute + { + IEnumerable Generate() => + new AnimationData[] + { + new("3 frames starting from 0") + { + Frames = + { + (0f, 10f), + (0.5f, 30f), + (1f, 20f) + }, + Checks = + { + (0.25f, 20f), + (0.5f, 30f), + (0.75f, 25f), + (1f, 20f) + } + }, + new("1 final frame") + { + Frames = + { + (1f, 10f) + }, + Checks = + { + (0f, 0f), + (0.5f, 5f), + (1f, 10f) + } + } + }; + + public override IEnumerable GetData(MethodInfo testMethod) + { + foreach (var ani in Generate()) + { + yield return new Object[] { ani }; + } + } + } + + [AnimationDataProvider] + [Theory] + public void GenericCheck(AnimationData data) + { + var compositor = + new Compositor(new RenderLoop(new CompositorTestsBase.ManualRenderTimer(), new Dispatcher(null)), null); + var target = compositor.CreateSolidColorVisual(); + var ani = new ScalarKeyFrameAnimation(null); + foreach (var frame in data.Frames) + ani.InsertKeyFrame(frame.key, frame.value, new LinearEasing()); + ani.Duration = TimeSpan.FromSeconds(1); + var instance = ani.CreateInstance(target.Server, null); + instance.Initialize(TimeSpan.Zero, data.StartingValue, ServerCompositionVisual.s_IdOfRotationAngleProperty); + var currentValue = ExpressionVariant.Create(data.StartingValue); + foreach (var check in data.Checks) + { + currentValue = instance.Evaluate(TimeSpan.FromSeconds(check.time), currentValue); + Assert.Equal(check.value, currentValue.Scalar); + } + + } + + public class AnimationData + { + public AnimationData(string name) + { + Name = name; + } + + public string Name { get; } + public List<(float key, float value)> Frames { get; set; } = new(); + public List<(float time, float value)> Checks { get; set; } = new(); + public float StartingValue { get; set; } + public float Duration { get; set; } = 1; + public override string ToString() + { + return Name; + } + } +} \ No newline at end of file