[wasm][debugger][tests] Split tests into separate files (#19647)
[mono-project.git] / sdks / wasm / DebuggerTestSuite / Tests.cs
blob668791d402b812cf5d16d028a7ccba946bcf07c5
1 using System;
2 using System.Linq;
3 using System.Threading.Tasks;
4 using Newtonsoft.Json.Linq;
5 using Xunit;
6 using WebAssembly.Net.Debugging;
8 namespace DebuggerTests
11 public class SourceList : DebuggerTestBase {
13 [Fact]
14 public async Task CheckThatAllSourcesAreSent () {
15 var insp = new Inspector ();
16 //Collect events
17 var scripts = SubscribeToScripts(insp);
19 await Ready();
20 //all sources are sent before runtime ready is sent, nothing to check
21 await insp.Ready ();
22 Assert.Contains ("dotnet://debugger-test.dll/debugger-test.cs", scripts.Values);
23 Assert.Contains ("dotnet://debugger-test.dll/debugger-test2.cs", scripts.Values);
24 Assert.Contains ("dotnet://Simple.Dependency.dll/dependency.cs", scripts.Values);
27 [Fact]
28 public async Task CreateGoodBreakpoint () {
29 var insp = new Inspector ();
31 //Collect events
32 var scripts = SubscribeToScripts(insp);
34 await Ready ();
35 await insp.Ready (async (cli, token) => {
36 ctx = new DebugTestContext (cli, insp, token, scripts);
38 var bp1_res = await SetBreakpoint ("dotnet://debugger-test.dll/debugger-test.cs", 5, 2);
40 Assert.EndsWith ("debugger-test.cs", bp1_res.Value ["breakpointId"].ToString());
41 Assert.Equal (1, bp1_res.Value ["locations"]?.Value<JArray> ()?.Count);
43 var loc = bp1_res.Value ["locations"]?.Value<JArray> ()[0];
45 Assert.NotNull (loc ["scriptId"]);
46 Assert.Equal("dotnet://debugger-test.dll/debugger-test.cs", scripts [loc["scriptId"]?.Value<string> ()]);
47 Assert.Equal (5, loc ["lineNumber"]);
48 Assert.Equal (2, loc ["columnNumber"]);
49 });
52 [Fact]
53 public async Task CreateBadBreakpoint () {
54 var insp = new Inspector ();
56 //Collect events
57 var scripts = SubscribeToScripts(insp);
59 await Ready ();
60 await insp.Ready (async (cli, token) => {
61 var bp1_req = JObject.FromObject(new {
62 lineNumber = 5,
63 columnNumber = 2,
64 url = "dotnet://debugger-test.dll/this-file-doesnt-exist.cs",
65 });
67 var bp1_res = await cli.SendCommand ("Debugger.setBreakpointByUrl", bp1_req, token);
69 Assert.True (bp1_res.IsOk);
70 Assert.Empty (bp1_res.Value["locations"].Values<object>());
71 //Assert.Equal ((int)MonoErrorCodes.BpNotFound, bp1_res.Error ["code"]?.Value<int> ());
72 });
75 [Fact]
76 public async Task CreateGoodBreakpointAndHit () {
77 var insp = new Inspector ();
79 //Collect events
80 var scripts = SubscribeToScripts(insp);
82 await Ready ();
83 await insp.Ready (async (cli, token) => {
84 ctx = new DebugTestContext (cli, insp, token, scripts);
86 var bp = await SetBreakpoint ("dotnet://debugger-test.dll/debugger-test.cs", 5, 2);
88 var eval_req = JObject.FromObject(new {
89 expression = "window.setTimeout(function() { invoke_add(); }, 1);",
90 });
92 await EvaluateAndCheck (
93 "window.setTimeout(function() { invoke_add(); }, 1);",
94 "dotnet://debugger-test.dll/debugger-test.cs", 5, 2,
95 "IntAdd",
96 wait_for_event_fn: (pause_location) => {
97 Assert.Equal ("other", pause_location ["reason"]?.Value<string> ());
98 Assert.Equal (bp.Value["breakpointId"]?.ToString(), pause_location ["hitBreakpoints"]?[0]?.Value<string> ());
100 var top_frame = pause_location ["callFrames"][0];
101 Assert.Equal ("IntAdd", top_frame ["functionName"].Value<string>());
102 Assert.Contains ("debugger-test.cs", top_frame ["url"].Value<string> ());
104 CheckLocation ("dotnet://debugger-test.dll/debugger-test.cs", 3, 41, scripts, top_frame["functionLocation"]);
106 //now check the scope
107 var scope = top_frame ["scopeChain"][0];
108 Assert.Equal ("local", scope ["type"]);
109 Assert.Equal ("IntAdd", scope ["name"]);
111 Assert.Equal ("object", scope ["object"]["type"]);
112 Assert.Equal ("dotnet:scope:0", scope ["object"]["objectId"]);
113 CheckLocation ("dotnet://debugger-test.dll/debugger-test.cs", 3, 41, scripts, scope["startLocation"]);
114 CheckLocation ("dotnet://debugger-test.dll/debugger-test.cs", 9, 1, scripts, scope["endLocation"]);
115 return Task.CompletedTask;
122 [Fact]
123 public async Task ExceptionThrownInJS () {
124 var insp = new Inspector ();
126 //Collect events
127 var scripts = SubscribeToScripts(insp);
129 await Ready ();
130 await insp.Ready (async (cli, token) => {
131 var eval_req = JObject.FromObject(new {
132 expression = "invoke_bad_js_test();"
135 var eval_res = await cli.SendCommand ("Runtime.evaluate", eval_req, token);
136 Assert.True (eval_res.IsErr);
137 Assert.Equal ("Uncaught", eval_res.Error ["exceptionDetails"]? ["text"]? .Value<string> ());
141 [Fact]
142 public async Task ExceptionThrownInJSOutOfBand () {
143 var insp = new Inspector ();
145 //Collect events
146 var scripts = SubscribeToScripts(insp);
148 await Ready ();
149 await insp.Ready (async (cli, token) => {
150 ctx = new DebugTestContext (cli, insp, token, scripts);
152 await SetBreakpoint ("/debugger-driver.html", 27, 2);
154 var eval_req = JObject.FromObject(new {
155 expression = "window.setTimeout(function() { invoke_bad_js_test(); }, 1);",
158 var eval_res = await cli.SendCommand ("Runtime.evaluate", eval_req, token);
159 // Response here will be the id for the timer from JS!
160 Assert.True (eval_res.IsOk);
162 var ex = await Assert.ThrowsAsync<ArgumentException> (async () => await insp.WaitFor("Runtime.exceptionThrown"));
163 var ex_json = JObject.Parse (ex.Message);
164 Assert.Equal (dicFileToUrl["/debugger-driver.html"], ex_json ["exceptionDetails"]? ["url"]? .Value<string> ());
169 [Theory]
170 [InlineData (false)]
171 [InlineData (true)]
172 public async Task InspectLocalsAtBreakpointSite (bool use_cfo) =>
173 await CheckInspectLocalsAtBreakpointSite (
174 "dotnet://debugger-test.dll/debugger-test.cs", 5, 2, "IntAdd",
175 "window.setTimeout(function() { invoke_add(); }, 1);",
176 use_cfo: use_cfo,
177 test_fn: (locals) => {
178 CheckNumber (locals, "a", 10);
179 CheckNumber (locals, "b", 20);
180 CheckNumber (locals, "c", 30);
181 CheckNumber (locals, "d", 0);
182 CheckNumber (locals, "e", 0);
186 [Fact]
187 public async Task InspectPrimitiveTypeLocalsAtBreakpointSite () =>
188 await CheckInspectLocalsAtBreakpointSite (
189 "dotnet://debugger-test.dll/debugger-test.cs", 145, 2, "PrimitiveTypesTest",
190 "window.setTimeout(function() { invoke_static_method ('[debugger-test] Math:PrimitiveTypesTest'); }, 1);",
191 test_fn: (locals) => {
192 CheckSymbol (locals, "c0", "8364 '€'");
193 CheckSymbol (locals, "c1", "65 'A'");
197 [Theory]
198 [InlineData (false)]
199 [InlineData (true)]
200 public async Task InspectLocalsWithGenericTypesAtBreakpointSite (bool use_cfo) =>
201 await CheckInspectLocalsAtBreakpointSite (
202 "dotnet://debugger-test.dll/debugger-test.cs", 65, 2, "GenericTypesTest",
203 "window.setTimeout(function() { invoke_generic_types_test (); }, 1);",
204 use_cfo: use_cfo,
205 test_fn: (locals) => {
206 CheckObject (locals, "list", "System.Collections.Generic.Dictionary<Math[], Math.IsMathNull>");
207 CheckObject (locals, "list_null", "System.Collections.Generic.Dictionary<Math[], Math.IsMathNull>", is_null: true);
209 CheckArray (locals, "list_arr", "System.Collections.Generic.Dictionary<Math[], Math.IsMathNull>[]");
210 CheckObject (locals, "list_arr_null", "System.Collections.Generic.Dictionary<Math[], Math.IsMathNull>[]", is_null: true);
212 // Unused locals
213 CheckObject (locals, "list_unused", "System.Collections.Generic.Dictionary<Math[], Math.IsMathNull>");
214 CheckObject (locals, "list_null_unused", "System.Collections.Generic.Dictionary<Math[], Math.IsMathNull>", is_null: true);
216 CheckObject (locals, "list_arr_unused", "System.Collections.Generic.Dictionary<Math[], Math.IsMathNull>[]");
217 CheckObject (locals, "list_arr_null_unused", "System.Collections.Generic.Dictionary<Math[], Math.IsMathNull>[]", is_null: true);
221 object TGenericStruct(string typearg, string stringField)
222 => new {
223 List = TObject ($"System.Collections.Generic.List<{typearg}>"),
224 StringField = TString (stringField)
227 [Fact]
228 public async Task RuntimeGetPropertiesWithInvalidScopeIdTest () {
229 var insp = new Inspector ();
230 //Collect events
231 var scripts = SubscribeToScripts(insp);
233 await Ready ();
234 await insp.Ready (async (cli, token) => {
235 ctx = new DebugTestContext (cli, insp, token, scripts);
237 var bp = await SetBreakpoint ("dotnet://debugger-test.dll/debugger-test.cs", 41, 2);
239 await EvaluateAndCheck (
240 "window.setTimeout(function() { invoke_delegates_test (); }, 1);",
241 "dotnet://debugger-test.dll/debugger-test.cs", 41, 2,
242 "DelegatesTest",
243 wait_for_event_fn: async (pause_location) => {
244 //make sure we're on the right bp
245 Assert.Equal (bp.Value ["breakpointId"]?.ToString (), pause_location ["hitBreakpoints"]?[0]?.Value<string> ());
247 var top_frame = pause_location ["callFrames"][0];
249 var scope = top_frame ["scopeChain"][0];
250 Assert.Equal ("dotnet:scope:0", scope ["object"]["objectId"]);
252 // Try to get an invalid scope!
253 var get_prop_req = JObject.FromObject(new {
254 objectId = "dotnet:scope:23490871",
257 var frame_props = await cli.SendCommand ("Runtime.getProperties", get_prop_req, token);
258 Assert.True (frame_props.IsErr);
264 [Fact]
265 public async Task TrivalStepping () {
266 var insp = new Inspector ();
267 //Collect events
268 var scripts = SubscribeToScripts(insp);
270 await Ready ();
271 await insp.Ready (async (cli, token) => {
272 ctx = new DebugTestContext (cli, insp, token, scripts);
274 var bp = await SetBreakpoint ("dotnet://debugger-test.dll/debugger-test.cs", 5, 2);
276 await EvaluateAndCheck (
277 "window.setTimeout(function() { invoke_add(); }, 1);",
278 "dotnet://debugger-test.dll/debugger-test.cs", 5, 2,
279 "IntAdd",
280 wait_for_event_fn: (pause_location) => {
281 //make sure we're on the right bp
282 Assert.Equal (bp.Value ["breakpointId"]?.ToString (), pause_location ["hitBreakpoints"]?[0]?.Value<string> ());
284 var top_frame = pause_location ["callFrames"][0];
285 CheckLocation ("dotnet://debugger-test.dll/debugger-test.cs", 3, 41, scripts, top_frame["functionLocation"]);
286 return Task.CompletedTask;
290 await StepAndCheck (StepKind.Over, "dotnet://debugger-test.dll/debugger-test.cs", 6, 2, "IntAdd",
291 wait_for_event_fn: (pause_location) => {
292 var top_frame = pause_location ["callFrames"][0];
293 CheckLocation ("dotnet://debugger-test.dll/debugger-test.cs", 3, 41, scripts, top_frame["functionLocation"]);
294 return Task.CompletedTask;
300 [Fact]
301 public async Task InspectLocalsDuringStepping () {
302 var insp = new Inspector ();
303 //Collect events
304 var scripts = SubscribeToScripts(insp);
306 await Ready();
307 await insp.Ready (async (cli, token) => {
308 ctx = new DebugTestContext (cli, insp, token, scripts);
310 var debugger_test_loc = "dotnet://debugger-test.dll/debugger-test.cs";
311 await SetBreakpoint (debugger_test_loc, 4, 2);
313 await EvaluateAndCheck (
314 "window.setTimeout(function() { invoke_add(); }, 1);",
315 debugger_test_loc, 4, 2, "IntAdd",
316 locals_fn: (locals) => {
317 CheckNumber (locals, "a", 10);
318 CheckNumber (locals, "b", 20);
319 CheckNumber (locals, "c", 0);
320 CheckNumber (locals, "d", 0);
321 CheckNumber (locals, "e", 0);
325 await StepAndCheck (StepKind.Over, debugger_test_loc, 5, 2, "IntAdd",
326 locals_fn: (locals) => {
327 CheckNumber (locals, "a", 10);
328 CheckNumber (locals, "b", 20);
329 CheckNumber (locals, "c", 30);
330 CheckNumber (locals, "d", 0);
331 CheckNumber (locals, "e", 0);
335 //step and get locals
336 await StepAndCheck (StepKind.Over, debugger_test_loc, 6, 2, "IntAdd",
337 locals_fn: (locals) => {
338 CheckNumber (locals, "a", 10);
339 CheckNumber (locals, "b", 20);
340 CheckNumber (locals, "c", 30);
341 CheckNumber (locals, "d", 50);
342 CheckNumber (locals, "e", 0);
348 [Theory]
349 [InlineData (false)]
350 [InlineData (true)]
351 public async Task InspectLocalsInPreviousFramesDuringSteppingIn2 (bool use_cfo) {
352 var insp = new Inspector ();
353 //Collect events
354 var scripts = SubscribeToScripts(insp);
356 await Ready();
357 await insp.Ready (async (cli, token) => {
358 ctx = new DebugTestContext (cli, insp, token, scripts);
359 ctx.UseCallFunctionOnBeforeGetProperties = use_cfo;
361 var dep_cs_loc = "dotnet://Simple.Dependency.dll/dependency.cs";
362 await SetBreakpoint (dep_cs_loc, 24, 2);
364 var debugger_test_loc = "dotnet://debugger-test.dll/debugger-test.cs";
366 // Will stop in Complex.DoEvenMoreStuff
367 var pause_location = await EvaluateAndCheck (
368 "window.setTimeout(function() { invoke_use_complex (); }, 1);",
369 dep_cs_loc, 24, 2, "DoEvenMoreStuff",
370 locals_fn: (locals) => {
371 Assert.Single (locals);
372 CheckObject (locals, "this", "Simple.Complex");
376 var props = await GetObjectOnFrame (pause_location["callFrames"][0], "this");
377 Assert.Equal (3, props.Count());
378 CheckNumber (props, "A", 10);
379 CheckString (props, "B", "xx");
380 CheckObject (props, "c", "object");
382 // Check UseComplex frame
383 var locals_m1 = await GetLocalsForFrame (pause_location ["callFrames"][3], debugger_test_loc, 17, 2, "UseComplex");
384 Assert.Equal (7, locals_m1.Count());
386 CheckNumber (locals_m1, "a", 10);
387 CheckNumber (locals_m1, "b", 20);
388 CheckObject (locals_m1, "complex", "Simple.Complex");
389 CheckNumber (locals_m1, "c", 30);
390 CheckNumber (locals_m1, "d", 50);
391 CheckNumber (locals_m1, "e", 60);
392 CheckNumber (locals_m1, "f", 0);
394 props = await GetObjectOnFrame (pause_location["callFrames"][3], "complex");
395 Assert.Equal (3, props.Count());
396 CheckNumber (props, "A", 10);
397 CheckString (props, "B", "xx");
398 CheckObject (props, "c", "object");
400 pause_location = await StepAndCheck (StepKind.Over, dep_cs_loc, 16, 2, "DoStuff", times: 2);
401 // Check UseComplex frame again
402 locals_m1 = await GetLocalsForFrame (pause_location ["callFrames"][1], debugger_test_loc, 17, 2, "UseComplex");
403 Assert.Equal (7, locals_m1.Count());
405 CheckNumber (locals_m1, "a", 10);
406 CheckNumber (locals_m1, "b", 20);
407 CheckObject (locals_m1, "complex", "Simple.Complex");
408 CheckNumber (locals_m1, "c", 30);
409 CheckNumber (locals_m1, "d", 50);
410 CheckNumber (locals_m1, "e", 60);
411 CheckNumber (locals_m1, "f", 0);
413 props = await GetObjectOnFrame (pause_location["callFrames"][1], "complex");
414 Assert.Equal (3, props.Count());
415 CheckNumber (props, "A", 10);
416 CheckString (props, "B", "xx");
417 CheckObject (props, "c", "object");
421 [Theory]
422 [InlineData (false)]
423 [InlineData (true)]
424 public async Task InspectLocalsInPreviousFramesDuringSteppingIn (bool use_cfo) {
425 var insp = new Inspector ();
426 //Collect events
427 var scripts = SubscribeToScripts(insp);
429 await Ready();
430 await insp.Ready (async (cli, token) => {
431 ctx = new DebugTestContext (cli, insp, token, scripts);
432 ctx.UseCallFunctionOnBeforeGetProperties = use_cfo;
434 var debugger_test_loc = "dotnet://debugger-test.dll/debugger-test.cs";
435 await SetBreakpoint (debugger_test_loc, 102, 3);
437 // Will stop in InnerMethod
438 var wait_res = await EvaluateAndCheck (
439 "window.setTimeout(function() { invoke_outer_method(); }, 1);",
440 debugger_test_loc, 102, 3, "InnerMethod",
441 locals_fn: (locals) => {
442 Assert.Equal (4, locals.Count());
443 CheckNumber (locals, "i", 5);
444 CheckNumber (locals, "j", 24);
445 CheckString (locals, "foo_str", "foo");
446 CheckObject (locals, "this", "Math.NestedInMath");
450 var this_props = await GetObjectOnFrame (wait_res["callFrames"][0], "this");
451 Assert.Equal (2, this_props.Count());
452 CheckObject (this_props, "m", "Math");
453 CheckValueType (this_props, "SimpleStructProperty", "Math.SimpleStruct");
455 var ss_props = await GetObjectOnLocals (this_props, "SimpleStructProperty");
456 Assert.Equal (2, ss_props.Count());
457 CheckValueType (ss_props, "dt", "System.DateTime");
458 CheckValueType (ss_props, "gs", "Math.GenericStruct<System.DateTime>");
460 await CheckDateTime (ss_props, "dt", new DateTime (2020, 1, 2, 3, 4, 5));
462 // Check OuterMethod frame
463 var locals_m1 = await GetLocalsForFrame (wait_res ["callFrames"][1], debugger_test_loc, 78, 2, "OuterMethod");
464 Assert.Equal (5, locals_m1.Count());
465 // FIXME: Failing test CheckNumber (locals_m1, "i", 5);
466 // FIXME: Failing test CheckString (locals_m1, "text", "Hello");
467 CheckNumber (locals_m1, "new_i", 0);
468 CheckNumber (locals_m1, "k", 0);
469 CheckObject (locals_m1, "nim", "Math.NestedInMath");
471 // step back into OuterMethod
472 await StepAndCheck (StepKind.Over, debugger_test_loc, 82, 2, "OuterMethod", times: 9,
473 locals_fn: (locals) => {
474 Assert.Equal (5, locals.Count());
476 // FIXME: Failing test CheckNumber (locals_m1, "i", 5);
477 CheckString (locals, "text", "Hello");
478 // FIXME: Failing test CheckNumber (locals, "new_i", 24);
479 CheckNumber (locals, "k", 19);
480 CheckObject (locals, "nim", "Math.NestedInMath");
484 //await StepAndCheck (StepKind.Over, "dotnet://debugger-test.dll/debugger-test.cs", 81, 2, "OuterMethod", times: 2);
486 // step into InnerMethod2
487 await StepAndCheck (StepKind.Into, "dotnet://debugger-test.dll/debugger-test.cs", 87, 1, "InnerMethod2",
488 locals_fn: (locals) => {
489 Assert.Equal (3, locals.Count());
491 CheckString (locals, "s", "test string");
492 //out var: CheckNumber (locals, "k", 0);
493 CheckNumber (locals, "i", 24);
497 await StepAndCheck (StepKind.Over, "dotnet://debugger-test.dll/debugger-test.cs", 91, 1, "InnerMethod2", times: 4,
498 locals_fn: (locals) => {
499 Assert.Equal (3, locals.Count());
501 CheckString (locals, "s", "test string");
502 // FIXME: Failing test CheckNumber (locals, "k", 34);
503 CheckNumber (locals, "i", 24);
507 await StepAndCheck (StepKind.Over, "dotnet://debugger-test.dll/debugger-test.cs", 83, 2, "OuterMethod", times: 2,
508 locals_fn: (locals) => {
509 Assert.Equal (5, locals.Count());
511 CheckString (locals, "text", "Hello");
512 // FIXME: failing test CheckNumber (locals, "i", 5);
513 CheckNumber (locals, "new_i", 22);
514 CheckNumber (locals, "k", 34);
515 CheckObject (locals, "nim", "Math.NestedInMath");
521 [Fact]
522 public async Task InspectLocalsDuringSteppingIn () {
523 var insp = new Inspector ();
524 //Collect events
525 var scripts = SubscribeToScripts(insp);
527 await Ready();
528 await insp.Ready (async (cli, token) => {
529 ctx = new DebugTestContext (cli, insp, token, scripts);
531 await SetBreakpoint ("dotnet://debugger-test.dll/debugger-test.cs", 77, 2);
533 await EvaluateAndCheck ("window.setTimeout(function() { invoke_outer_method(); }, 1);",
534 "dotnet://debugger-test.dll/debugger-test.cs", 77, 2, "OuterMethod",
535 locals_fn: (locals) => {
536 Assert.Equal (5, locals.Count());
538 CheckObject (locals, "nim", "Math.NestedInMath");
539 CheckNumber (locals, "i", 5);
540 CheckNumber (locals, "k", 0);
541 CheckNumber (locals, "new_i", 0);
542 CheckString (locals, "text", null);
546 await StepAndCheck (StepKind.Over, "dotnet://debugger-test.dll/debugger-test.cs", 78, 2, "OuterMethod",
547 locals_fn: (locals) => {
548 Assert.Equal (5, locals.Count());
550 CheckObject (locals, "nim", "Math.NestedInMath");
551 // FIXME: Failing test CheckNumber (locals, "i", 5);
552 CheckNumber (locals, "k", 0);
553 CheckNumber (locals, "new_i", 0);
554 CheckString (locals, "text", "Hello");
558 // Step into InnerMethod
559 await StepAndCheck (StepKind.Into, "dotnet://debugger-test.dll/debugger-test.cs", 96, 2, "InnerMethod");
560 await StepAndCheck (StepKind.Over, "dotnet://debugger-test.dll/debugger-test.cs", 100, 3, "InnerMethod", times: 5,
561 locals_fn: (locals) => {
562 Assert.Equal (4, locals.Count());
564 CheckNumber (locals, "i", 5);
565 CheckNumber (locals, "j", 15);
566 CheckString (locals, "foo_str", "foo");
567 CheckObject (locals, "this", "Math.NestedInMath");
571 // Step back to OuterMethod
572 await StepAndCheck (StepKind.Over, "dotnet://debugger-test.dll/debugger-test.cs", 79, 2, "OuterMethod", times: 6,
573 locals_fn: (locals) => {
574 Assert.Equal (5, locals.Count());
576 CheckObject (locals, "nim", "Math.NestedInMath");
577 // FIXME: Failing test CheckNumber (locals, "i", 5);
578 CheckNumber (locals, "k", 0);
579 CheckNumber (locals, "new_i", 24);
580 CheckString (locals, "text", "Hello");
586 [Theory]
587 [InlineData (false)]
588 [InlineData (true)]
589 public async Task InspectLocalsInAsyncMethods (bool use_cfo) {
590 var insp = new Inspector ();
591 //Collect events
592 var scripts = SubscribeToScripts(insp);
594 await Ready();
595 await insp.Ready (async (cli, token) => {
596 ctx = new DebugTestContext (cli, insp, token, scripts);
597 ctx.UseCallFunctionOnBeforeGetProperties = use_cfo;
598 var debugger_test_loc = "dotnet://debugger-test.dll/debugger-test.cs";
600 await SetBreakpoint (debugger_test_loc, 111, 3);
601 await SetBreakpoint (debugger_test_loc, 126, 3);
603 // Will stop in Asyncmethod0
604 var wait_res = await EvaluateAndCheck (
605 "window.setTimeout(function() { invoke_async_method_with_await(); }, 1);",
606 debugger_test_loc, 111, 3, "MoveNext", //FIXME:
607 locals_fn: (locals) => {
608 Assert.Equal (4, locals.Count());
609 CheckString (locals, "s", "string from js");
610 CheckNumber (locals, "i", 42);
611 CheckString (locals, "local0", "value0");
612 CheckObject (locals, "this", "Math.NestedInMath");
615 Console.WriteLine (wait_res);
617 #if false // Disabled for now, as we don't have proper async traces
618 var locals = await GetProperties (wait_res ["callFrames"][2]["callFrameId"].Value<string> ());
619 Assert.Equal (4, locals.Count());
620 CheckString (locals, "ls", "string from jstest");
621 CheckNumber (locals, "li", 52);
622 #endif
624 // TODO: previous frames have async machinery details, so no point checking that right now
626 var pause_loc = await SendCommandAndCheck (null, "Debugger.resume", debugger_test_loc, 126, 3, /*FIXME: "AsyncMethodNoReturn"*/ "MoveNext",
627 locals_fn: (locals) => {
628 Assert.Equal (4, locals.Count());
629 CheckString (locals, "str", "AsyncMethodNoReturn's local");
630 CheckObject (locals, "this", "Math.NestedInMath");
631 //FIXME: check fields
632 CheckValueType (locals, "ss", "Math.SimpleStruct");
633 CheckArray (locals, "ss_arr", "Math.SimpleStruct[]");
634 // TODO: struct fields
638 var this_props = await GetObjectOnFrame (pause_loc ["callFrames"][0], "this");
639 Assert.Equal (2, this_props.Count ());
640 CheckObject (this_props, "m", "Math");
641 CheckValueType (this_props, "SimpleStructProperty", "Math.SimpleStruct");
643 // TODO: Check `this` properties
647 [Theory]
648 [InlineData (false)]
649 [InlineData (true)]
650 public async Task InspectLocalsWithStructs (bool use_cfo) {
651 var insp = new Inspector ();
652 //Collect events
653 var scripts = SubscribeToScripts(insp);
655 await Ready();
656 await insp.Ready (async (cli, token) => {
657 ctx = new DebugTestContext (cli, insp, token, scripts);
658 ctx.UseCallFunctionOnBeforeGetProperties = use_cfo;
659 var debugger_test_loc = "dotnet://debugger-test.dll/debugger-valuetypes-test.cs";
661 await SetBreakpoint (debugger_test_loc, 16, 2);
663 var pause_location = await EvaluateAndCheck (
664 "window.setTimeout(function() { invoke_method_with_structs(); }, 1);",
665 debugger_test_loc, 16, 2, "MethodWithLocalStructs",
666 locals_fn: (locals) => {
667 Assert.Equal (3, locals.Count ());
669 CheckValueType (locals, "ss_local", "DebuggerTests.ValueTypesTest.SimpleStruct");
670 CheckValueType (locals, "gs_local", "DebuggerTests.ValueTypesTest.GenericStruct<DebuggerTests.ValueTypesTest>");
671 CheckObject (locals, "vt_local", "DebuggerTests.ValueTypesTest");
675 var dt = new DateTime (2021, 2, 3, 4, 6, 7);
676 // Check ss_local's properties
677 var ss_local_props = await GetObjectOnFrame (pause_location ["callFrames"][0], "ss_local");
678 await CheckProps (ss_local_props, new {
679 str_member = TString ("set in MethodWithLocalStructs#SimpleStruct#str_member"),
680 dt = TValueType ("System.DateTime", dt.ToString ()),
681 gs = TValueType ("DebuggerTests.ValueTypesTest.GenericStruct<System.DateTime>"),
682 Kind = TEnum ("System.DateTimeKind", "Utc")
683 }, "ss_local");
686 // Check ss_local.dt
687 await CheckDateTime (ss_local_props, "dt", dt);
689 // Check ss_local.gs
690 var gs_props = await GetObjectOnLocals (ss_local_props, "gs");
691 CheckString (gs_props, "StringField", "set in MethodWithLocalStructs#SimpleStruct#gs#StringField");
692 CheckObject (gs_props, "List", "System.Collections.Generic.List<System.DateTime>");
695 // Check gs_local's properties
696 var gs_local_props = await GetObjectOnFrame (pause_location ["callFrames"][0], "gs_local");
697 await CheckProps (gs_local_props, new {
698 StringField = TString ("gs_local#GenericStruct<ValueTypesTest>#StringField"),
699 List = TObject ("System.Collections.Generic.List<DebuggerTests.ValueTypesTest>", is_null: true),
700 Options = TEnum ("DebuggerTests.Options", "None")
701 }, "gs_local");
703 // Check vt_local's properties
704 var vt_local_props = await GetObjectOnFrame (pause_location ["callFrames"][0], "vt_local");
705 Assert.Equal (5, vt_local_props.Count());
707 CheckString (vt_local_props, "StringField", "string#0");
708 CheckValueType (vt_local_props, "SimpleStructField", "DebuggerTests.ValueTypesTest.SimpleStruct");
709 CheckValueType (vt_local_props, "SimpleStructProperty", "DebuggerTests.ValueTypesTest.SimpleStruct");
710 await CheckDateTime (vt_local_props, "DT", new DateTime (2020, 1, 2, 3, 4, 5));
711 CheckEnum (vt_local_props, "RGB", "DebuggerTests.RGB", "Blue");
714 // SimpleStructProperty
715 dt = new DateTime (2022, 3, 4, 5, 7, 8);
716 var ssp_props = await CompareObjectPropertiesFor (vt_local_props, "SimpleStructProperty",
717 new {
718 str_member = TString ("SimpleStructProperty#string#0#SimpleStruct#str_member"),
719 dt = TValueType ("System.DateTime", dt.ToString ()),
720 gs = TValueType ("DebuggerTests.ValueTypesTest.GenericStruct<System.DateTime>"),
721 Kind = TEnum ("System.DateTimeKind", "Utc")
723 label: "vt_local_props.SimpleStructProperty");
725 await CheckDateTime (ssp_props, "dt", dt);
727 // SimpleStructField
728 dt = new DateTime (2025, 6, 7, 8, 10, 11);
729 var ssf_props = await CompareObjectPropertiesFor (vt_local_props, "SimpleStructField",
730 new {
731 str_member = TString ("SimpleStructField#string#0#SimpleStruct#str_member"),
732 dt = TValueType ("System.DateTime", dt.ToString ()),
733 gs = TValueType ("DebuggerTests.ValueTypesTest.GenericStruct<System.DateTime>"),
734 Kind = TEnum ("System.DateTimeKind", "Local")
736 label: "vt_local_props.SimpleStructField");
738 await CheckDateTime (ssf_props, "dt", dt);
741 // FIXME: check ss_local.gs.List's members
745 [Theory]
746 [InlineData (false)]
747 [InlineData (true)]
748 public async Task InspectValueTypeMethodArgs (bool use_cfo) {
749 var insp = new Inspector ();
750 //Collect events
751 var scripts = SubscribeToScripts(insp);
753 await Ready();
754 await insp.Ready (async (cli, token) => {
755 ctx = new DebugTestContext (cli, insp, token, scripts);
756 ctx.UseCallFunctionOnBeforeGetProperties = use_cfo;
757 var debugger_test_loc = "dotnet://debugger-test.dll/debugger-valuetypes-test.cs";
759 await SetBreakpoint (debugger_test_loc, 27, 3);
762 var pause_location = await EvaluateAndCheck (
763 "window.setTimeout(function() { invoke_static_method ('[debugger-test] DebuggerTests.ValueTypesTest:TestStructsAsMethodArgs'); }, 1);",
764 debugger_test_loc, 27, 3, "MethodWithStructArgs",
765 locals_fn: (locals) => {
766 Assert.Equal (3, locals.Count ());
768 CheckString (locals, "label", "TestStructsAsMethodArgs#label");
769 CheckValueType (locals, "ss_arg", "DebuggerTests.ValueTypesTest.SimpleStruct");
770 CheckNumber (locals, "x", 3);
774 var dt = new DateTime (2025, 6, 7, 8, 10, 11);
775 var ss_local_as_ss_arg = new {
776 str_member = TString ("ss_local#SimpleStruct#string#0#SimpleStruct#str_member"),
777 dt = TValueType ("System.DateTime", dt.ToString ()),
778 gs = TValueType ("DebuggerTests.ValueTypesTest.GenericStruct<System.DateTime>"),
779 Kind = TEnum ("System.DateTimeKind", "Local")
781 var ss_local_gs = new {
782 StringField = TString ("ss_local#SimpleStruct#string#0#SimpleStruct#gs#StringField"),
783 List = TObject ("System.Collections.Generic.List<System.DateTime>"),
784 Options = TEnum ("DebuggerTests.Options", "Option1")
787 // Check ss_arg's properties
788 var ss_arg_props = await GetObjectOnFrame (pause_location ["callFrames"][0], "ss_arg");
789 await CheckProps (ss_arg_props, ss_local_as_ss_arg, "ss_arg");
792 // Check ss_local.dt
793 await CheckDateTime (ss_arg_props, "dt", dt);
795 // Check ss_local.gs
796 await CompareObjectPropertiesFor (ss_arg_props, "gs", ss_local_gs);
799 pause_location = await StepAndCheck (StepKind.Over, debugger_test_loc, 31, 3, "MethodWithStructArgs", times: 4,
800 locals_fn: (locals) => {
801 Assert.Equal (3, locals.Count());
803 CheckString (locals, "label", "TestStructsAsMethodArgs#label");
804 CheckValueType (locals, "ss_arg", "DebuggerTests.ValueTypesTest.SimpleStruct");
805 CheckNumber (locals, "x", 3);
810 var ss_arg_updated = new {
811 str_member = TString ("ValueTypesTest#MethodWithStructArgs#updated#ss_arg#str_member"),
812 dt = TValueType ("System.DateTime", dt.ToString ()),
813 gs = TValueType ("DebuggerTests.ValueTypesTest.GenericStruct<System.DateTime>"),
814 Kind = TEnum ("System.DateTimeKind", "Utc")
817 ss_arg_props = await GetObjectOnFrame (pause_location ["callFrames"][0], "ss_arg");
818 await CheckProps (ss_arg_props, ss_arg_updated, "ss_ar");
821 // Check ss_local.gs
822 await CompareObjectPropertiesFor (ss_arg_props, "gs", new {
823 StringField = TString ("ValueTypesTest#MethodWithStructArgs#updated#gs#StringField#3"),
824 List = TObject ("System.Collections.Generic.List<System.DateTime>"),
825 Options = TEnum ("DebuggerTests.Options", "Option1")
828 await CheckDateTime (ss_arg_props, "dt", dt);
831 // Check locals on previous frame, same as earlier in this test
832 ss_arg_props = await GetObjectOnFrame (pause_location ["callFrames"][1], "ss_local");
833 await CheckProps (ss_arg_props, ss_local_as_ss_arg, "ss_local");
836 // Check ss_local.dt
837 await CheckDateTime (ss_arg_props, "dt", dt);
839 // Check ss_local.gs
840 var gs_props = await GetObjectOnLocals (ss_arg_props, "gs");
841 CheckString (gs_props, "StringField", "ss_local#SimpleStruct#string#0#SimpleStruct#gs#StringField");
842 CheckObject (gs_props, "List", "System.Collections.Generic.List<System.DateTime>");
845 // ----------- Step back to the caller ---------
847 pause_location = await StepAndCheck (StepKind.Over, debugger_test_loc, 22, 3, "TestStructsAsMethodArgs",
848 times: 2, locals_fn: (l) => { /* non-null to make sure that locals get fetched */} );
849 var locals = await GetProperties (pause_location ["callFrames"][0]["callFrameId"].Value<string> ());
850 await CheckProps (locals, new {
851 ss_local = TValueType ("DebuggerTests.ValueTypesTest.SimpleStruct"),
852 ss_ret = TValueType ("DebuggerTests.ValueTypesTest.SimpleStruct")
854 "locals#0");
856 ss_arg_props = await GetObjectOnFrame (pause_location ["callFrames"] [0], "ss_local");
857 await CheckProps (ss_arg_props, ss_local_as_ss_arg, "ss_local");
860 // Check ss_local.gs
861 await CompareObjectPropertiesFor (ss_arg_props, "gs", ss_local_gs, label: "ss_local_gs");
864 // FIXME: check ss_local.gs.List's members
868 [Theory]
869 [InlineData (false)]
870 [InlineData (true)]
871 public async Task InspectLocalsWithStructsStaticAsync (bool use_cfo) {
872 var insp = new Inspector ();
873 //Collect events
874 var scripts = SubscribeToScripts(insp);
876 await Ready();
877 await insp.Ready (async (cli, token) => {
878 ctx = new DebugTestContext (cli, insp, token, scripts);
879 ctx.UseCallFunctionOnBeforeGetProperties = use_cfo;
880 var debugger_test_loc = "dotnet://debugger-test.dll/debugger-valuetypes-test.cs";
882 await SetBreakpoint (debugger_test_loc, 47, 3);
884 var pause_location = await EvaluateAndCheck (
885 "window.setTimeout(function() { invoke_static_method_async ("
886 + "'[debugger-test] DebuggerTests.ValueTypesTest:MethodWithLocalStructsStaticAsync'"
887 + "); }, 1);",
888 debugger_test_loc, 47, 3, "MoveNext"); //BUG: method name
890 var locals = await GetProperties (pause_location ["callFrames"][0]["callFrameId"].Value<string> ());
891 await CheckProps (locals, new {
892 ss_local = TObject ("DebuggerTests.ValueTypesTest.SimpleStruct"),
893 gs_local = TValueType ("DebuggerTests.ValueTypesTest.GenericStruct<int>"),
894 result = TBool (true)
896 "locals#0");
898 var dt = new DateTime (2021, 2, 3, 4, 6, 7);
899 // Check ss_local's properties
900 var ss_local_props = await GetObjectOnFrame (pause_location ["callFrames"][0], "ss_local");
901 await CheckProps (ss_local_props, new {
902 str_member = TString ("set in MethodWithLocalStructsStaticAsync#SimpleStruct#str_member"),
903 dt = TValueType ("System.DateTime", dt.ToString ()),
904 gs = TValueType ("DebuggerTests.ValueTypesTest.GenericStruct<System.DateTime>"),
905 Kind = TEnum ("System.DateTimeKind", "Utc")
906 }, "ss_local");
909 // Check ss_local.dt
910 await CheckDateTime (ss_local_props, "dt", dt);
912 // Check ss_local.gs
913 await CompareObjectPropertiesFor (ss_local_props, "gs",
914 new {
915 StringField = TString ("set in MethodWithLocalStructsStaticAsync#SimpleStruct#gs#StringField"),
916 List = TObject ("System.Collections.Generic.List<System.DateTime>"),
917 Options = TEnum ("DebuggerTests.Options", "Option1")
922 // Check gs_local's properties
923 var gs_local_props = await GetObjectOnFrame (pause_location ["callFrames"][0], "gs_local");
924 await CheckProps (gs_local_props, new {
925 StringField = TString ("gs_local#GenericStruct<ValueTypesTest>#StringField"),
926 List = TObject ("System.Collections.Generic.List<int>"),
927 Options = TEnum ("DebuggerTests.Options", "Option2")
928 }, "gs_local");
930 // FIXME: check ss_local.gs.List's members
934 [Theory]
935 [InlineData (123, 3, "MethodWithLocalsForToStringTest", false, false)]
936 [InlineData (133, 3, "MethodWithArgumentsForToStringTest", true, false)]
937 [InlineData (175, 3, "MethodWithArgumentsForToStringTestAsync", true, true)]
938 [InlineData (165, 3, "MethodWithArgumentsForToStringTestAsync", false, true)]
939 public async Task InspectLocalsForToStringDescriptions (int line, int col, string method_name, bool call_other, bool invoke_async)
941 var insp = new Inspector ();
942 //Collect events
943 var scripts = SubscribeToScripts(insp);
944 string entry_method_name = $"[debugger-test] DebuggerTests.ValueTypesTest:MethodWithLocalsForToStringTest{(invoke_async ? "Async" : String.Empty)}";
945 int frame_idx = 0;
947 await Ready();
948 await insp.Ready (async (cli, token) => {
949 ctx = new DebugTestContext (cli, insp, token, scripts);
950 var debugger_test_loc = "dotnet://debugger-test.dll/debugger-valuetypes-test.cs";
952 await SetBreakpoint (debugger_test_loc, line, col);
954 var eval_expr = "window.setTimeout(function() {"
955 + (invoke_async ? "invoke_static_method_async (" : "invoke_static_method (")
956 + $"'{entry_method_name}',"
957 + (call_other ? "true" : "false")
958 + "); }, 1);";
959 Console.WriteLine ($"{eval_expr}");
961 var pause_location = await EvaluateAndCheck (eval_expr, debugger_test_loc, line, col, invoke_async ? "MoveNext" : method_name);
963 var dt0 = new DateTime (2020, 1, 2, 3, 4, 5);
964 var dt1 = new DateTime (2010, 5, 4, 3, 2, 1);
965 var ts = dt0 - dt1;
966 var dto = new DateTimeOffset (dt0, new TimeSpan(4, 5, 0));
968 var frame_locals = await GetProperties (pause_location ["callFrames"][frame_idx]["callFrameId"].Value<string> ());
969 await CheckProps (frame_locals, new {
970 call_other = TBool (call_other),
971 dt0 = TValueType ("System.DateTime", dt0.ToString ()),
972 dt1 = TValueType ("System.DateTime", dt1.ToString ()),
973 dto = TValueType ("System.DateTimeOffset", dto.ToString ()),
974 ts = TValueType ("System.TimeSpan", ts.ToString ()),
975 dec = TValueType ("System.Decimal", "123987123"),
976 guid = TValueType ("System.Guid", "3D36E07E-AC90-48C6-B7EC-A481E289D014"),
977 dts = TArray ("System.DateTime[]", 2),
978 obj = TObject ("DebuggerTests.ClassForToStringTests"),
979 sst = TObject ("DebuggerTests.StructForToStringTests")
980 }, "locals#0");
982 var dts_0 = new DateTime (1983, 6, 7, 5, 6, 10);
983 var dts_1 = new DateTime (1999, 10, 15, 1, 2, 3);
984 var dts_elements = await GetObjectOnLocals (frame_locals, "dts");
985 await CheckDateTime (dts_elements, "0", dts_0);
986 await CheckDateTime (dts_elements, "1", dts_1);
988 // TimeSpan
989 await CompareObjectPropertiesFor (frame_locals, "ts",
990 new {
991 Days = TNumber (3530),
992 Minutes = TNumber (2),
993 Seconds = TNumber (4),
994 }, "ts_props", num_fields: 12);
996 // DateTimeOffset
997 await CompareObjectPropertiesFor (frame_locals, "dto",
998 new {
999 Day = TNumber (2),
1000 Year = TNumber (2020),
1001 DayOfWeek = TEnum ("System.DayOfWeek", "Thursday")
1002 }, "dto_props", num_fields: 22);
1004 var DT = new DateTime (2004, 10, 15, 1, 2, 3);
1005 var DTO = new DateTimeOffset (dt0, new TimeSpan(2, 14, 0));
1007 var obj_props = await CompareObjectPropertiesFor (frame_locals, "obj",
1008 new {
1009 DT = TValueType ("System.DateTime", DT.ToString ()),
1010 DTO = TValueType ("System.DateTimeOffset", DTO.ToString ()),
1011 TS = TValueType ("System.TimeSpan", ts.ToString ()),
1012 Dec = TValueType ("System.Decimal", "1239871"),
1013 Guid = TValueType ("System.Guid", "3D36E07E-AC90-48C6-B7EC-A481E289D014")
1014 }, "obj_props");
1016 DTO = new DateTimeOffset (dt0, new TimeSpan (3, 15, 0));
1017 var sst_props = await CompareObjectPropertiesFor (frame_locals, "sst",
1018 new {
1019 DT = TValueType ("System.DateTime", DT.ToString ()),
1020 DTO = TValueType ("System.DateTimeOffset", DTO.ToString ()),
1021 TS = TValueType ("System.TimeSpan", ts.ToString ()),
1022 Dec = TValueType ("System.Decimal", "1239871"),
1023 Guid = TValueType ("System.Guid", "3D36E07E-AC90-48C6-B7EC-A481E289D014")
1024 }, "sst_props");
1028 [Fact]
1029 public async Task InspectLocals () {
1030 var insp = new Inspector ();
1031 var scripts = SubscribeToScripts (insp);
1033 await Ready();
1034 await insp.Ready (async (cli, token) => {
1035 ctx = new DebugTestContext (cli, insp, token, scripts);
1037 var wait_res = await RunUntil ("locals_inner");
1038 var locals = await GetProperties (wait_res ["callFrames"][1]["callFrameId"].Value<string> ());
1042 [Theory]
1043 [InlineData (false)]
1044 [InlineData (true)]
1045 public async Task InspectLocalsWithPointers (bool use_cfo)
1046 => await CheckInspectLocalsAtBreakpointSite (
1047 "dotnet://debugger-test.dll/debugger-test.cs", 294, 2,
1048 "PointersTest",
1049 "window.setTimeout(function() { invoke_static_method_async ('[debugger-test] Math:PointersTest'); })",
1050 use_cfo: use_cfo,
1051 wait_for_event_fn: async (pause_location) => {
1052 var locals = await GetProperties (pause_location ["callFrames"][0]["callFrameId"].Value<string>());
1054 var dt = new DateTime (5, 6, 7, 8, 9, 10);
1055 await CheckProps (locals, new {
1056 ivalue0 = TNumber (5),
1057 ivalue1 = TNumber (10),
1058 ip = TPointer ("int*"),
1059 ip_null = TPointer ("int*", is_null: true),
1060 ipp = TPointer ("int**"),
1062 ipa = TArray ("int*[]", 3),
1063 cvalue0 = TSymbol ("113 'q'"),
1064 cp = TPointer ("char*"),
1065 dt = TValueType ("System.DateTime", dt.ToString ()),
1066 vp = TPointer ("void*"),
1067 vp_null = TPointer ("void*", is_null: true),
1068 dtp = TPointer ("System.DateTime*"),
1069 dtp_null = TPointer ("System.DateTime*", is_null: true)
1070 }, "locals");
1074 [Theory]
1075 [InlineData (false)]
1076 [InlineData (true)]
1077 public async Task InspectLocalsForStructInstanceMethod (bool use_cfo)
1078 => await CheckInspectLocalsAtBreakpointSite (
1079 "dotnet://debugger-test.dll/debugger-array-test.cs", 236, 3,
1080 "GenericInstanceMethod<DebuggerTests.SimpleClass>",
1081 "window.setTimeout(function() { invoke_static_method_async ('[debugger-test] DebuggerTests.EntryClass:run'); })",
1082 use_cfo: use_cfo,
1083 wait_for_event_fn: async (pause_location) => {
1084 var frame_locals = await GetProperties (pause_location ["callFrames"][0]["callFrameId"].Value<string>());
1086 await CheckProps (frame_locals, new {
1087 sc_arg = TObject ("DebuggerTests.SimpleClass"),
1088 @this = TValueType ("DebuggerTests.Point"),
1089 local_gs = TValueType ("DebuggerTests.SimpleGenericStruct<int>")
1091 "locals#0");
1093 await CompareObjectPropertiesFor (frame_locals, "local_gs",
1094 new {
1095 Id = TString ("local_gs#Id"),
1096 Color = TEnum ("DebuggerTests.RGB", "Green"),
1097 Value = TNumber (4)
1099 label: "local_gs#0");
1101 await CompareObjectPropertiesFor (frame_locals, "sc_arg",
1102 TSimpleClass (10, 45, "sc_arg#Id", "Blue"),
1103 label: "sc_arg#0");
1105 await CompareObjectPropertiesFor (frame_locals, "this",
1106 TPoint (90, -4, "point#Id", "Green"),
1107 label: "this#0");
1111 //TODO add tests covering basic stepping behavior as step in/out/over