using XFESystem.Core; using XFESystem.Desktop; using Xunit; namespace XFESystem.Core.Tests; public sealed class DesktopMotionTests { private sealed class Canvas : IDesktopSceneMotionCanvas { public int Width => 1280; public int Height => 800; public bool SupportsSceneCache => true; public List<(DesktopBounds Source, int X, int Y)> Moves { get; } = []; public void Fill(uint rgb, int x, int y, int width, int height) { } public void Line(uint rgb, int x1, int y1, int x2, int y2) { } public void Text(string text, uint rgb, int x, int y) { } public void Present() { } public void PreserveTranslatedSceneRegion(DesktopBounds source, int destinationX, int destinationY) => Moves.Add((source, destinationX, destinationY)); public void EndScenePreservation() { } } [Fact] public void CoalescedDragReadsLastRenderedSceneRatherThanIntermediateInputBounds() { var canvas = new Canvas(); var desktop = new DesktopSession(canvas, new MemoryWorkspace()); var window = desktop.Open(DesktopApplication.Editor); desktop.Render(); var original = window.Bounds; desktop.Pointer(original.X + 90, original.Y + 15, true, timestampMs: 100); desktop.Render(); desktop.Pointer(original.X + 100, original.Y + 17, true, timestampMs: 110); desktop.Pointer(original.X + 110, original.Y + 19, true, timestampMs: 115); desktop.Render(); var move = Assert.Single(canvas.Moves); Assert.Equal(new DesktopBounds(original.X + 2, original.Y + 65, original.Width - 4, original.Height - 109), move.Source); Assert.Equal(window.Bounds.X + 2, move.X); Assert.Equal(window.Bounds.Y + 65, move.Y); var rendered = window.Bounds; desktop.Pointer(original.X + 120, original.Y + 20, true, timestampMs: 120); desktop.Render(); Assert.Equal(rendered.X + 2, canvas.Moves[^1].Source.X); } [Fact] public void EditingBetweenMotionPacketsCancelsReuseOfStaleDocumentPixels() { var canvas = new Canvas(); var desktop = new DesktopSession(canvas, new MemoryWorkspace()); var window = desktop.Open(DesktopApplication.Editor); desktop.Render(); var b = window.Bounds; desktop.Pointer(b.X + 90, b.Y + 15, true, timestampMs: 100); desktop.Render(); desktop.Pointer(b.X + 100, b.Y + 17, true, timestampMs: 110); desktop.Key(DesktopKey.Character, 'Z'); desktop.Render(); Assert.Empty(canvas.Moves); Assert.Equal("Z", window.Content); desktop.Pointer(b.X + 110, b.Y + 18, true, timestampMs: 120); desktop.Render(); Assert.Single(canvas.Moves); } [Fact] public void ResizeReusesOnlyACommonPrefixAfterItsInitialFullComposition() { var canvas = new Canvas(); var desktop = new DesktopSession(canvas, new MemoryWorkspace()); var window = desktop.Open(DesktopApplication.Editor); desktop.Render(); var b = window.Bounds; desktop.Pointer(b.X + 90, b.Y + 15, true, timestampMs: 100); desktop.Render(); desktop.Key(DesktopKey.Maximize); desktop.Render(); Assert.Empty(canvas.Moves); desktop.Key(DesktopKey.Restore); desktop.Render(); b = window.Bounds; desktop.Pointer(b.X + b.Width - 5, b.Y + b.Height - 5, false, timestampMs: 200); desktop.Pointer(b.X + b.Width - 5, b.Y + b.Height - 5, true, timestampMs: 205); desktop.Render(); Assert.Empty(canvas.Moves); desktop.Pointer(b.X + b.Width + 10, b.Y + b.Height + 10, true, timestampMs: 210); desktop.Render(); var move = Assert.Single(canvas.Moves); Assert.Equal(new DesktopBounds(b.X + 2, b.Y + 65, b.Width - 96, b.Height - 129), move.Source); Assert.Equal(move.Source.X, move.X); Assert.Equal(move.Source.Y, move.Y); desktop.Pointer(b.X + b.Width - 20, b.Y + b.Height - 20, true, timestampMs: 220); desktop.Render(); Assert.Equal(2, canvas.Moves.Count); Assert.Equal(window.Bounds.Width - 96, canvas.Moves[^1].Source.Width); Assert.Equal(window.Bounds.Height - 129, canvas.Moves[^1].Source.Height); } [Fact] public void SettingsResizeAlwaysRecomposesConditionallyVisibleControls() { var canvas = new Canvas(); var desktop = new DesktopSession(canvas, new MemoryWorkspace()); var window = desktop.Open(DesktopApplication.Settings); desktop.Render(); var b = window.Bounds; desktop.Pointer(b.X + b.Width - 5, b.Y + b.Height - 5, true, timestampMs: 100); desktop.Render(); desktop.Pointer(b.X + b.Width - 50, b.Y + b.Height - 50, true, timestampMs: 110); desktop.Render(); Assert.Empty(canvas.Moves); } [Theory] [InlineData(DesktopApplication.Files, 515, 524)] [InlineData(DesktopApplication.Files, 524, 515)] [InlineData(DesktopApplication.Editor, 511, 512)] [InlineData(DesktopApplication.Editor, 512, 511)] [InlineData(DesktopApplication.Terminal, 511, 512)] public void ResizePrefixStopsBeforeEitherLayoutsFirstHiddenRow(DesktopApplication app, int oldHeight, int newHeight) { var canvas = new Canvas(); var desktop = new DesktopSession(canvas, new MemoryWorkspace()); var window = desktop.Open(app); desktop.Render(); var original = window.Bounds; int px = original.X + original.Width - 5, py = original.Y + original.Height - 5; desktop.Pointer(px, py, true, timestampMs: 100); desktop.Render(); desktop.Pointer(px, py + oldHeight - original.Height, true, timestampMs: 110); desktop.Render(); canvas.Moves.Clear(); desktop.Pointer(px, py + newHeight - original.Height, true, timestampMs: 120); desktop.Render(); var prefix = Assert.Single(canvas.Moves).Source; int rows = app == DesktopApplication.Files ? Math.Min((oldHeight - 132) / 28, (newHeight - 132) / 28) : Math.Min((oldHeight - 112) / 20, (newHeight - 112) / 20); int firstHiddenTop = original.Y + (app == DesktopApplication.Files ? 96 + rows * 28 : 76 + rows * 20); Assert.True(prefix.Y + prefix.Height <= firstHiddenTop); } [Fact] public void CodeResizeRepaintsTheWholeKeywordWhoseColorCanChangeAtTruncation() { var canvas = new Canvas(); var storage = new MemoryWorkspace(); string path = SystemPaths.Combine(SystemPaths.Documents, "Program.cs"); storage.WriteText(path, new string(' ', 22) + "namespaceABCD"); var desktop = new DesktopSession(canvas, storage); var window = desktop.Open(DesktopApplication.Editor, path); desktop.Render(); var original = window.Bounds; int py = original.Y + original.Height - 5; desktop.Pointer(original.X + original.Width - 5, py, true, timestampMs: 100); desktop.Render(); desktop.Pointer(original.X + 320 - 5, py, true, timestampMs: 110); desktop.Render(); canvas.Moves.Clear(); desktop.Pointer(original.X + 352 - 5, py, true, timestampMs: 120); desktop.Render(); var prefix = Assert.Single(canvas.Moves).Source; Assert.Equal(160, prefix.Width); Assert.True(prefix.X + prefix.Width <= original.X + 20 + 22 * 8); } }