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);
}
}
}
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);
}
}
}