3 using System
.Threading
.Tasks
;
4 using Newtonsoft
.Json
.Linq
;
6 using WebAssembly
.Net
.Debugging
;
8 namespace DebuggerTests
11 public class SourceList
: DebuggerTestBase
{
14 public async Task
CheckThatAllSourcesAreSent () {
15 var insp
= new Inspector ();
17 var scripts
= SubscribeToScripts(insp
);
20 //all sources are sent before runtime ready is sent, nothing to check
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
);
28 public async Task
CreateGoodBreakpoint () {
29 var insp
= new Inspector ();
32 var scripts
= SubscribeToScripts(insp
);
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"]);
53 public async Task
CreateBadBreakpoint () {
54 var insp
= new Inspector ();
57 var scripts
= SubscribeToScripts(insp
);
60 await insp
.Ready (async (cli
, token
) => {
61 var bp1_req
= JObject
.FromObject(new {
64 url
= "dotnet://debugger-test.dll/this-file-doesnt-exist.cs",
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> ());
76 public async Task
CreateGoodBreakpointAndHit () {
77 var insp
= new Inspector ();
80 var scripts
= SubscribeToScripts(insp
);
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);",
92 await EvaluateAndCheck (
93 "window.setTimeout(function() { invoke_add(); }, 1);",
94 "dotnet://debugger-test.dll/debugger-test.cs", 5, 2,
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
;
123 public async Task
ExceptionThrownInJS () {
124 var insp
= new Inspector ();
127 var scripts
= SubscribeToScripts(insp
);
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> ());
142 public async Task
ExceptionThrownInJSOutOfBand () {
143 var insp
= new Inspector ();
146 var scripts
= SubscribeToScripts(insp
);
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> ());
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);",
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);
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'");
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);",
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);
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
)
223 List
= TObject ($"System.Collections.Generic.List<{typearg}>"),
224 StringField
= TString (stringField
)
228 public async Task
RuntimeGetPropertiesWithInvalidScopeIdTest () {
229 var insp
= new Inspector ();
231 var scripts
= SubscribeToScripts(insp
);
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,
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
);
265 public async Task
TrivalStepping () {
266 var insp
= new Inspector ();
268 var scripts
= SubscribeToScripts(insp
);
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,
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
;
301 public async Task
InspectLocalsDuringStepping () {
302 var insp
= new Inspector ();
304 var scripts
= SubscribeToScripts(insp
);
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);
351 public async Task
InspectLocalsInPreviousFramesDuringSteppingIn2 (bool use_cfo
) {
352 var insp
= new Inspector ();
354 var scripts
= SubscribeToScripts(insp
);
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");
424 public async Task
InspectLocalsInPreviousFramesDuringSteppingIn (bool use_cfo
) {
425 var insp
= new Inspector ();
427 var scripts
= SubscribeToScripts(insp
);
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");
522 public async Task
InspectLocalsDuringSteppingIn () {
523 var insp
= new Inspector ();
525 var scripts
= SubscribeToScripts(insp
);
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");
589 public async Task
InspectLocalsInAsyncMethods (bool use_cfo
) {
590 var insp
= new Inspector ();
592 var scripts
= SubscribeToScripts(insp
);
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);
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
650 public async Task
InspectLocalsWithStructs (bool use_cfo
) {
651 var insp
= new Inspector ();
653 var scripts
= SubscribeToScripts(insp
);
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")
687 await CheckDateTime (ss_local_props
, "dt", dt
);
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")
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",
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
);
728 dt
= new DateTime (2025, 6, 7, 8, 10, 11);
729 var ssf_props
= await CompareObjectPropertiesFor (vt_local_props
, "SimpleStructField",
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
748 public async Task
InspectValueTypeMethodArgs (bool use_cfo
) {
749 var insp
= new Inspector ();
751 var scripts
= SubscribeToScripts(insp
);
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");
793 await CheckDateTime (ss_arg_props
, "dt", dt
);
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");
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");
837 await CheckDateTime (ss_arg_props
, "dt", dt
);
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")
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");
861 await CompareObjectPropertiesFor (ss_arg_props
, "gs", ss_local_gs
, label
: "ss_local_gs");
864 // FIXME: check ss_local.gs.List's members
871 public async Task
InspectLocalsWithStructsStaticAsync (bool use_cfo
) {
872 var insp
= new Inspector ();
874 var scripts
= SubscribeToScripts(insp
);
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'"
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)
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")
910 await CheckDateTime (ss_local_props
, "dt", dt
);
913 await CompareObjectPropertiesFor (ss_local_props
, "gs",
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")
930 // FIXME: check ss_local.gs.List's members
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 ();
943 var scripts
= SubscribeToScripts(insp
);
944 string entry_method_name
= $"[debugger-test] DebuggerTests.ValueTypesTest:MethodWithLocalsForToStringTest{(invoke_async ? "Async" : String.Empty)}";
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")
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);
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")
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
);
989 await CompareObjectPropertiesFor (frame_locals
, "ts",
991 Days
= TNumber (3530),
992 Minutes
= TNumber (2),
993 Seconds
= TNumber (4),
994 }, "ts_props", num_fields
: 12);
997 await CompareObjectPropertiesFor (frame_locals
, "dto",
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",
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")
1016 DTO
= new DateTimeOffset (dt0
, new TimeSpan (3, 15, 0));
1017 var sst_props
= await CompareObjectPropertiesFor (frame_locals
, "sst",
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")
1029 public async Task
InspectLocals () {
1030 var insp
= new Inspector ();
1031 var scripts
= SubscribeToScripts (insp
);
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> ());
1043 [InlineData (false)]
1045 public async Task
InspectLocalsWithPointers (bool use_cfo
)
1046 => await CheckInspectLocalsAtBreakpointSite (
1047 "dotnet://debugger-test.dll/debugger-test.cs", 294, 2,
1049 "window.setTimeout(function() { invoke_static_method_async ('[debugger-test] Math:PointersTest'); })",
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)
1075 [InlineData (false)]
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'); })",
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>")
1093 await CompareObjectPropertiesFor (frame_locals
, "local_gs",
1095 Id
= TString ("local_gs#Id"),
1096 Color
= TEnum ("DebuggerTests.RGB", "Green"),
1099 label: "local_gs#0");
1101 await CompareObjectPropertiesFor (frame_locals
, "sc_arg",
1102 TSimpleClass (10, 45, "sc_arg#Id", "Blue"),
1105 await CompareObjectPropertiesFor (frame_locals
, "this",
1106 TPoint (90, -4, "point#Id", "Green"),
1111 //TODO add tests covering basic stepping behavior as step in/out/over