using Artemis.UI.Shared.Services.ProfileEditor.Commands; using Artemis.UI.Shared.Tests.Infrastructure; using RGB.NET.Core; namespace Artemis.UI.Shared.Tests.ProfileEditor.Commands; /// /// Deleting, duplicating, moving and easing keyframes, and turning keyframes on and off /// public class KeyframeCommandTests : ProfileEditorTestBase { private readonly FloatLayerProperty _opacity; private readonly LayerPropertyKeyframe _first; private readonly LayerPropertyKeyframe _second; public KeyframeCommandTests() { Layer layer = AddLayer("Layer", null, LedId.Keyboard_A); _opacity = layer.Transform.Opacity; _opacity.KeyframesEnabled = true; _first = new LayerPropertyKeyframe(20, TimeSpan.FromSeconds(1), Easings.Functions.Linear, _opacity); _second = new LayerPropertyKeyframe(80, TimeSpan.FromSeconds(2), Easings.Functions.Linear, _opacity); _opacity.AddKeyframe(_first); _opacity.AddKeyframe(_second); } [Fact] public void DeleteKeyframe_RemovesTheKeyframe() { DeleteKeyframe command = new(_first); command.Execute(); command.DisplayName.ShouldBe("Delete keyframe"); _opacity.Keyframes.ShouldBe([_second]); } [Fact] public void DeleteKeyframe_Undo_PutsTheSameKeyframeBack() { string before = Snapshot(); DeleteKeyframe command = new(_first); command.Execute(); command.Undo(); _opacity.Keyframes.ShouldBe([_first, _second]); Snapshot().ShouldBe(before); } [Fact] public void DeleteKeyframe_Undo_OfTheLastKeyframe_TurnsKeyframesBackOn() { DeleteKeyframe deleteFirst = new(_first); DeleteKeyframe deleteSecond = new(_second); deleteFirst.Execute(); deleteSecond.Execute(); _opacity.KeyframesEnabled = false; deleteSecond.Undo(); // Adding a keyframe always turns keyframes on _opacity.KeyframesEnabled.ShouldBeTrue(); } [Fact] public void DuplicateKeyframe_AddsACopyAtThePosition() { _first.EasingFunction = Easings.Functions.CubicEaseIn; DuplicateKeyframe command = new(_first, TimeSpan.FromSeconds(3)); command.Execute(); command.DisplayName.ShouldBe("Duplicate keyframe"); LayerPropertyKeyframe copy = command.Duplication.ShouldBeOfType>(); _opacity.Keyframes.ShouldBe([_first, _second, copy]); copy.Value.ShouldBe(20); copy.Position.ShouldBe(TimeSpan.FromSeconds(3)); copy.EasingFunction.ShouldBe(Easings.Functions.CubicEaseIn); } [Fact] public void DuplicateKeyframe_UndoAndRedo_ReuseTheSameCopy() { string before = Snapshot(); DuplicateKeyframe command = new(_first, TimeSpan.FromSeconds(3)); command.Execute(); ILayerPropertyKeyframe copy = command.Duplication!; command.Undo(); Snapshot().ShouldBe(before); command.Execute(); command.Duplication.ShouldBe(copy); _opacity.Keyframes.ShouldContain((LayerPropertyKeyframe) copy); } [Fact] public void DuplicateKeyframe_Undo_BeforeExecute_DoesNothing() { new DuplicateKeyframe(_first, TimeSpan.FromSeconds(3)).Undo(); _opacity.Keyframes.ShouldBe([_first, _second]); } [Fact] public void MoveKeyframe_MovesAndUndoRestoresThePosition() { string before = Snapshot(); MoveKeyframe command = new(_first, TimeSpan.FromSeconds(3)); command.Execute(); command.DisplayName.ShouldBe("Move keyframe"); _first.Position.ShouldBe(TimeSpan.FromSeconds(3)); // Keyframes stay sorted by position _opacity.Keyframes.ShouldBe([_second, _first]); command.Undo(); _first.Position.ShouldBe(TimeSpan.FromSeconds(1)); _opacity.Keyframes.ShouldBe([_first, _second]); Snapshot().ShouldBe(before); } [Fact] public void MoveKeyframe_WithAnOriginalPosition_UndoesToThatPosition() { // The timeline moves keyframes while dragging and passes where the drag started _first.Position = TimeSpan.FromSeconds(1.5); MoveKeyframe command = new(_first, TimeSpan.FromSeconds(1.75), TimeSpan.FromSeconds(1)); command.Execute(); _first.Position.ShouldBe(TimeSpan.FromSeconds(1.75)); command.Undo(); _first.Position.ShouldBe(TimeSpan.FromSeconds(1)); } [Fact] public void ChangeKeyframeEasing_ChangesAndUndoRestoresTheEasing() { string before = Snapshot(); ChangeKeyframeEasing command = new(_first, Easings.Functions.CubicEaseInOut); command.Execute(); command.DisplayName.ShouldBe("Change easing to cubic ease in out"); _first.EasingFunction.ShouldBe(Easings.Functions.CubicEaseInOut); command.Undo(); _first.EasingFunction.ShouldBe(Easings.Functions.Linear); Snapshot().ShouldBe(before); } [Fact] public void ToggleLayerPropertyKeyframes_Enable_AddsAKeyframeWithTheCurrentValue() { FloatLayerProperty rotation = ((Layer) _opacity.ProfileElement).Transform.Rotation; rotation.SetCurrentValue(45); ToggleLayerPropertyKeyframes command = new(rotation, true, TimeSpan.FromSeconds(2)); command.Execute(); command.DisplayName.ShouldBe("Enable keyframes"); rotation.KeyframesEnabled.ShouldBeTrue(); LayerPropertyKeyframe keyframe = rotation.Keyframes.ShouldHaveSingleItem(); keyframe.Value.ShouldBe(45); keyframe.Position.ShouldBe(TimeSpan.FromSeconds(2)); keyframe.EasingFunction.ShouldBe(Easings.Functions.Linear); } [Fact] public void ToggleLayerPropertyKeyframes_Enable_UndoAndRedo() { FloatLayerProperty rotation = ((Layer) _opacity.ProfileElement).Transform.Rotation; string before = Snapshot(); ToggleLayerPropertyKeyframes command = new(rotation, true, TimeSpan.FromSeconds(2)); command.Execute(); LayerPropertyKeyframe keyframe = rotation.Keyframes.Single(); command.Undo(); rotation.KeyframesEnabled.ShouldBeFalse(); rotation.Keyframes.ShouldBeEmpty(); Snapshot().ShouldBe(before); command.Execute(); rotation.Keyframes.ShouldBe([keyframe]); } [Fact] public void ToggleLayerPropertyKeyframes_Enable_WithKeyframesAlreadyThere_AddsNone() { _opacity.KeyframesEnabled = false; string before = Snapshot(); ToggleLayerPropertyKeyframes command = new(_opacity, true, TimeSpan.FromSeconds(3)); command.Execute(); _opacity.KeyframesEnabled.ShouldBeTrue(); _opacity.Keyframes.ShouldBe([_first, _second]); command.Undo(); _opacity.KeyframesEnabled.ShouldBeFalse(); Snapshot().ShouldBe(before); } [Fact] public void ToggleLayerPropertyKeyframes_Disable_UndoTurnsThemBackOn() { string before = Snapshot(); ToggleLayerPropertyKeyframes command = new(_opacity, false, TimeSpan.Zero); command.Execute(); command.DisplayName.ShouldBe("Disable keyframes"); _opacity.KeyframesEnabled.ShouldBeFalse(); // The keyframes themselves are kept _opacity.Keyframes.ShouldBe([_first, _second]); command.Undo(); _opacity.KeyframesEnabled.ShouldBeTrue(); Snapshot().ShouldBe(before); } [Fact] public void ToggleLayerPropertyKeyframes_Undo_RestoresWhatItWasBefore() { ToggleLayerPropertyKeyframes enable = new(_opacity, true, TimeSpan.Zero); enable.Execute(); enable.Undo(); // "Enabling" keyframes that were already enabled leaves them enabled when undone _opacity.KeyframesEnabled.ShouldBeTrue(); _opacity.Keyframes.ShouldBe([_first, _second]); } }