using AngleSharp.Html.Parser;
using XFESystem.Browser;
namespace XFESystem.Kernel;
/// <summary>Same code is run on the guest: reports actual JavaScript/host identity and dispatch results.</summary>
public static class BrowserNativeEventRegression
{
public static bool Run(BrowserService browser, Action<string> log)
{
var passed = true;
void Stage(string name, string actual, string expected)
{
var ok = actual == expected; passed &= ok;
log("XFE_BROWSER_EVENT_REGRESSION|" + name + "|" + (ok ? "PASS" : "FAIL") + "|" + actual.Replace('\r', ' ').Replace('\n', ' ') + "\n");
}
string Page(string source) => browser.ExecuteJavaScript(source);
try
{
Stage("WeakMapPlainSameEval", Page("var __xfeRegKey={},__xfeRegWeak=new WeakMap();__xfeRegWeak.set(__xfeRegKey,42);__xfeRegWeak.has(__xfeRegKey)+':'+__xfeRegWeak.get(__xfeRegKey)"), "true:42");
Stage("WeakMapPlainCrossEval", Page("__xfeRegWeak.has(__xfeRegKey)+':'+__xfeRegWeak.get(__xfeRegKey)"), "true:42");
Stage("WeakMapHostSameEval", Page("var __xfeRegBody=document.body,__xfeRegHostWeak=new WeakMap();__xfeRegHostWeak.set(__xfeRegBody,43);__xfeRegHostWeak.has(document.body)+':'+__xfeRegHostWeak.get(document.body)+':'+(__xfeRegBody===document.body)"), "true:43:true");
Stage("WeakMapHostCrossEval", Page("__xfeRegHostWeak.has(document.body)+':'+__xfeRegHostWeak.get(document.body)+':'+(__xfeRegBody===document.body)"), "true:43:true");
Stage("PlainEventTargetSameEval", Page("var __xfeRegCount=0,__xfeRegTarget=new EventTarget();__xfeRegTarget.addEventListener('xfe-test',()=>++__xfeRegCount);__xfeRegTarget.dispatchEvent(new Event('xfe-test'));__xfeRegCount"), "1");
Stage("PlainEventTargetCrossEval", Page("__xfeRegTarget.dispatchEvent(new Event('xfe-test'));__xfeRegCount"), "2");
Stage("HostEventSameEval", Page("var __xfeRegButton=document.createElement('button');__xfeRegButton.id='XfeNativeEventRegression';document.body.appendChild(__xfeRegButton);var __xfeRegButtonCount=0;__xfeRegButton.addEventListener('click',()=>{++__xfeRegButtonCount;__xfeRegButton.textContent='clicked '+__xfeRegButtonCount;});__xfeRegButton.dispatchEvent(new Event('click'));__xfeRegButtonCount+':'+__xfeRegButton.textContent"), "1:clicked 1");
Stage("HostEventCrossEval", Page("document.getElementById('XfeNativeEventRegression').dispatchEvent(new Event('click'));__xfeRegButtonCount+':'+__xfeRegButton.textContent"), "2:clicked 2");
Stage("HostClickMethodCrossEval", Page("document.getElementById('XfeNativeEventRegression').click();__xfeRegButtonCount+':'+__xfeRegButton.textContent"), "3:clicked 3");
Stage("HostListenerReceiver", Page("var __xfeRegSameReceiver=false;__xfeRegButton.addEventListener('receiver',function(e){__xfeRegSameReceiver=this===__xfeRegButton&&e.target===this;});__xfeRegButton.dispatchEvent(new Event('receiver'));__xfeRegSameReceiver"), "true");
Page("__xfeRegButton.remove()");
}
catch (Exception error) { passed = false; log("XFE_BROWSER_EVENT_REGRESSION|PageException|FAIL|" + error.Message + "\n"); }
try
{
var limits = new BrowserLimits(); var runtime = new JavaScriptRuntime(limits);
var document = new HtmlParser().ParseDocument("<button id='Button'>Before</button>"); var mutations = 0;
var dom = new DomBridge(runtime, document, new Uri("http://xfe.test/Regression"), limits, new() { Mutated = () => ++mutations });
Stage("BridgeSetup", runtime.Evaluate("var count=0;var button=document.getElementById('Button');button.addEventListener('click',()=>{++count;button.textContent='clicked '+count;});'ready'").Text, "ready");
Stage("BridgeCrossCSharpAllowed", dom.DispatchEvent(document.GetElementById("Button"), "click").ToString(), "True");
Stage("BridgeCrossCSharpMutation", runtime.Evaluate("count+':'+document.getElementById('Button').textContent").Text, "1:clicked 1");
Stage("BridgeMutationCallback", mutations.ToString(), "1");
Stage("BridgeWeakMapIdentity", runtime.Evaluate("var weak=new WeakMap();weak.set(button,44);weak.get(document.getElementById('Button'))+':'+weak.has(button)").Text, "44:true");
Stage("BridgeSecondCSharpAllowed", dom.DispatchEvent(document.GetElementById("Button"), "click").ToString(), "True");
Stage("BridgeSecondCSharpMutation", runtime.Evaluate("count+':'+button.textContent").Text, "2:clicked 2");
Stage("BridgeEventErrorVisible", runtime.Evaluate("var afterError=0;button.addEventListener('error-probe',()=>{throw Error('NativeEventErrorVisible');});button.addEventListener('error-probe',()=>++afterError);'ready'").Text, "ready");
dom.DispatchEvent(document.GetElementById("Button"), "error-probe");
Stage("BridgeErrorConsole", runtime.DrainConsoleOutput().Contains("NativeEventErrorVisible", StringComparison.Ordinal).ToString(), "True");
Stage("BridgeAfterErrorListener", runtime.Evaluate("afterError").Text, "1");
Stage("BridgeAfterErrorLexicalScope", runtime.Evaluate("function outer(){const value=21;try{(()=>{throw Error('scope')})()}catch(error){return (()=>value*2)()}}outer()").Text, "42");
}
catch (Exception error) { passed = false; log("XFE_BROWSER_EVENT_REGRESSION|BridgeException|FAIL|" + error.Message + "\n"); }
log("XFE_BROWSER_EVENT_REGRESSION|Complete|" + (passed ? "PASS" : "FAIL") + "\n");
return passed;
}
}
using AngleSharp.Html.Parser;
using XFESystem.Browser;
namespace XFESystem.Kernel;
/// <summary>Same code is run on the guest: reports actual JavaScript/host identity and dispatch results.</summary>
public static class BrowserNativeEventRegression
{
public static bool Run(BrowserService browser, Action<string> log)
{
var passed = true;
void Stage(string name, string actual, string expected)
{
var ok = actual == expected; passed &= ok;
log("XFE_BROWSER_EVENT_REGRESSION|" + name + "|" + (ok ? "PASS" : "FAIL") + "|" + actual.Replace('\r', ' ').Replace('\n', ' ') + "\n");
}
string Page(string source) => browser.ExecuteJavaScript(source);
try
{
Stage("WeakMapPlainSameEval", Page("var __xfeRegKey={},__xfeRegWeak=new WeakMap();__xfeRegWeak.set(__xfeRegKey,42);__xfeRegWeak.has(__xfeRegKey)+':'+__xfeRegWeak.get(__xfeRegKey)"), "true:42");
Stage("WeakMapPlainCrossEval", Page("__xfeRegWeak.has(__xfeRegKey)+':'+__xfeRegWeak.get(__xfeRegKey)"), "true:42");
Stage("WeakMapHostSameEval", Page("var __xfeRegBody=document.body,__xfeRegHostWeak=new WeakMap();__xfeRegHostWeak.set(__xfeRegBody,43);__xfeRegHostWeak.has(document.body)+':'+__xfeRegHostWeak.get(document.body)+':'+(__xfeRegBody===document.body)"), "true:43:true");
Stage("WeakMapHostCrossEval", Page("__xfeRegHostWeak.has(document.body)+':'+__xfeRegHostWeak.get(document.body)+':'+(__xfeRegBody===document.body)"), "true:43:true");
Stage("PlainEventTargetSameEval", Page("var __xfeRegCount=0,__xfeRegTarget=new EventTarget();__xfeRegTarget.addEventListener('xfe-test',()=>++__xfeRegCount);__xfeRegTarget.dispatchEvent(new Event('xfe-test'));__xfeRegCount"), "1");
Stage("PlainEventTargetCrossEval", Page("__xfeRegTarget.dispatchEvent(new Event('xfe-test'));__xfeRegCount"), "2");
Stage("HostEventSameEval", Page("var __xfeRegButton=document.createElement('button');__xfeRegButton.id='XfeNativeEventRegression';document.body.appendChild(__xfeRegButton);var __xfeRegButtonCount=0;__xfeRegButton.addEventListener('click',()=>{++__xfeRegButtonCount;__xfeRegButton.textContent='clicked '+__xfeRegButtonCount;});__xfeRegButton.dispatchEvent(new Event('click'));__xfeRegButtonCount+':'+__xfeRegButton.textContent"), "1:clicked 1");
Stage("HostEventCrossEval", Page("document.getElementById('XfeNativeEventRegression').dispatchEvent(new Event('click'));__xfeRegButtonCount+':'+__xfeRegButton.textContent"), "2:clicked 2");
Stage("HostClickMethodCrossEval", Page("document.getElementById('XfeNativeEventRegression').click();__xfeRegButtonCount+':'+__xfeRegButton.textContent"), "3:clicked 3");
Stage("HostListenerReceiver", Page("var __xfeRegSameReceiver=false;__xfeRegButton.addEventListener('receiver',function(e){__xfeRegSameReceiver=this===__xfeRegButton&&e.target===this;});__xfeRegButton.dispatchEvent(new Event('receiver'));__xfeRegSameReceiver"), "true");
Page("__xfeRegButton.remove()");
}
catch (Exception error) { passed = false; log("XFE_BROWSER_EVENT_REGRESSION|PageException|FAIL|" + error.Message + "\n"); }
try
{
var limits = new BrowserLimits(); var runtime = new JavaScriptRuntime(limits);
var document = new HtmlParser().ParseDocument("<button id='Button'>Before</button>"); var mutations = 0;
var dom = new DomBridge(runtime, document, new Uri("http://xfe.test/Regression"), limits, new() { Mutated = () => ++mutations });
Stage("BridgeSetup", runtime.Evaluate("var count=0;var button=document.getElementById('Button');button.addEventListener('click',()=>{++count;button.textContent='clicked '+count;});'ready'").Text, "ready");
Stage("BridgeCrossCSharpAllowed", dom.DispatchEvent(document.GetElementById("Button"), "click").ToString(), "True");
Stage("BridgeCrossCSharpMutation", runtime.Evaluate("count+':'+document.getElementById('Button').textContent").Text, "1:clicked 1");
Stage("BridgeMutationCallback", mutations.ToString(), "1");
Stage("BridgeWeakMapIdentity", runtime.Evaluate("var weak=new WeakMap();weak.set(button,44);weak.get(document.getElementById('Button'))+':'+weak.has(button)").Text, "44:true");
Stage("BridgeSecondCSharpAllowed", dom.DispatchEvent(document.GetElementById("Button"), "click").ToString(), "True");
Stage("BridgeSecondCSharpMutation", runtime.Evaluate("count+':'+button.textContent").Text, "2:clicked 2");
Stage("BridgeEventErrorVisible", runtime.Evaluate("var afterError=0;button.addEventListener('error-probe',()=>{throw Error('NativeEventErrorVisible');});button.addEventListener('error-probe',()=>++afterError);'ready'").Text, "ready");
dom.DispatchEvent(document.GetElementById("Button"), "error-probe");
Stage("BridgeErrorConsole", runtime.DrainConsoleOutput().Contains("NativeEventErrorVisible", StringComparison.Ordinal).ToString(), "True");
Stage("BridgeAfterErrorListener", runtime.Evaluate("afterError").Text, "1");
Stage("BridgeAfterErrorLexicalScope", runtime.Evaluate("function outer(){const value=21;try{(()=>{throw Error('scope')})()}catch(error){return (()=>value*2)()}}outer()").Text, "42");
}
catch (Exception error) { passed = false; log("XFE_BROWSER_EVENT_REGRESSION|BridgeException|FAIL|" + error.Message + "\n"); }
log("XFE_BROWSER_EVENT_REGRESSION|Complete|" + (passed ? "PASS" : "FAIL") + "\n");
return passed;
}
}