XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet

XFESystem

【Rust】XFE系统,基于Rust和汇编

公开
关注 0 Fork 0 Star 0
UTF-8
using System.Text;
using XFESystem.Console;
using XFESystem.Core;
using Xunit;

namespace XFESystem.Desktop.Tests;

public sealed class TerminalDesktopTests
{
    [Fact]
    public void OpeningTerminalPaintsTheConciseBlueShellWithoutDemoToolbarOrDemoHitRegion()
    {
        var canvas = new Canvas(); int demos = 0;
        var desktop = new DesktopSession(canvas, new MemoryWorkspace(false), consoleDemo: () => demos++);
        var window = desktop.Open(DesktopApplication.Terminal); desktop.Render();
        Assert.NotNull(window.Shell); Assert.Equal("0.3.0-dev.3", window.Shell.Version);
        string text = canvas.TerminalText(window);
        Assert.Contains("XFESystem|XFEstudio", text); Assert.Contains("0.3.0-dev.3", text); Assert.Contains("help", text);
        Assert.DoesNotContain("Run Demo", text); Assert.DoesNotContain("development session", text);
        Assert.Contains(canvas.Texts, item => item.Color == 0x75C9F5 && item.Text.EndsWith("> ", StringComparison.Ordinal));
        desktop.Pointer(window.Bounds.X + 90, window.Bounds.Y + 48, true);
        desktop.Pointer(window.Bounds.X + 90, window.Bounds.Y + 48, false);
        Assert.Equal(0, demos); Assert.Same(window, desktop.ActiveWindow);
    }

    [Fact]
    public void DesktopKeyboardAndPasteExecuteRealRamCommandsAndRetainHistoryDraft()
    {
        var storage = new MemoryWorkspace(false); var desktop = new DesktopSession(new Canvas(), storage);
        var window = desktop.Open(DesktopApplication.Terminal);
        Run(desktop, "md Work"); Run(desktop, "cd Work"); Run(desktop, "mf Hello.txt"); Run(desktop, "write Hello.txt \"Hello XFE\"");
        Assert.Equal("Hello XFE", storage.ReadText(SystemPaths.Documents + "\\Work\\Hello.txt"));
        Assert.Equal(SystemPaths.Documents + "\\Work", window.Location);
        Assert.True(desktop.PasteTerminalInput("draft")); desktop.Key(DesktopKey.Up); Assert.Equal("write Hello.txt \"Hello XFE\"", window.Shell!.Input);
        desktop.Key(DesktopKey.Up); Assert.Equal("mf Hello.txt", window.Shell.Input);
        desktop.Key(DesktopKey.Down); desktop.Key(DesktopKey.Down); Assert.Equal("draft", window.Shell.Input);
        desktop.Key(DesktopKey.Escape); Assert.Empty(window.Shell.Input); Assert.Same(window, desktop.ActiveWindow);
        Assert.False(desktop.PasteTerminalInput("mf Bad.txt\n"));
        Run(desktop, "cat Hello.txt"); Assert.Contains("Hello XFE", string.Concat(window.Terminal!.Cells.Select(cell => cell.Text)));
        desktop.Key(DesktopKey.CloseWindow); Assert.Empty(desktop.Windows);
    }

    [Fact]
    public void MouseMovesTheInputCaretAndLeftDeleteInsertContinueEditingTheSameCommand()
    {
        var canvas = new Canvas(); var desktop = new DesktopSession(canvas, new MemoryWorkspace(false));
        var window = desktop.Open(DesktopApplication.Terminal); Assert.True(desktop.PasteTerminalInput("abcd")); desktop.Render();
        var prompt = canvas.Texts.Last(item => item.Text.EndsWith("> ", StringComparison.Ordinal));
        int x = prompt.X + canvas.TextWidth(prompt.Text) + 16, y = prompt.Y + 7;
        desktop.Pointer(x, y, true); desktop.Pointer(x, y, false); Assert.Equal(2, window.Shell!.Caret);
        desktop.Key(DesktopKey.Delete); desktop.Key(DesktopKey.Character, 'X'); Assert.Equal("abXd", window.Shell.Input);
        desktop.Key(DesktopKey.Left); desktop.Key(DesktopKey.Backspace); Assert.Equal("aXd", window.Shell.Input);
        desktop.Key(DesktopKey.Home); desktop.Key(DesktopKey.Insert); desktop.Key(DesktopKey.Character, 'Z'); Assert.Equal("ZXd", window.Shell.Input);
    }

    [Fact]
    public void ProgramOutputIsFrozenDuringWorkerOwnershipAndPublishedOnlyByUiCompletion()
    {
        var canvas = new Canvas(); var storage = new MemoryWorkspace(false); storage.WriteText(SystemPaths.Documents + "\\App.dll", "sample");
        TerminalProgramRequest? request = null;
        var desktop = new DesktopSession(canvas, storage) { TerminalProgramRequested = value => request = value };
        var window = desktop.Open(DesktopApplication.Terminal); Run(desktop, "run App.dll");
        Assert.NotNull(request); Assert.True(window.TerminalProgramRunning); var frozen = window.Terminal;
        Assert.Equal(window.Id, request.WindowId); Assert.Same(window.Shell!.ProgramOutput, request.Output);
        request.Output.Write("\u001b[38;2;23;45;67mWORKER ANSI\u001b[0m\r\n");
        Assert.False(desktop.PasteTerminalInput("echo blocked")); desktop.Key(DesktopKey.Character, 'x'); desktop.Key(DesktopKey.Enter);
        Assert.Empty(window.Shell.Input); Assert.Equal(new[] { "run App.dll" }, window.Shell.History);
        desktop.Key(DesktopKey.Cancel); Assert.Contains("cannot interrupt", window.Status);
        desktop.Render(); Assert.Same(frozen, window.Terminal); Assert.DoesNotContain("WORKER ANSI", canvas.TerminalText(window));
        desktop.RefreshTerminalOutput(window.Id); Assert.False(window.TerminalProgramRunning); canvas.Clear(); desktop.Render();
        Assert.Contains("WORKER ANSI", canvas.TerminalText(window));
        Assert.Contains(canvas.Texts, item => item.Color == 0x172D43 && item.Text == "W");
        Assert.Contains(canvas.Texts, item => item.Color == 0x75C9F5 && item.Text.EndsWith("> ", StringComparison.Ordinal));
    }

    [Fact]
    public void ClosedProgramWindowIsNotReopenedByItsLateCompletion()
    {
        var storage = new MemoryWorkspace(false); storage.WriteText(SystemPaths.Documents + "\\App.dll", "sample");
        TerminalProgramRequest? request = null;
        var desktop = new DesktopSession(new Canvas(), storage) { TerminalProgramRequested = value => request = value };
        var window = desktop.Open(DesktopApplication.Terminal); Run(desktop, "run App.dll"); desktop.Close(window.Id);
        request!.Output.WriteLine("Late output"); desktop.RefreshTerminalOutput(window.Id);
        Assert.Empty(desktop.Windows);
    }

    [Fact]
    public void CaretBlinksAndLongInputStaysInsideTheTerminalAfterResize()
    {
        var canvas = new Canvas(); long now = 0;
        var desktop = new DesktopSession(canvas, new MemoryWorkspace(false), monotonicMilliseconds: () => now);
        var window = desktop.Open(DesktopApplication.Terminal); desktop.Render(); Assert.True(canvas.HasTerminalCaret(window));
        now = 500; desktop.AdvanceFeedback(now); canvas.Clear(); desktop.Render(); Assert.False(canvas.HasTerminalCaret(window));
        now = 1000; desktop.AdvanceFeedback(now); canvas.Clear(); desktop.Render(); Assert.True(canvas.HasTerminalCaret(window));
        desktop.PasteTerminalInput(new string('a', 200));
        var original = window.Bounds; int x = original.X + original.Width - 5, y = original.Y + original.Height - 5;
        desktop.Pointer(x, y, true); desktop.Pointer(x - 480, y, true); desktop.Pointer(x - 480, y, false);
        canvas.Clear(); desktop.Render(); Assert.True(window.Bounds.Width < original.Width);
        foreach (var item in canvas.Texts.Where(item => item.Y >= window.Bounds.Y + 35 && item.Y < window.Bounds.Y + window.Bounds.Height - 29 && item.X >= window.Bounds.X + 2 && item.X < window.Bounds.X + window.Bounds.Width - 2))
            Assert.True(item.X + canvas.TextWidth(item.Text) <= window.Bounds.X + window.Bounds.Width - 2, item.Text);
        desktop.Key(DesktopKey.Home); desktop.Key(DesktopKey.Character, 'Z'); Assert.StartsWith("Z", window.Shell!.Input);
    }

    [Fact]
    public void RealWheelScrollsCompletedOutputAndTypingReturnsToTheLivePrompt()
    {
        var canvas = new Canvas(); var desktop = new DesktopSession(canvas, new MemoryWorkspace(false)); var window = desktop.Open(DesktopApplication.Terminal);
        for (int index = 0; index < 45; index++) Run(desktop, "echo row" + index);
        desktop.Render(); string tail = canvas.TerminalText(window); Assert.Contains("row44", tail);
        int x = window.Bounds.X + 100, y = window.Bounds.Y + 160;
        desktop.Pointer(x, y, false, wheel: 3); canvas.Clear(); desktop.Render(); string earlier = canvas.TerminalText(window);
        Assert.NotEqual(tail, earlier); Assert.DoesNotContain("row44", earlier);
        desktop.Key(DesktopKey.Character, 'h'); canvas.Clear(); desktop.Render(); Assert.Contains("row44", canvas.TerminalText(window));
    }

    [Fact]
    public void LegacySnapshotOutputRetainsItsAnsiColorsAlongsideTheShell()
    {
        var canvas = new Canvas(); var desktop = new DesktopSession(canvas, new MemoryWorkspace(false));
        var output = new TerminalBuffer(40, 4); output.Write("\u001b[38;2;11;22;33mStyled legacy\u001b[0m\r\n");
        desktop.SetTerminalSnapshot(output.Snapshot()); var window = desktop.ActiveWindow!; desktop.Render();
        Assert.Contains("Styled legacy", canvas.TerminalText(window));
        Assert.Contains(canvas.Texts, item => item.Text == "S" && item.Color == 0x0B1621);
        Run(desktop, "echo usable"); Assert.Contains("usable", string.Concat(window.Terminal!.Cells.Select(cell => cell.Text)));
    }

    [Theory]
    [InlineData("")]
    [InlineData("\r")]
    public void PartialProgramLinesRemainVisibleAndThePromptAndSubmittedCommandStartOnTheNextRow(string ending)
    {
        var canvas = new Canvas(); var desktop = new DesktopSession(canvas, new MemoryWorkspace(false)); var window = desktop.Open(DesktopApplication.Terminal);
        desktop.WriteTerminalOutput("\u001b[38;2;1;2;3mpartial" + ending + "\u001b[0m", window.Id); desktop.Render();
        int outputY = canvas.Texts.First(item => item.Color == 0x010203).Y;
        var prompt = canvas.Texts.Last(item => item.Text.EndsWith("> ", StringComparison.Ordinal));
        Assert.Equal(outputY + 20, prompt.Y);
        Run(desktop, "echo next");
        var frame = window.Terminal!;
        string previous = string.Concat(Enumerable.Range(0, frame.Columns).Select(col => frame.GetCell(col, 3).Text));
        string command = string.Concat(Enumerable.Range(0, frame.Columns).Select(col => frame.GetCell(col, 4).Text));
        Assert.StartsWith("partial", previous); Assert.DoesNotContain("> ", previous); Assert.Contains("> echo next", command);
    }

    private static void Run(DesktopSession desktop, string command)
    { Assert.True(desktop.PasteTerminalInput(command)); desktop.Key(DesktopKey.Enter); }

    private sealed class Canvas : IDesktopCanvas
    {
        public int Width => 1280; public int Height => 800;
        public readonly List<(string Text, uint Color, int X, int Y)> Texts = [];
        public readonly List<(uint Color, int X, int Y, int Width, int Height)> Fills = [];
        public int TextWidth(string text) => text.EnumerateRunes().Sum(rune => rune.Value > 255 ? 16 : 8);
        public void Fill(uint rgb, int x, int y, int width, int height) => Fills.Add((rgb, x, y, width, 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) => Texts.Add((text, rgb, x, y));
        public void Present() { }
        public void Clear() { Texts.Clear(); Fills.Clear(); }
        public string TerminalText(DesktopWindow window)
        {
            var result = new StringBuilder();
            foreach (var row in Texts.Where(item => item.Y >= window.Bounds.Y + 35 && item.Y < window.Bounds.Y + window.Bounds.Height - 29 && item.X >= window.Bounds.X + 2 && item.X < window.Bounds.X + window.Bounds.Width - 2)
                .GroupBy(item => item.Y).OrderBy(row => row.Key))
            {
                int right = row.Min(item => item.X);
                foreach (var item in row.OrderBy(item => item.X))
                {
                    if (item.X - right >= 8) result.Append(' ', (item.X - right) / 8);
                    result.Append(item.Text); right = item.X + TextWidth(item.Text);
                }
                result.AppendLine();
            }
            return result.ToString();
        }
        public bool HasTerminalCaret(DesktopWindow window) => Fills.Any(item => item.Color == 0x75C9F5 && item.Width == 2 && item.Height == 16 && item.Y >= window.Bounds.Y + 35);
    }
}