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

XFESystem

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

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

namespace XFESystem.Browser.Tests;

public sealed class NativeScriptAdmissionTests
{
    private const int NativeExternalResourceCharacters = 2_500_000;
    private static BrowserLimits NativeLimits => new() { MaximumExternalResourceCharacters = NativeExternalResourceCharacters };

    [Fact]
    public void NativeResourceLimitSurvivesCloneAndTrustedProfileWithoutPoisoningThePage()
    {
        var trace = new StringBuilder();
        var factory = new BrowserService(limits: NativeLimits, resources: new AdmissionResources()) { Trace = value => trace.Append(value) };
        var page = Assert.IsType<BrowserService>(factory.CreatePageSession());
        try
        {
            page.ResizeViewport(796, 404);
            page.NavigateDocument("# Resource admission\n\n" + string.Concat(Enumerable.Repeat("A readable paragraph.\n\n", 80)), "Admission.md");
            long prepared = page.PackagedScriptPreparations, reused = page.PackagedScriptCacheHits;
            // This is the same trusted-document execution profile as the
            // native preview. Its raised JS limit must not raise fetch limits.
            page.ExecuteJavaScript("""
                globalThis.rejectedDependency=false;globalThis.followingDependency=false;
                const denied=document.createElement('script');denied.src='/OversizedAdmission.js';
                denied.addEventListener('error',()=>{rejectedDependency=true;});document.head.appendChild(denied);
                const following=document.createElement('script');following.src='/FollowingAdmission.js';document.head.appendChild(following);
                """);
            Assert.Equal("true", page.ExecuteJavaScript("rejectedDependency && followingDependency && typeof oversizedDependency==='undefined'"));
            Assert.Equal(prepared, page.PackagedScriptPreparations);
            Assert.Equal(reused, page.PackagedScriptCacheHits);
            Assert.DoesNotContain(page.LoadedResources, resource => resource.Address.EndsWith("/OversizedAdmission.js", StringComparison.Ordinal));
            Assert.Contains(page.LoadedResources, resource => resource.Address.EndsWith("/FollowingAdmission.js", StringComparison.Ordinal));
            Assert.Contains("XFE_BROWSER_SCRIPT_REJECTED|/OversizedAdmission.js|Reason|ResourceBudget\n", trace.ToString(), StringComparison.Ordinal);
            Assert.DoesNotContain("XFE_BROWSER_SCRIPT_BEGIN|/OversizedAdmission.js|", trace.ToString(), StringComparison.Ordinal);

            page.AdvanceTime(1000); page.AdvanceTime(1020);
            double before = ReadProgress(page);
            page.ScrollBackgroundDocument(360); page.AdvanceTime(2000); page.AdvanceTime(2020);
            Assert.Equal(360, page.BackgroundViewport.ScrollY);
            Assert.True(page.Layout(new(796, 404, 0, 360)).GetBoundingClientRect(page.Document!.QuerySelector(".docs-article")!).Y < -30);
            Assert.True(ReadProgress(page) > before);
            Assert.Equal("42", page.ExecuteJavaScript("6*7"));
        }
        finally { page.Release(); factory.Release(); }
    }

    [Fact]
    public void OversizedRealMermaidUsesOriginalWebsiteErrorAndSourceFallback()
    {
        var trace = new StringBuilder();
        var page = new BrowserService(limits: NativeLimits) { Trace = value => trace.Append(value) };
        try
        {
            page.ResizeViewport(796, 404);
            page.NavigateDocument("# Mermaid admission\n\n```mermaid\ngraph TD\n  A-->B\n```", "Mermaid.md");
            for (int time = 0; time <= 200; time += 20) page.AdvanceTime(time);
            var wrapper = Assert.Single(page.Document!.QuerySelectorAll(".mermaid-wrapper"));
            Assert.True(wrapper.ClassList.Contains("is-error"));
            Assert.Equal("图表组件加载失败,已显示原始内容", wrapper.QuerySelector(".mermaid-error-title")!.TextContent);
            Assert.Contains("graph TD", wrapper.QuerySelector(".mermaid-source code")!.TextContent, StringComparison.Ordinal);
            Assert.Empty(wrapper.QuerySelectorAll("svg"));
            Assert.Equal("undefined", page.ExecuteJavaScript("typeof mermaid"));
            Assert.Contains("XFE_BROWSER_SCRIPT_REJECTED|/js/docs/mermaid.min.js?v=11.16.0|Reason|ResourceBudget\n", trace.ToString(), StringComparison.Ordinal);
            Assert.DoesNotContain("XFE_BROWSER_SCRIPT_BEGIN|/js/docs/mermaid.min.js", trace.ToString(), StringComparison.Ordinal);
            Assert.Equal("42", page.ExecuteJavaScript("6*7"));
        }
        finally { page.Release(); }
    }

    [Fact]
    public void NativeAdmissionAllowsActualMonacoCoreButRejectsActualLargerMermaidBeforeEvaluation()
    {
        var resources = new PackagedBrowserResources();
        var address = new Uri(PackagedBrowserResources.MonacoCoreRoot + "EditorCore.js");
        var loader = new BrowserResourceLoader(new UnavailableWebTransport(), resources, new(PackagedBrowserResources.MonacoPageAddress), NativeLimits);
        var core = loader.Get(address, "script");
        Assert.Equal(2_293_601, core.Body.Length);
        Assert.True(core.Body.Length <= NativeExternalResourceCharacters);
        Assert.True(WebsiteAssets.ReadText("Exact/Mermaid.min.js").Length > NativeExternalResourceCharacters);
        Assert.Throws<BrowserLimitException>(() => loader.Get(new(PackagedBrowserResources.Origin + "/js/docs/mermaid.min.js?v=11.16.0"), "script"));
        Assert.Single(loader.Receipts);
    }

    private static double ReadProgress(BrowserService page) => double.Parse(
        page.ExecuteJavaScript("parseFloat(document.querySelector('[data-doc-progress]').style.width)"),
        System.Globalization.CultureInfo.InvariantCulture);

    private sealed class AdmissionResources : IBrowserResourceSource
    {
        private readonly PackagedBrowserResources packaged = new();
        private readonly string oversized = "globalThis.oversizedDependency=true;" + new string(' ', NativeExternalResourceCharacters);
        public bool TryGet(Uri address, out WebResponse response)
        {
            if (address.GetLeftPart(UriPartial.Authority) == PackagedBrowserResources.Origin)
            {
                if (address.AbsolutePath == "/OversizedAdmission.js")
                { response = new(address, 200, "application/javascript", oversized); return true; }
                if (address.AbsolutePath == "/FollowingAdmission.js")
                { response = new(address, 200, "application/javascript", "followingDependency=true;"); return true; }
            }
            return packaged.TryGet(address, out response);
        }
    }
}