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

XFESystem

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

公开
关注 0 Fork 0 Star 0
UTF-8
namespace XFESystem.Browser.Tests;

public sealed class BrowserEventLoopTests
{
    [Fact]
    public void TimersWaitForExplicitMonotonicPumpAndCancellationWorks()
    {
        var runtime = new JavaScriptRuntime();
        Assert.True(runtime.Evaluate("var values=[];setTimeout((a,b)=>values.push(a+b),10,20,22);const gone=setTimeout(()=>values.push(99),0);clearTimeout(gone);").Success);
        Assert.True(runtime.Pump(9).Success); Assert.Equal("", runtime.Evaluate("values.join(',')").Value);
        Assert.True(runtime.Pump(10).Success); Assert.Equal("42", runtime.Evaluate("values.join(',')").Value); Assert.Equal(0, runtime.PendingTaskCount);
    }

    [Fact]
    public void IntervalsDoNotCatchUpInUnboundedLoopsAndCanCancelThemselves()
    {
        var runtime = new JavaScriptRuntime();
        runtime.Evaluate("var ticks=0;var timer=setInterval(()=>{if(++ticks===2)clearInterval(timer);},1)");
        runtime.Pump(1_000); Assert.Equal("1", runtime.Evaluate("ticks").Value);
        runtime.Pump(1_000); Assert.Equal("1", runtime.Evaluate("ticks").Value);
        runtime.Pump(1_001); Assert.Equal("2", runtime.Evaluate("ticks").Value); Assert.Equal(0, runtime.PendingTaskCount);
    }

    [Fact]
    public void RafRecursionWaitsForNextFrameAndReceivesMonotonicTime()
    {
        var runtime = new JavaScriptRuntime(); runtime.Evaluate("var frames=[];function frame(t){frames.push(t);requestAnimationFrame(frame);}requestAnimationFrame(frame)");
        runtime.Pump(15); Assert.Equal("15", runtime.Evaluate("frames.join(',')").Value);
        runtime.Pump(14); Assert.Equal("15", runtime.Evaluate("frames.join(',')").Value);
        runtime.Pump(16); Assert.Equal("15,16", runtime.Evaluate("frames.join(',')").Value);
    }

    [Fact]
    public void RealPromiseAndQueueMicrotaskOrderPrecedesTimers()
    {
        var runtime = new JavaScriptRuntime(); var result = runtime.Evaluate("var order=[];setTimeout(()=>order.push('timer'),0);Promise.resolve().then(()=>order.push('promise'));queueMicrotask(()=>order.push('micro'));order.push('sync');");
        Assert.True(result.Success, result.Error); Assert.Equal("sync,promise,micro", runtime.Evaluate("order.join(',')").Value);
        runtime.Pump(0); Assert.Equal("sync,promise,micro,timer", runtime.Evaluate("order.join(',')").Value);
    }

    [Fact]
    public void CallbackCountQueueSizeAndCallbackExecutionAreBounded()
    {
        var runtime = new JavaScriptRuntime(new() { MaximumPendingTasks = 4, MaximumEventCallbacksPerPump = 2, MaximumStatements = 100 });
        Assert.True(runtime.Evaluate("var count=0;for(let i=0;i<4;i++)setTimeout(()=>++count,0)").Success);
        Assert.False(runtime.Evaluate("setTimeout(()=>{},0)").Success);
        runtime.Pump(0); Assert.Equal("2", runtime.Evaluate("count").Value); Assert.Equal(2, runtime.PendingTaskCount);
        runtime.Pump(0); Assert.Equal("4", runtime.Evaluate("count").Value);
        runtime.Evaluate("setTimeout(()=>{while(true){}},0)"); Assert.False(runtime.Pump(0).Success);
        Assert.Equal("42", runtime.Evaluate("6*7").Value);
    }

    [Fact]
    public void StringTimerSourcesAreRejectedAndClockCannotRegress()
    {
        var runtime = new JavaScriptRuntime(); Assert.False(runtime.Evaluate("setTimeout('alert(1)',0)").Success);
        runtime.Pump(100); runtime.Pump(2); Assert.Equal("100", runtime.Evaluate("performance.now()").Value);
    }

    [Fact]
    public void BoundAndProxyFunctionsAreLegitimateTimerCallbacks()
    {
        var runtime = new JavaScriptRuntime();
        var result = runtime.Evaluate("var values=[];setTimeout(function(x){values.push(this.base+x)}.bind({base:40},2),0);setTimeout(new Proxy(()=>values.push(43),{}),0)");
        Assert.True(result.Success, result.Error); Assert.True(runtime.Pump(0).Success);
        Assert.Equal("42,43", runtime.Evaluate("values.join(',')").Value);
    }

    [Fact]
    public void PerformanceMarksAndMeasuresReflectActualPumpedTimeAndCanBeCleared()
    {
        var runtime = new JavaScriptRuntime(); Assert.True(runtime.Evaluate("performance.mark('start')").Success); runtime.Pump(25);
        var result = runtime.Evaluate("performance.mark('end');performance.measure('elapsed','start','end');performance.getEntriesByType('measure')[0].duration");
        Assert.True(result.Success, result.Error); Assert.Equal("25", result.Value);
        Assert.Equal("2", runtime.Evaluate("performance.getEntriesByType('mark').length").Value);
        runtime.Evaluate("performance.clearMarks('start');performance.clearMeasures();");
        Assert.Equal("1", runtime.Evaluate("performance.getEntries().length").Value);
        Assert.False(runtime.Evaluate("performance.measure('bad','unknown')").Success);
    }

    [Fact]
    public void PerformanceBufferRetainsBoundedRecentEntriesAndReportsEviction()
    {
        var runtime = new JavaScriptRuntime(new() { MaximumPendingTasks = 4 });
        var result = runtime.Evaluate("for(let i=0;i<10;i++)performance.mark('mark'+i);[performance.getEntries().length,performance.droppedEntriesCount,performance.getEntries()[0].name].join(':')");
        Assert.True(result.Success, result.Error); Assert.Equal("4:6:mark6", result.Value);
    }
}