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

XFESystem

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

公开
关注 0 Fork 0 Star 0
UTF-8
using AngleSharp.Dom;
using XFESystem.Desktop;
using System.Text.Json;

namespace XFESystem.Browser.Tests;

public sealed class DocumentFirstPaintTests
{
    private const string Source = "# Actual source heading\n\nA real **document paragraph**.\n\n```csharp\nConsole.WriteLine(42);\n```";

    [Fact]
    public void FirstDocumentContainsSanitizedSourceAndAllOriginalStylesBeforeAnyScript()
    {
        var browser = new BrowserService();
        var page = browser.BeginDocumentPreview(Source + "\n\n<script>document.title='Forbidden'</script>", "First.md");
        Assert.Equal("First.md", page.Title);
        Assert.Contains("Actual source heading", page.Text, StringComparison.Ordinal);
        Assert.Contains("document paragraph", page.Text, StringComparison.Ordinal);
        Assert.DoesNotContain("Forbidden", page.Text, StringComparison.Ordinal);
        Assert.Equal(9, browser.LoadedResources.Count(resource => resource.Kind == "style"));
        Assert.DoesNotContain(browser.LoadedResources, resource => resource.Kind == "script");
        var list = browser.Layout(new(796, 404));
        Assert.Contains(list.Commands, command => command.Kind == BrowserDrawKind.Text && command.Text.Contains("Actual", StringComparison.Ordinal));
        Assert.True(browser.DocumentEnhancementsPending);
        Assert.False(browser.DocumentFirstFramePresented);
    }

    [Fact]
    public void AdvancingOrFinishingRasterWithoutPresentationCannotStartScripts()
    {
        var browser = new BrowserService(); browser.BeginDocumentPreview(Source, "First.md");
        browser.AdvanceTime(20);
        browser.Paint(new Canvas(), new(0, 0, 796, 404), 0);
        browser.AdvanceTime(40);
        Assert.DoesNotContain(browser.LoadedResources, resource => resource.Kind == "script");
        Assert.False(browser.DocumentFirstFramePresented);
        browser.FramePresented();
        Assert.True(browser.DocumentFirstFramePresented);
        // Runtime construction is its own phase. The first original script
        // cannot share that phase, and no source or script bytes are removed.
        browser.AdvanceTime(60);
        Assert.DoesNotContain(browser.LoadedResources, resource => resource.Kind == "script");
        Assert.Equal("{}", browser.ReadWebsiteDocumentProof()); // No expensive/incomplete JS proof during staged loading.
        long revision = browser.Revision;
        browser.AdvanceTime(80);
        Assert.Single(browser.LoadedResources, resource => resource.Kind == "script");
        Assert.Equal(revision, browser.Revision); // Pure highlight.js library does not repaint.
    }

    [Fact]
    public void FirstPresentationTraceRequiresRealPaintAndDoesNotIncludeAuthorScriptExecution()
    {
        var lines = new List<string>(); var browser = new BrowserService { Trace = lines.Add };
        browser.BeginDocumentPreview(Source, "First.md");
        browser.FramePresented();
        Assert.DoesNotContain(lines, line => line.StartsWith("XFE_DOCUMENT_FIRST_PRESENTED", StringComparison.Ordinal));
        browser.Paint(new Canvas(), new(0, 0, 796, 404), 0);
        browser.FramePresented(); browser.FramePresented();
        var trace = Assert.Single(lines, line => line.StartsWith("XFE_DOCUMENT_FIRST_PRESENTED", StringComparison.Ordinal));
        Assert.Contains("|OriginalStyles|9|ExecutedScripts|0", trace, StringComparison.Ordinal);
        using var proof = JsonDocument.Parse(browser.ReadDocumentFirstPaintProof());
        Assert.Equal("ActualNativeFirstDocumentPaint", proof.RootElement.GetProperty("Kind").GetString());
        Assert.Equal(0, proof.RootElement.GetProperty("ExecutedScriptCount").GetInt32());
        Assert.Equal(Source.Length, proof.RootElement.GetProperty("SourceCharacters").GetInt32());
        Assert.Equal("Actual source heading", proof.RootElement.GetProperty("Heading").GetProperty("Text").GetString());
        Assert.True(proof.RootElement.GetProperty("Heading").GetProperty("Runs").GetArrayLength() > 0);
        long revision = browser.Revision;
        Assert.Equal(browser.ReadDocumentFirstPaintProof(), browser.ReadDocumentFirstPaintProof());
        Assert.Equal(revision, browser.Revision);
    }

    [Fact]
    public void OriginalScriptsRunInOrderAndEventuallyProduceTheSameHighlightedDocument()
    {
        var synchronous = new BrowserService(); synchronous.NavigateDocument(Source, "First.md");
        for (int i = 1; i <= 4; i++) synchronous.AdvanceTime(i * 20);
        var staged = new BrowserService(); staged.BeginDocumentPreview(Source, "First.md");
        staged.Paint(new Canvas(), new(0, 0, 796, 404), 0); staged.FramePresented();
        for (int i = 1; i <= 64; i++)
        {
            int scripts = staged.LoadedResources.Count(resource => resource.Kind == "script");
            staged.AdvanceTime(i * 20);
            Assert.InRange(staged.LoadedResources.Count(resource => resource.Kind == "script") - scripts, 0, 1);
        }
        Assert.False(staged.DocumentEnhancementsPending);
        Assert.Equal(synchronous.LoadedResources.Where(resource => resource.Kind == "script").Select(resource => resource.Address),
            staged.LoadedResources.Where(resource => resource.Kind == "script").Select(resource => resource.Address));
        Assert.Equal(synchronous.Document!.QuerySelector(".markdown-body")!.OuterHtml,
            staged.Document!.QuerySelector(".markdown-body")!.OuterHtml);
        Assert.DoesNotContain("JavaScript error:", staged.CurrentPage.Text, StringComparison.Ordinal);
        Assert.Equal("complete", staged.ExecuteJavaScript("document.readyState"));
    }

    [Fact]
    public void NavigatingAwayCancelsAllOldDeferredScriptsAndKeepsNewRuntimeIsolation()
    {
        var browser = new BrowserService(); browser.BeginDocumentPreview(Source, "First.md");
        browser.Navigate("about:Start");
        browser.FramePresented(); browser.AdvanceTime(20);
        Assert.False(browser.DocumentEnhancementsPending);
        Assert.False(browser.DocumentFirstFramePresented);
        Assert.Empty(browser.LoadedResources);
        Assert.Equal("undefined", browser.ExecuteJavaScript("typeof hljs"));
        Assert.Equal("XFESystem Browser", browser.CurrentPage.Title);
    }

    [Fact]
    public void ExplicitScriptReadbackBeforePresentationDoesNotReplaceThePendingDocument()
    {
        var browser = new BrowserService(); browser.BeginDocumentPreview(Source, "First.md");
        Assert.Equal("First.md", browser.ExecuteJavaScript("document.title"));
        Assert.Contains("Actual source heading", browser.CurrentPage.Text, StringComparison.Ordinal);
        Assert.True(browser.DocumentEnhancementsPending);
        Assert.DoesNotContain(browser.LoadedResources, resource => resource.Kind == "script");
    }

    [Fact]
    public void PixelBindingReadsOnlyThePresentedFrameAndTheStoredProofDoesNotChange()
    {
        var browser = new BrowserService(); var canvas = new PresentedCanvas();
        browser.BeginDocumentPreview(Source, "Pixels.md");
        browser.FramePresented(); Assert.Equal(0, canvas.Reads);
        browser.Paint(canvas, new(0, 0, 796, 404), 0);
        Assert.Equal(0, canvas.Reads); Assert.Equal("{}", browser.ReadDocumentFirstPaintProof());
        browser.FramePresented(); // A notification cannot replace an actual newer presentation.
        Assert.Equal(0, canvas.Reads); Assert.False(browser.DocumentFirstFramePresented);
        canvas.Present(); browser.FramePresented();
        Assert.Equal(2, canvas.Reads);
        string saved = browser.ReadDocumentFirstPaintProof();
        using var proof = JsonDocument.Parse(saved);
        foreach (string name in new[] { "Heading", "Paragraph" })
        {
            var binding = proof.RootElement.GetProperty(name).GetProperty("PresentedPixels");
            Assert.Equal("RGB24-FNV1a64", binding.GetProperty("FingerprintAlgorithm").GetString());
            Assert.Equal(1, binding.GetProperty("PresentationSequence").GetInt64());
            var bounds = binding.GetProperty("NativeBounds");
            Assert.True(DesktopPresentedPixels.TryFingerprint(canvas.Presented, 796, 404, 796,
                new(bounds.GetProperty("X").GetInt32(), bounds.GetProperty("Y").GetInt32(), bounds.GetProperty("Width").GetInt32(), bounds.GetProperty("Height").GetInt32()), 1, out var expected));
            Assert.Equal(expected.Fingerprint, binding.GetProperty("Fingerprint").GetString());
        }
        Array.Fill(canvas.Presented, 0xff00); canvas.Present(); browser.FramePresented();
        Assert.Equal(saved, browser.ReadDocumentFirstPaintProof()); Assert.Equal(2, canvas.Reads);
    }

    private sealed class Canvas : IDesktopCanvas
    {
        public int Width => 796; public int Height => 404;
        public void Fill(uint color, int x, int y, int width, int height) { }
        public void Text(string text, uint color, int x, int y) { }
        public void Line(uint color, int x1, int y1, int x2, int y2) { }
        public void Present() { }
    }

    private sealed class PresentedCanvas : IDesktopCanvas, IDesktopPresentedPixelsCanvas
    {
        public int Width => 796; public int Height => 404;
        public int[] Presented { get; } = new int[796 * 404];
        public long FramesPresented { get; private set; }
        public int Reads;
        public bool TryFingerprintPresentedPixels(DesktopBounds bounds, out DesktopPresentedPixelsFingerprint result)
        { Assert.True(FramesPresented > 0); Reads++; return DesktopPresentedPixels.TryFingerprint(Presented, Width, Height, Width, bounds, FramesPresented, out result); }
        public void Fill(uint color, int x, int y, int width, int height) { }
        public void Text(string text, uint color, int x, int y) { }
        public void Line(uint color, int x1, int y1, int x2, int y2) { }
        public void Present() { FramesPresented++; }
    }
}