public SingleSessionTestBase(string driver = "debugger-driver.html") : base(driver) { insp = new Inspector(); scripts = SubscribeToScripts(insp); }
public async Task InspectValueTypeMethodArgsWhileStepping(bool use_cfo) { var insp = new Inspector(); //Collect events var scripts = SubscribeToScripts(insp); await Ready(); await insp.Ready(async (cli, token) => { ctx = new DebugTestContext(cli, insp, token, scripts); ctx.UseCallFunctionOnBeforeGetProperties = use_cfo; var debugger_test_loc = "dotnet://debugger-test.dll/debugger-valuetypes-test.cs"; await SetBreakpoint(debugger_test_loc, 36, 12); var pause_location = await EvaluateAndCheck( "window.setTimeout(function() { invoke_static_method ('[debugger-test] DebuggerTests.ValueTypesTest:TestStructsAsMethodArgs'); }, 1);", debugger_test_loc, 36, 12, "MethodWithStructArgs"); var locals = await GetProperties(pause_location["callFrames"][0]["callFrameId"].Value <string>()); { Assert.Equal(3, locals.Count()); CheckString(locals, "label", "TestStructsAsMethodArgs#label"); CheckValueType(locals, "ss_arg", "DebuggerTests.ValueTypesTest.SimpleStruct"); CheckNumber(locals, "x", 3); } var dt = new DateTime(2025, 6, 7, 8, 10, 11); var ss_local_as_ss_arg = new { V = TGetter("V"), str_member = TString("ss_local#SimpleStruct#string#0#SimpleStruct#str_member"), dt = TDateTime(dt), gs = TValueType("DebuggerTests.ValueTypesTest.GenericStruct<System.DateTime>"), Kind = TEnum("System.DateTimeKind", "Local") }; var ss_local_gs = new { StringField = TString("ss_local#SimpleStruct#string#0#SimpleStruct#gs#StringField"), List = TObject("System.Collections.Generic.List<System.DateTime>"), Options = TEnum("DebuggerTests.Options", "Option1") }; // Check ss_arg's properties var ss_arg_props = await GetObjectOnFrame(pause_location["callFrames"][0], "ss_arg"); await CheckProps(ss_arg_props, ss_local_as_ss_arg, "ss_arg"); var res = await InvokeGetter(GetAndAssertObjectWithName(locals, "ss_arg"), "V"); await CheckValue(res.Value["result"], TNumber(0xDEADBEEF + (uint)dt.Month), "ss_arg#V"); { // Check ss_local.gs await CompareObjectPropertiesFor(ss_arg_props, "gs", ss_local_gs); } pause_location = await StepAndCheck(StepKind.Over, debugger_test_loc, 40, 8, "MethodWithStructArgs", times: 4, locals_fn: (l) => { /* non-null to make sure that locals get fetched */ }); locals = await GetProperties(pause_location["callFrames"][0]["callFrameId"].Value <string>()); { Assert.Equal(3, locals.Count()); CheckString(locals, "label", "TestStructsAsMethodArgs#label"); CheckValueType(locals, "ss_arg", "DebuggerTests.ValueTypesTest.SimpleStruct"); CheckNumber(locals, "x", 3); } var ss_arg_updated = new { V = TGetter("V"), str_member = TString("ValueTypesTest#MethodWithStructArgs#updated#ss_arg#str_member"), dt = TDateTime(dt), gs = TValueType("DebuggerTests.ValueTypesTest.GenericStruct<System.DateTime>"), Kind = TEnum("System.DateTimeKind", "Utc") }; ss_arg_props = await GetObjectOnFrame(pause_location["callFrames"][0], "ss_arg"); await CheckProps(ss_arg_props, ss_arg_updated, "ss_arg"); res = await InvokeGetter(GetAndAssertObjectWithName(locals, "ss_arg"), "V"); await CheckValue(res.Value["result"], TNumber(0xDEADBEEF + (uint)dt.Month), "ss_arg#V"); { // Check ss_local.gs await CompareObjectPropertiesFor(ss_arg_props, "gs", new { StringField = TString("ValueTypesTest#MethodWithStructArgs#updated#gs#StringField#3"), List = TObject("System.Collections.Generic.List<System.DateTime>"), Options = TEnum("DebuggerTests.Options", "Option1") }); } // Check locals on previous frame, same as earlier in this test ss_arg_props = await GetObjectOnFrame(pause_location["callFrames"][1], "ss_local"); await CheckProps(ss_arg_props, ss_local_as_ss_arg, "ss_local"); { // Check ss_local.dt await CheckDateTime(ss_arg_props, "dt", dt); // Check ss_local.gs var gs_props = await GetObjectOnLocals(ss_arg_props, "gs"); CheckString(gs_props, "StringField", "ss_local#SimpleStruct#string#0#SimpleStruct#gs#StringField"); CheckObject(gs_props, "List", "System.Collections.Generic.List<System.DateTime>"); } // ----------- Step back to the caller --------- pause_location = await StepAndCheck(StepKind.Over, debugger_test_loc, 30, 12, "TestStructsAsMethodArgs", times: 2, locals_fn: (l) => { /* non-null to make sure that locals get fetched */ }); locals = await GetProperties(pause_location["callFrames"][0]["callFrameId"].Value <string>()); await CheckProps(locals, new { ss_local = TValueType("DebuggerTests.ValueTypesTest.SimpleStruct"), ss_ret = TValueType("DebuggerTests.ValueTypesTest.SimpleStruct") }, "locals#0"); ss_arg_props = await GetObjectOnFrame(pause_location["callFrames"][0], "ss_local"); await CheckProps(ss_arg_props, ss_local_as_ss_arg, "ss_local"); { // Check ss_local.gs await CompareObjectPropertiesFor(ss_arg_props, "gs", ss_local_gs, label: "ss_local_gs"); } // FIXME: check ss_local.gs.List's members }); }
async Task AssemblyLoadedEventTest(string asm_name, string asm_path, string pdb_path, string source_file, int expected_count) { var insp = new Inspector(); var scripts = SubscribeToScripts(insp); int event_count = 0; var tcs = new TaskCompletionSource <bool>(); insp.On("Debugger.scriptParsed", async(args, c) => { try { var url = args["url"]?.Value <string>(); if (url?.EndsWith(source_file) == true) { event_count++; if (event_count > expected_count) { tcs.SetResult(false); } } } catch (Exception ex) { tcs.SetException(ex); } await Task.CompletedTask; }); await Ready(); await insp.Ready(async (cli, token) => { ctx = new DebugTestContext(cli, insp, token, scripts); byte[] bytes = File.ReadAllBytes(asm_path); string asm_base64 = Convert.ToBase64String(bytes); string pdb_base64 = String.Empty; if (pdb_path != null) { bytes = File.ReadAllBytes(pdb_path); pdb_base64 = Convert.ToBase64String(bytes); } var expression = $@"MONO.mono_wasm_raise_debug_event({{ eventName: 'AssemblyLoaded', assembly_name: '{asm_name}', assembly_b64: '{asm_base64}', pdb_b64: '{pdb_base64}' }});"; var res = await ctx.cli.SendCommand($"Runtime.evaluate", JObject.FromObject(new { expression }), ctx.token); Assert.True(res.IsOk, $"Expected to pass for {expression}"); res = await ctx.cli.SendCommand($"Runtime.evaluate", JObject.FromObject(new { expression }), ctx.token); Assert.True(res.IsOk, $"Expected to pass for {expression}"); var t = await Task.WhenAny(tcs.Task, Task.Delay(2000)); if (t.IsFaulted) { throw t.Exception; } Assert.True(event_count <= expected_count, $"number of scriptParsed events received. Expected: {expected_count}, Actual: {event_count}"); }); }
public async Task InspectLocalsDuringSteppingIn() { var insp = new Inspector(); //Collect events var scripts = SubscribeToScripts(insp); await Ready(); await insp.Ready(async (cli, token) => { ctx = new DebugTestContext(cli, insp, token, scripts); await SetBreakpoint("dotnet://debugger-test.dll/debugger-test.cs", 86, 8); await EvaluateAndCheck("window.setTimeout(function() { invoke_outer_method(); }, 1);", "dotnet://debugger-test.dll/debugger-test.cs", 86, 8, "OuterMethod", locals_fn: (locals) => { Assert.Equal(5, locals.Count()); CheckObject(locals, "nim", "Math.NestedInMath"); CheckNumber(locals, "i", 5); CheckNumber(locals, "k", 0); CheckNumber(locals, "new_i", 0); CheckString(locals, "text", null); } ); await StepAndCheck(StepKind.Over, "dotnet://debugger-test.dll/debugger-test.cs", 87, 8, "OuterMethod", locals_fn: (locals) => { Assert.Equal(5, locals.Count()); CheckObject(locals, "nim", "Math.NestedInMath"); // FIXME: Failing test CheckNumber (locals, "i", 5); CheckNumber(locals, "k", 0); CheckNumber(locals, "new_i", 0); CheckString(locals, "text", "Hello"); } ); // Step into InnerMethod await StepAndCheck(StepKind.Into, "dotnet://debugger-test.dll/debugger-test.cs", 105, 8, "InnerMethod"); await StepAndCheck(StepKind.Over, "dotnet://debugger-test.dll/debugger-test.cs", 109, 12, "InnerMethod", times: 5, locals_fn: (locals) => { Assert.Equal(4, locals.Count()); CheckNumber(locals, "i", 5); CheckNumber(locals, "j", 15); CheckString(locals, "foo_str", "foo"); CheckObject(locals, "this", "Math.NestedInMath"); } ); // Step back to OuterMethod await StepAndCheck(StepKind.Over, "dotnet://debugger-test.dll/debugger-test.cs", 88, 8, "OuterMethod", times: 6, locals_fn: (locals) => { Assert.Equal(5, locals.Count()); CheckObject(locals, "nim", "Math.NestedInMath"); // FIXME: Failing test CheckNumber (locals, "i", 5); CheckNumber(locals, "k", 0); CheckNumber(locals, "new_i", 24); CheckString(locals, "text", "Hello"); } ); }); }
public async Task InspectLocalsInAsyncMethods(bool use_cfo) { var insp = new Inspector(); //Collect events var scripts = SubscribeToScripts(insp); await Ready(); await insp.Ready(async (cli, token) => { ctx = new DebugTestContext(cli, insp, token, scripts); ctx.UseCallFunctionOnBeforeGetProperties = use_cfo; var debugger_test_loc = "dotnet://debugger-test.dll/debugger-test.cs"; await SetBreakpoint(debugger_test_loc, 120, 12); await SetBreakpoint(debugger_test_loc, 135, 12); // Will stop in Asyncmethod0 var wait_res = await EvaluateAndCheck( "window.setTimeout(function() { invoke_async_method_with_await(); }, 1);", debugger_test_loc, 120, 12, "MoveNext", //FIXME: locals_fn: (locals) => { Assert.Equal(4, locals.Count()); CheckString(locals, "s", "string from js"); CheckNumber(locals, "i", 42); CheckString(locals, "local0", "value0"); CheckObject(locals, "this", "Math.NestedInMath"); } ); Console.WriteLine(wait_res); #if false // Disabled for now, as we don't have proper async traces var locals = await GetProperties(wait_res["callFrames"][2]["callFrameId"].Value <string>()); Assert.Equal(4, locals.Count()); CheckString(locals, "ls", "string from jstest"); CheckNumber(locals, "li", 52); #endif // TODO: previous frames have async machinery details, so no point checking that right now var pause_loc = await SendCommandAndCheck(null, "Debugger.resume", debugger_test_loc, 135, 12, /*FIXME: "AsyncMethodNoReturn"*/ "MoveNext", locals_fn: (locals) => { Assert.Equal(4, locals.Count()); CheckString(locals, "str", "AsyncMethodNoReturn's local"); CheckObject(locals, "this", "Math.NestedInMath"); //FIXME: check fields CheckValueType(locals, "ss", "Math.SimpleStruct"); CheckArray(locals, "ss_arr", "Math.SimpleStruct[]", 0); // TODO: struct fields } ); var this_props = await GetObjectOnFrame(pause_loc["callFrames"][0], "this"); Assert.Equal(2, this_props.Count()); CheckObject(this_props, "m", "Math"); CheckValueType(this_props, "SimpleStructProperty", "Math.SimpleStruct"); // TODO: Check `this` properties }); }
public async Task InspectLocalsInPreviousFramesDuringSteppingIn(bool use_cfo) { var insp = new Inspector(); //Collect events var scripts = SubscribeToScripts(insp); await Ready(); await insp.Ready(async (cli, token) => { ctx = new DebugTestContext(cli, insp, token, scripts); ctx.UseCallFunctionOnBeforeGetProperties = use_cfo; var debugger_test_loc = "dotnet://debugger-test.dll/debugger-test.cs"; await SetBreakpoint(debugger_test_loc, 111, 12); // Will stop in InnerMethod var wait_res = await EvaluateAndCheck( "window.setTimeout(function() { invoke_outer_method(); }, 1);", debugger_test_loc, 111, 12, "InnerMethod", locals_fn: (locals) => { Assert.Equal(4, locals.Count()); CheckNumber(locals, "i", 5); CheckNumber(locals, "j", 24); CheckString(locals, "foo_str", "foo"); CheckObject(locals, "this", "Math.NestedInMath"); } ); var this_props = await GetObjectOnFrame(wait_res["callFrames"][0], "this"); Assert.Equal(2, this_props.Count()); CheckObject(this_props, "m", "Math"); CheckValueType(this_props, "SimpleStructProperty", "Math.SimpleStruct"); var ss_props = await GetObjectOnLocals(this_props, "SimpleStructProperty"); var dt = new DateTime(2020, 1, 2, 3, 4, 5); await CheckProps(ss_props, new { dt = TDateTime(dt), gs = TValueType("Math.GenericStruct<System.DateTime>") }, "ss_props"); // Check OuterMethod frame var locals_m1 = await GetLocalsForFrame(wait_res["callFrames"][1], debugger_test_loc, 87, 8, "OuterMethod"); Assert.Equal(5, locals_m1.Count()); // FIXME: Failing test CheckNumber (locals_m1, "i", 5); // FIXME: Failing test CheckString (locals_m1, "text", "Hello"); CheckNumber(locals_m1, "new_i", 0); CheckNumber(locals_m1, "k", 0); CheckObject(locals_m1, "nim", "Math.NestedInMath"); // step back into OuterMethod await StepAndCheck(StepKind.Over, debugger_test_loc, 91, 8, "OuterMethod", times: 9, locals_fn: (locals) => { Assert.Equal(5, locals.Count()); // FIXME: Failing test CheckNumber (locals_m1, "i", 5); CheckString(locals, "text", "Hello"); // FIXME: Failing test CheckNumber (locals, "new_i", 24); CheckNumber(locals, "k", 19); CheckObject(locals, "nim", "Math.NestedInMath"); } ); //await StepAndCheck (StepKind.Over, "dotnet://debugger-test.dll/debugger-test.cs", 81, 2, "OuterMethod", times: 2); // step into InnerMethod2 await StepAndCheck(StepKind.Into, "dotnet://debugger-test.dll/debugger-test.cs", 96, 4, "InnerMethod2", locals_fn: (locals) => { Assert.Equal(3, locals.Count()); CheckString(locals, "s", "test string"); //out var: CheckNumber (locals, "k", 0); CheckNumber(locals, "i", 24); } ); await StepAndCheck(StepKind.Over, "dotnet://debugger-test.dll/debugger-test.cs", 100, 4, "InnerMethod2", times: 4, locals_fn: (locals) => { Assert.Equal(3, locals.Count()); CheckString(locals, "s", "test string"); // FIXME: Failing test CheckNumber (locals, "k", 34); CheckNumber(locals, "i", 24); } ); await StepAndCheck(StepKind.Over, "dotnet://debugger-test.dll/debugger-test.cs", 92, 8, "OuterMethod", times: 2, locals_fn: (locals) => { Assert.Equal(5, locals.Count()); CheckString(locals, "text", "Hello"); // FIXME: failing test CheckNumber (locals, "i", 5); CheckNumber(locals, "new_i", 22); CheckNumber(locals, "k", 34); CheckObject(locals, "nim", "Math.NestedInMath"); } ); }); }
public async Task InspectLocalsInPreviousFramesDuringSteppingIn2(bool use_cfo) { var insp = new Inspector(); //Collect events var scripts = SubscribeToScripts(insp); await Ready(); await insp.Ready(async (cli, token) => { ctx = new DebugTestContext(cli, insp, token, scripts); ctx.UseCallFunctionOnBeforeGetProperties = use_cfo; var dep_cs_loc = "dotnet://debugger-test.dll/dependency.cs"; await SetBreakpoint(dep_cs_loc, 33, 8); var debugger_test_loc = "dotnet://debugger-test.dll/debugger-test.cs"; // Will stop in Complex.DoEvenMoreStuff var pause_location = await EvaluateAndCheck( "window.setTimeout(function() { invoke_use_complex (); }, 1);", dep_cs_loc, 33, 8, "DoEvenMoreStuff", locals_fn: (locals) => { Assert.Single(locals); CheckObject(locals, "this", "Simple.Complex"); } ); var props = await GetObjectOnFrame(pause_location["callFrames"][0], "this"); Assert.Equal(3, props.Count()); CheckNumber(props, "A", 10); CheckString(props, "B", "xx"); CheckString(props, "c", "20_xx"); // Check UseComplex frame var locals_m1 = await GetLocalsForFrame(pause_location["callFrames"][3], debugger_test_loc, 23, 8, "UseComplex"); Assert.Equal(7, locals_m1.Count()); CheckNumber(locals_m1, "a", 10); CheckNumber(locals_m1, "b", 20); CheckObject(locals_m1, "complex", "Simple.Complex"); CheckNumber(locals_m1, "c", 30); CheckNumber(locals_m1, "d", 50); CheckNumber(locals_m1, "e", 60); CheckNumber(locals_m1, "f", 0); props = await GetObjectOnFrame(pause_location["callFrames"][3], "complex"); Assert.Equal(3, props.Count()); CheckNumber(props, "A", 10); CheckString(props, "B", "xx"); CheckString(props, "c", "20_xx"); pause_location = await StepAndCheck(StepKind.Over, dep_cs_loc, 23, 8, "DoStuff", times: 2); // Check UseComplex frame again locals_m1 = await GetLocalsForFrame(pause_location["callFrames"][1], debugger_test_loc, 23, 8, "UseComplex"); Assert.Equal(7, locals_m1.Count()); CheckNumber(locals_m1, "a", 10); CheckNumber(locals_m1, "b", 20); CheckObject(locals_m1, "complex", "Simple.Complex"); CheckNumber(locals_m1, "c", 30); CheckNumber(locals_m1, "d", 50); CheckNumber(locals_m1, "e", 60); CheckNumber(locals_m1, "f", 0); props = await GetObjectOnFrame(pause_location["callFrames"][1], "complex"); Assert.Equal(3, props.Count()); CheckNumber(props, "A", 10); CheckString(props, "B", "xx"); CheckString(props, "c", "20_xx"); }); }
public async Task InspectLocalsDuringStepping() { var insp = new Inspector(); //Collect events var scripts = SubscribeToScripts(insp); await Ready(); await insp.Ready(async (cli, token) => { var bp1_req = JObject.FromObject(new { lineNumber = 4, columnNumber = 2, url = dicFileToUrl["dotnet://debugger-test.dll/debugger-test.cs"], }); var bp1_res = await cli.SendCommand("Debugger.setBreakpointByUrl", bp1_req, token); Assert.True(bp1_res.IsOk); var eval_req = JObject.FromObject(new { expression = "window.setTimeout(function() { invoke_add(); }, 1);", }); var eval_res = await cli.SendCommand("Runtime.evaluate", eval_req, token); Assert.True(eval_res.IsOk); var pause_location = await insp.WaitFor(Inspector.PAUSE); //ok, what's on that scope? var get_prop_req = JObject.FromObject(new { objectId = "dotnet:scope:0", }); var frame_props = await cli.SendCommand("Runtime.getProperties", get_prop_req, token); Assert.True(frame_props.IsOk); var locals = frame_props.Value ["result"]; CheckNumber(locals, "a", 10); CheckNumber(locals, "b", 20); CheckNumber(locals, "c", 0); CheckNumber(locals, "d", 0); CheckNumber(locals, "e", 0); //step and get locals var step_res = await cli.SendCommand("Debugger.stepOver", null, token); Assert.True(step_res.IsOk); pause_location = await insp.WaitFor(Inspector.PAUSE); frame_props = await cli.SendCommand("Runtime.getProperties", get_prop_req, token); Assert.True(frame_props.IsOk); locals = frame_props.Value ["result"]; CheckNumber(locals, "a", 10); CheckNumber(locals, "b", 20); CheckNumber(locals, "c", 30); CheckNumber(locals, "d", 0); CheckNumber(locals, "e", 0); //step and get locals step_res = await cli.SendCommand("Debugger.stepOver", null, token); Assert.True(step_res.IsOk); pause_location = await insp.WaitFor(Inspector.PAUSE); frame_props = await cli.SendCommand("Runtime.getProperties", get_prop_req, token); Assert.True(frame_props.IsOk); locals = frame_props.Value ["result"]; CheckNumber(locals, "a", 10); CheckNumber(locals, "b", 20); CheckNumber(locals, "c", 30); CheckNumber(locals, "d", 50); CheckNumber(locals, "e", 0); }); }
/* * 1. runs `Runtime.callFunctionOn` on the objectId, * if @roundtrip == false, then * -> calls @test_fn for that result (new objectId) * else * -> runs it again on the *result's* objectId. * -> calls @test_fn on the *new* result objectId * * Returns: result of `Runtime.callFunctionOn` */ async Task RunCallFunctionOn(string eval_fn, string fn_decl, string local_name, string bp_loc, int line, int col, int res_array_len = -1, Func <Result, Task> test_fn = null, bool returnByValue = false, JArray fn_args = null, bool roundtrip = false) { var insp = new Inspector(); //Collect events var scripts = SubscribeToScripts(insp); await Ready(); await insp.Ready(async (cli, token) => { ctx = new DebugTestContext(cli, insp, token, scripts); await SetBreakpoint(bp_loc, line, col); // callFunctionOn var eval_expr = $"window.setTimeout(function() {{ {eval_fn} }}, 1);"; var result = await ctx.cli.SendCommand("Runtime.evaluate", JObject.FromObject(new { expression = eval_expr }), ctx.token); var pause_location = await ctx.insp.WaitFor(Inspector.PAUSE); // Um for js we get "scriptId": "6" // CheckLocation (bp_loc, line, col, ctx.scripts, pause_location ["callFrames"][0]["location"]); // Check the object at the bp var frame_locals = await GetProperties(pause_location ["callFrames"][0]["scopeChain"][0]["object"]["objectId"].Value <string> ()); var obj = GetAndAssertObjectWithName(frame_locals, local_name); var obj_id = obj ["value"]["objectId"].Value <string> (); var cfo_args = JObject.FromObject(new { functionDeclaration = fn_decl, objectId = obj_id }); if (fn_args != null) { cfo_args ["arguments"] = fn_args; } if (returnByValue) { cfo_args ["returnByValue"] = returnByValue; } // callFunctionOn result = await ctx.cli.SendCommand("Runtime.callFunctionOn", cfo_args, ctx.token); await CheckCFOResult(result); // If it wasn't `returnByValue`, then try to run a new function // on that *returned* object // This second function, just returns the object as-is, so the same // test_fn is re-usable. if (!returnByValue && roundtrip) { cfo_args = JObject.FromObject(new { functionDeclaration = "function () { return this; }", objectId = result.Value ["result"]["objectId"]?.Value <string> () }); if (fn_args != null) { cfo_args ["arguments"] = fn_args; } result = await ctx.cli.SendCommand("Runtime.callFunctionOn", cfo_args, ctx.token); await CheckCFOResult(result); } if (test_fn != null) { await test_fn(result); } return; async Task CheckCFOResult(Result result) { if (returnByValue) { return; } if (res_array_len < 0) { await CheckValue(result.Value ["result"], TObject("Object"), $"cfo-res"); } else { await CheckValue(result.Value ["result"], TArray("Array", res_array_len), $"cfo-res"); } } }); }
public BadHarnessInitTests(string driver = "debugger-driver.html") : base(driver) { insp = new Inspector(); scripts = SubscribeToScripts(insp); }