// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Threading.Tasks; using Microsoft.WebAssembly.Diagnostics; using Newtonsoft.Json.Linq; using Xunit; using Xunit.Abstractions; namespace DebuggerTests { // TODO: static async, static method args public class EvaluateOnCallFrameTests : DebuggerTests { public EvaluateOnCallFrameTests(ITestOutputHelper testOutput) : base(testOutput) {} public static IEnumerable InstanceMethodsTestData(string type_name) { yield return new object[] { type_name, "InstanceMethod", $"{type_name}.InstanceMethod", false }; yield return new object[] { type_name, "GenericInstanceMethod", $"{type_name}.GenericInstanceMethod", false }; yield return new object[] { type_name, "InstanceMethodAsync", $"{type_name}.InstanceMethodAsync", true }; yield return new object[] { type_name, "GenericInstanceMethodAsync", $"{type_name}.GenericInstanceMethodAsync", true }; // TODO: { "DebuggerTests.EvaluateTestsGeneric`1", "Instance", 9, "EvaluateTestsGenericStructInstanceMethod", prefix } } public static IEnumerable InstanceMethodForTypeMembersTestData(string type_name) { foreach (var data in InstanceMethodsTestData(type_name)) { yield return new object[] { "", 0 }.Concat(data).ToArray(); yield return new object[] { "this.", 0 }.Concat(data).ToArray(); yield return new object[] { "NewInstance.", 3 }.Concat(data).ToArray(); yield return new object[] { "this.NewInstance.", 3 }.Concat(data).ToArray(); } } [ConditionalTheory(nameof(RunningOnChrome))] [MemberData(nameof(InstanceMethodForTypeMembersTestData), parameters: "DebuggerTests.EvaluateTestsStructWithProperties")] [MemberData(nameof(InstanceMethodForTypeMembersTestData), parameters: "DebuggerTests.EvaluateTestsClassWithProperties")] public async Task EvaluateTypeInstanceMembers(string prefix, int bias, string type, string method, string bp_function_name, bool is_async) => await CheckInspectLocalsAtBreakpointSite( type, method, /*line_offset*/1, bp_function_name, $"window.setTimeout(function() {{ invoke_static_method_async('[debugger-test] {type}:run');}}, 1);", wait_for_event_fn: async (pause_location) => { var id = pause_location["callFrames"][0]["callFrameId"].Value(); var dateTime = new DateTime(2010, 9, 8, 7, 6, 5 + bias); var DTProp = dateTime.AddMinutes(10); foreach (var pad in new[] { String.Empty, " " }) { var padded_prefix = pad + prefix; await EvaluateOnCallFrameAndCheck(id, ($"{padded_prefix}a", TNumber(4)), // fields ($"{padded_prefix}dateTime.TimeOfDay", TValueType("System.TimeSpan", dateTime.TimeOfDay.ToString())), ($"{padded_prefix}dateTime", TDateTime(dateTime)), ($"{padded_prefix}dateTime.TimeOfDay.Minutes", TNumber(dateTime.TimeOfDay.Minutes)), // properties ($"{padded_prefix}DTProp.TimeOfDay.Minutes", TNumber(DTProp.TimeOfDay.Minutes)), ($"{padded_prefix}DTProp", TDateTime(DTProp)), ($"{padded_prefix}DTProp.TimeOfDay", TValueType("System.TimeSpan", DTProp.TimeOfDay.ToString())), ($"{padded_prefix}IntProp", TNumber(9)), ($"{padded_prefix}NullIfAIsNotZero", TObject("DebuggerTests.EvaluateTestsClassWithProperties", is_null: true)) ); } }); [Theory] [MemberData(nameof(InstanceMethodsTestData), parameters: "DebuggerTests.EvaluateTestsStructWithProperties")] [MemberData(nameof(InstanceMethodsTestData), parameters: "DebuggerTests.EvaluateTestsClassWithProperties")] public async Task EvaluateInstanceMethodArguments(string type, string method, string bp_function_name, bool is_async) => await CheckInspectLocalsAtBreakpointSite( type, method, /*line_offset*/1, bp_function_name, $"window.setTimeout(function() {{ invoke_static_method_async('[debugger-test] {type}:run');}}, 1);", wait_for_event_fn: async (pause_location) => { var id = pause_location["callFrames"][0]["callFrameId"].Value(); var DTProp = new DateTime(2010, 9, 8, 7, 6, 5).AddMinutes(10); _testOutput.WriteLine ($"------- test running the bits.."); await EvaluateOnCallFrameAndCheck(id, ("g", TNumber(400)), ("h", TNumber(123)), ("valString", TString("just a test")), ("me", TObject(type)), // property on method arg ("me.DTProp", TDateTime(DTProp)), ("me.DTProp.TimeOfDay.Minutes", TNumber(DTProp.TimeOfDay.Minutes)), ("me.DTProp.Second + (me.IntProp - 5)", TNumber(DTProp.Second + 4))) .ConfigureAwait(false); _testOutput.WriteLine ($"------- test done!"); }); [Theory] [MemberData(nameof(InstanceMethodsTestData), parameters: "DebuggerTests.EvaluateTestsStructWithProperties")] [MemberData(nameof(InstanceMethodsTestData), parameters: "DebuggerTests.EvaluateTestsClassWithProperties")] public async Task EvaluateMethodLocals(string type, string method, string bp_function_name, bool is_async) => await CheckInspectLocalsAtBreakpointSite( type, method, /*line_offset*/5, bp_function_name, $"window.setTimeout(function() {{ invoke_static_method_async('[debugger-test] {type}:run');}}, 1);", wait_for_event_fn: async (pause_location) => { var id = pause_location["callFrames"][0]["callFrameId"].Value(); var dt = new DateTime(2025, 3, 5, 7, 9, 11); await EvaluateOnCallFrameAndCheck(id, (" d ", TNumber(401)), ("d", TNumber(401)), (" d", TNumber(401)), ("e", TNumber(402)), ("f", TNumber(403)), // property on a local ("local_dt", TDateTime(dt)), (" local_dt", TDateTime(dt)), ("local_dt.Date", TDateTime(dt.Date)), (" local_dt.Date", TDateTime(dt.Date))); }); [ConditionalFact(nameof(RunningOnChrome))] public async Task EvaluateStaticLocalsWithDeepMemberAccess() => await CheckInspectLocalsAtBreakpointSite( "DebuggerTests.EvaluateTestsClass", "EvaluateLocals", 9, "DebuggerTests.EvaluateTestsClass.EvaluateLocals", "window.setTimeout(function() { invoke_static_method ('[debugger-test] DebuggerTests.EvaluateTestsClass:EvaluateLocals'); })", wait_for_event_fn: async (pause_location) => { var id = pause_location["callFrames"][0]["callFrameId"].Value(); var dt = new DateTime(2020, 1, 2, 3, 4, 5); await EvaluateOnCallFrameAndCheck(id, ("f_s.c", TNumber(4)), ("f_s", TValueType("DebuggerTests.EvaluateTestsStructWithProperties")), ("f_s.dateTime", TDateTime(dt)), ("f_s.dateTime.Date", TDateTime(dt.Date))); }); [ConditionalFact(nameof(RunningOnChrome))] public async Task EvaluateLocalsAsync() => await CheckInspectLocalsAtBreakpointSite( "DebuggerTests.Point", "AsyncInstanceMethod", 1, "DebuggerTests.Point.AsyncInstanceMethod", "window.setTimeout(function() { invoke_static_method_async ('[debugger-test] DebuggerTests.ArrayTestsClass:EntryPointForStructMethod', true); })", wait_for_event_fn: async (pause_location) => { var id = pause_location["callFrames"][0]["callFrameId"].Value(); // sc_arg { var (sc_arg, _) = await EvaluateOnCallFrame(id, "sc_arg"); await CheckValue(sc_arg, TObject("DebuggerTests.SimpleClass"), nameof(sc_arg)); // Check that we did get the correct object var sc_arg_props = await GetProperties(sc_arg["objectId"]?.Value()); await CheckProps(sc_arg_props, new { X = TNumber(10), Y = TNumber(45), Id = TString("sc#Id"), Color = TEnum("DebuggerTests.RGB", "Blue"), PointWithCustomGetter = TGetter("PointWithCustomGetter") }, "sc_arg_props#1"); await EvaluateOnCallFrameAndCheck(id, ("(sc_arg.PointWithCustomGetter.X)", TNumber(100)), ("sc_arg.Id + \"_foo\"", TString($"sc#Id_foo")), ("sc_arg.Id + (sc_arg.X==10 ? \"_is_ten\" : \"_not_ten\")", TString($"sc#Id_is_ten"))); } // local_gs { var (local_gs, _) = await EvaluateOnCallFrame(id, "local_gs"); await CheckValue(local_gs, TValueType("DebuggerTests.SimpleGenericStruct"), nameof(local_gs)); (local_gs, _) = await EvaluateOnCallFrame(id, " local_gs"); await CheckValue(local_gs, TValueType("DebuggerTests.SimpleGenericStruct"), nameof(local_gs)); var local_gs_props = await GetProperties(local_gs["objectId"]?.Value()); await CheckProps(local_gs_props, new { Id = TObject("string", is_null: true), Color = TEnum("DebuggerTests.RGB", "Red"), Value = TNumber(0) }, "local_gs_props#1"); await EvaluateOnCallFrameAndCheck(id, ("(local_gs.Id)", TString(null))); } }); [ConditionalTheory(nameof(RunningOnChrome))] [MemberData(nameof(InstanceMethodForTypeMembersTestData), parameters: "DebuggerTests.EvaluateTestsStructWithProperties")] [MemberData(nameof(InstanceMethodForTypeMembersTestData), parameters: "DebuggerTests.EvaluateTestsClassWithProperties")] public async Task EvaluateExpressionsWithDeepMemberAccesses(string prefix, int bias, string type, string method, string bp_function_name, bool _) => await CheckInspectLocalsAtBreakpointSite( type, method, /*line_offset*/4, bp_function_name, $"window.setTimeout(function() {{ invoke_static_method_async('[debugger-test] {type}:run');}}, 1);", wait_for_event_fn: async (pause_location) => { var id = pause_location["callFrames"][0]["callFrameId"].Value(); var dateTime = new DateTime(2010, 9, 8, 7, 6, 5 + bias); var DTProp = dateTime.AddMinutes(10); await EvaluateOnCallFrameAndCheck(id, ($"{prefix}a + 5", TNumber(9)), ($"10 + {prefix}IntProp", TNumber(19)), ($" {prefix}IntProp + {prefix}DTProp.Second", TNumber(9 + DTProp.Second)), ($" {prefix}IntProp + ({prefix}DTProp.Second+{prefix}dateTime.Year)", TNumber(9 + DTProp.Second + dateTime.Year)), ($" {prefix}DTProp.Second > 0 ? \"_foo_\": \"_zero_\"", TString("_foo_")), // local_dt is not live yet ($"local_dt.Date.Year * 10", TNumber(10))); }); [Theory] [InlineData("")] [InlineData("this.")] public async Task InheritedAndPrivateMembersInAClass(string prefix) => await CheckInspectLocalsAtBreakpointSite( "DebuggerTests.GetPropertiesTests.DerivedClass", "InstanceMethod", 1, "DebuggerTests.GetPropertiesTests.DerivedClass.InstanceMethod", $"window.setTimeout(function() {{ invoke_static_method_async('[debugger-test] DebuggerTests.GetPropertiesTests.DerivedClass:run');}}, 1);", wait_for_event_fn: async (pause_location) => { var id = pause_location["callFrames"][0]["callFrameId"].Value(); foreach (var pad in new[] { String.Empty, " " }) { var padded_prefix = pad + prefix; await EvaluateOnCallFrameAndCheck(id, // overridden ($"{padded_prefix}FirstName + \"_foo\"", TString("DerivedClass#FirstName_foo")), ($"{padded_prefix}DateTimeForOverride.Date.Year", TNumber(2190)), ($"{padded_prefix}DateTimeForOverride.Date.Year - 10", TNumber(2180)), ($"\"foo_\" + {padded_prefix}StringPropertyForOverrideWithAutoProperty", TString("foo_DerivedClass#StringPropertyForOverrideWithAutoProperty")), // private ($"{padded_prefix}_stringField + \"_foo\"", TString("DerivedClass#_stringField_foo")), ($"{padded_prefix}_stringField", TString("DerivedClass#_stringField")), ($"{padded_prefix}_dateTime.Second + 4", TNumber(7)), ($"{padded_prefix}_DTProp.Second + 4", TNumber(13)), // inherited public ($"\"foo_\" + {padded_prefix}Base_AutoStringProperty", TString("foo_base#Base_AutoStringProperty")), // inherited private ($"{padded_prefix}_base_dateTime.Date.Year - 10", TNumber(2124)) ); } }); [Fact] public async Task EvaluateSimpleExpressions() => await CheckInspectLocalsAtBreakpointSite( "DebuggerTests.EvaluateTestsClass.TestEvaluate", "run", 9, "DebuggerTests.EvaluateTestsClass.TestEvaluate.run", "window.setTimeout(function() { invoke_static_method ('[debugger-test] DebuggerTests.EvaluateTestsClass:EvaluateLocals'); })", wait_for_event_fn: async (pause_location) => { var id = pause_location["callFrames"][0]["callFrameId"].Value(); await EvaluateOnCallFrameAndCheck(id, // "((this))", TObject("foo")); //FIXME: // "((dt))", TObject("foo")); //FIXME: ("this", TObject("DebuggerTests.EvaluateTestsClass.TestEvaluate")), (" this", TObject("DebuggerTests.EvaluateTestsClass.TestEvaluate")), ("5", TNumber(5)), (" 5", TNumber(5)), ("d + e", TNumber(203)), ("e + 10", TNumber(112)), // repeated expressions ("this.a + this.a", TNumber(2)), ("a + \"_\" + a", TString("9000_9000")), ("a+(a )", TString("90009000")), // possible duplicate arg name ("this.a + this_a", TNumber(46)), ("this.a + this.b", TNumber(3)), ("\"test\" + \"test\"", TString("testtest")), ("5 + 5", TNumber(10))); }); public static TheoryData ShadowMethodArgsTestData => new TheoryData { { "DebuggerTests.EvaluateTestsClassWithProperties", "EvaluateShadow", "DebuggerTests.EvaluateTestsClassWithProperties.EvaluateShadow" }, { "DebuggerTests.EvaluateTestsClassWithProperties", "EvaluateShadowAsync", "DebuggerTests.EvaluateTestsClassWithProperties.EvaluateShadowAsync" }, { "DebuggerTests.EvaluateTestsStructWithProperties", "EvaluateShadow", "DebuggerTests.EvaluateTestsStructWithProperties.EvaluateShadow" }, { "DebuggerTests.EvaluateTestsStructWithProperties", "EvaluateShadowAsync", "DebuggerTests.EvaluateTestsStructWithProperties.EvaluateShadowAsync" }, }; [Theory] [MemberData(nameof(ShadowMethodArgsTestData))] public async Task LocalsAndArgsShadowingThisMembers(string type_name, string method, string bp_function_name) => await CheckInspectLocalsAtBreakpointSite( type_name, method, 2, bp_function_name, "window.setTimeout(function() { invoke_static_method ('[debugger-test] " + type_name + ":run'); })", wait_for_event_fn: async (pause_location) => { var id = pause_location["callFrames"][0]["callFrameId"].Value(); await EvaluateOnCallFrameAndCheck(id, ("a", TString("hello")), ("this.a", TNumber(4))); await CheckExpressions("this.", new DateTime(2010, 9, 8, 7, 6, 5 + 0)); await CheckExpressions(String.Empty, new DateTime(2020, 3, 4, 5, 6, 7)); async Task CheckExpressions(string prefix, DateTime dateTime) { await EvaluateOnCallFrameAndCheck(id, (prefix + "dateTime", TDateTime(dateTime)), (prefix + "dateTime.TimeOfDay.Minutes", TNumber(dateTime.TimeOfDay.Minutes)), (prefix + "dateTime.TimeOfDay", TValueType("System.TimeSpan", dateTime.TimeOfDay.ToString()))); } }); [ConditionalTheory(nameof(RunningOnChrome))] [InlineData("DebuggerTests.EvaluateTestsStructWithProperties", true)] [InlineData("DebuggerTests.EvaluateTestsClassWithProperties", false)] public async Task EvaluateOnPreviousFrames(string type_name, bool is_valuetype) => await CheckInspectLocalsAtBreakpointSite( type_name, "EvaluateShadow", 1, $"{type_name}.EvaluateShadow", $"window.setTimeout(function() {{ invoke_static_method ('[debugger-test] {type_name}:run'); }})", wait_for_event_fn: async (pause_location) => { var dt_local = new DateTime(2020, 3, 4, 5, 6, 7); var dt_this = new DateTime(2010, 9, 8, 7, 6, 5); // At EvaluateShadow { var id0 = pause_location["callFrames"][0]["callFrameId"].Value(); await EvaluateOnCallFrameAndCheck(id0, ("dateTime", TDateTime(dt_local)), ("this.dateTime", TDateTime(dt_this)) ); await EvaluateOnCallFrameFail(id0, ("obj.IntProp", "ReferenceError")); } { var id1 = pause_location["callFrames"][1]["callFrameId"].Value(); await EvaluateOnCallFrameFail(id1, ("dateTime", "ReferenceError"), ("this.dateTime", "ReferenceError")); // obj available only on the -1 frame await EvaluateOnCallFrameAndCheck(id1, ("obj.IntProp", TNumber(7))); } await SetBreakpointInMethod("debugger-test.dll", type_name, "SomeMethod", 1); pause_location = await SendCommandAndCheck(null, "Debugger.resume", null, 0, 0, $"{type_name}.SomeMethod"); // At SomeMethod // TODO: change types also.. so, that `this` is different! // Check frame0 { var id0 = pause_location["callFrames"][0]["callFrameId"].Value(); // 'me' and 'dateTime' are reversed in this method await EvaluateOnCallFrameAndCheck(id0, ("dateTime", is_valuetype ? TValueType(type_name) : TObject(type_name)), ("this.dateTime", TDateTime(dt_this)), ("me", TDateTime(dt_local)), // local variable shadows field, but isn't "live" yet ("DTProp", TString(null)), // access field via `this.` ("this.DTProp", TDateTime(dt_this.AddMinutes(10)))); await EvaluateOnCallFrameFail(id0, ("obj", "ReferenceError")); } // check frame1 { var id1 = pause_location["callFrames"][1]["callFrameId"].Value(); await EvaluateOnCallFrameAndCheck(id1, // 'me' and 'dateTime' are reversed in this method ("dateTime", TDateTime(dt_local)), ("this.dateTime", TDateTime(dt_this)), ("me", is_valuetype ? TValueType(type_name) : TObject(type_name)), // not shadowed here ("DTProp", TDateTime(dt_this.AddMinutes(10))), // access field via `this.` ("this.DTProp", TDateTime(dt_this.AddMinutes(10)))); await EvaluateOnCallFrameFail(id1, ("obj", "ReferenceError")); } // check frame2 { var id2 = pause_location["callFrames"][2]["callFrameId"].Value(); // Only obj should be available await EvaluateOnCallFrameFail(id2, ("dateTime", "ReferenceError"), ("this.dateTime", "ReferenceError"), ("me", "ReferenceError")); await EvaluateOnCallFrameAndCheck(id2, ("obj", is_valuetype ? TValueType(type_name) : TObject(type_name))); } }); [ConditionalFact(nameof(RunningOnChrome))] public async Task JSEvaluate() { var bp_loc = "/other.js"; var line = 78; var col = 1; await SetBreakpoint(bp_loc, line, col); var eval_expr = "window.setTimeout(function() { eval_call_on_frame_test (); }, 1)"; var result = await cli.SendCommand("Runtime.evaluate", JObject.FromObject(new { expression = eval_expr }), token); var pause_location = await insp.WaitFor(Inspector.PAUSE); var id = pause_location["callFrames"][0]["callFrameId"].Value(); await EvaluateOnCallFrameFail(id, ("me.foo", null), ("obj.foo.bar", null)); await EvaluateOnCallFrame(id, "obj.foo", expect_ok: true); } [ConditionalFact(nameof(RunningOnChrome))] public async Task NegativeTestsInInstanceMethod() => await CheckInspectLocalsAtBreakpointSite( "DebuggerTests.EvaluateTestsClass.TestEvaluate", "run", 9, "DebuggerTests.EvaluateTestsClass.TestEvaluate.run", "window.setTimeout(function() { invoke_static_method ('[debugger-test] DebuggerTests.EvaluateTestsClass:EvaluateLocals'); })", wait_for_event_fn: async (pause_location) => { var id = pause_location["callFrames"][0]["callFrameId"].Value(); // Use '.' on a primitive member await EvaluateOnCallFrameFail(id, //BUG: TODO: //("a)", "CompilationError"), ("this.a.", "ReferenceError"), ("a.", "ReferenceError"), ("this..a", "CompilationError"), (".a.", "ReferenceError"), ("me.foo", "ReferenceError"), ("this.a + non_existent", "ReferenceError"), ("this.NullIfAIsNotZero.foo", "ReferenceError"), ("NullIfAIsNotZero.foo", "ReferenceError")); }); [ConditionalFact(nameof(RunningOnChrome))] public async Task NegativeTestsInStaticMethod() => await CheckInspectLocalsAtBreakpointSite( "DebuggerTests.EvaluateTestsClass", "EvaluateLocals", 9, "DebuggerTests.EvaluateTestsClass.EvaluateLocals", "window.setTimeout(function() { invoke_static_method ('[debugger-test] DebuggerTests.EvaluateTestsClass:EvaluateLocals'); })", wait_for_event_fn: async (pause_location) => { var id = pause_location["callFrames"][0]["callFrameId"].Value(); await EvaluateOnCallFrameFail(id, ("me.foo", "ReferenceError"), ("this", "CompilationError"), ("this.NullIfAIsNotZero.foo", "ReferenceError")); }); [Fact] public async Task EvaluatePropertyThatThrows() => await CheckInspectLocalsAtBreakpointSite( "DebuggerTests.EvaluateTestsClassWithProperties", "InstanceMethod", /*line_offset*/1, "DebuggerTests.EvaluateTestsClassWithProperties.InstanceMethod", $"window.setTimeout(function() {{ invoke_static_method_async('[debugger-test] DebuggerTests.EvaluateTestsClassWithProperties:run');}}, 1);", wait_for_event_fn: async (pause_location) => { var id = pause_location["callFrames"][0]["callFrameId"].Value(); await EvaluateOnCallFrameAndCheck(id, ("this.PropertyThrowException", TString("System.Exception: error"))); }); async Task EvaluateOnCallFrameFail(string call_frame_id, params (string expression, string class_name)[] args) { foreach (var arg in args) { var (_, res) = await EvaluateOnCallFrame(call_frame_id, arg.expression, expect_ok: false); if (arg.class_name != null) AssertEqual(arg.class_name, res.Error["result"]?["className"]?.Value(), $"Error className did not match for expression '{arg.expression}'"); } } [ConditionalFact(nameof(RunningOnChrome))] public async Task EvaluateSimpleMethodCallsError() => await CheckInspectLocalsAtBreakpointSite( "DebuggerTests.EvaluateMethodTestsClass.TestEvaluate", "run", 9, "DebuggerTests.EvaluateMethodTestsClass.TestEvaluate.run", "window.setTimeout(function() { invoke_static_method ('[debugger-test] DebuggerTests.EvaluateMethodTestsClass:EvaluateMethods'); })", wait_for_event_fn: async (pause_location) => { var id = pause_location["callFrames"][0]["callFrameId"].Value(); var (_, res) = await EvaluateOnCallFrame(id, "this.objToTest.MyMethodWrong()", expect_ok: false ); Assert.Equal( $"Method 'MyMethodWrong' not found in type 'DebuggerTests.EvaluateMethodTestsClass.ParmToTest'", res.Error["result"]?["description"]?.Value()); (_, res) = await EvaluateOnCallFrame(id, "this.objToTest.MyMethod(1)", expect_ok: false); Assert.Equal( "Unable to evaluate method 'MyMethod'. Too many arguments passed.", res.Error["result"]?["description"]?.Value()); (_, res) = await EvaluateOnCallFrame(id, "this.CallMethodWithParm(\"1\")", expect_ok: false ); Assert.Contains("No implementation of method 'CallMethodWithParm' matching 'this.CallMethodWithParm(\"1\")' found in type DebuggerTests.EvaluateMethodTestsClass.TestEvaluate.", res.Error["result"]?["description"]?.Value()); (_, res) = await EvaluateOnCallFrame(id, "this.ParmToTestObjNull.MyMethod()", expect_ok: false ); Assert.Equal("Expression 'this.ParmToTestObjNull.MyMethod' evaluated to null", res.Error["message"]?.Value()); (_, res) = await EvaluateOnCallFrame(id, "this.ParmToTestObjException.MyMethod()", expect_ok: false ); Assert.Equal("Method 'MyMethod' not found in type 'string'", res.Error["result"]?["description"]?.Value()); }); [Fact] public async Task EvaluateSimpleMethodCallsWithoutParms() => await CheckInspectLocalsAtBreakpointSite( "DebuggerTests.EvaluateMethodTestsClass.TestEvaluate", "run", 9, "DebuggerTests.EvaluateMethodTestsClass.TestEvaluate.run", "window.setTimeout(function() { invoke_static_method ('[debugger-test] DebuggerTests.EvaluateMethodTestsClass:EvaluateMethods'); })", wait_for_event_fn: async (pause_location) => { var id = pause_location["callFrames"][0]["callFrameId"].Value(); await EvaluateOnCallFrameAndCheck(id, ("this.CallMethod()", TNumber(1)), ("this.CallMethod()", TNumber(1)), ("this.CallMethodReturningChar()", TChar('A')), ("this.ParmToTestObj.MyMethod()", TString("methodOK")), ("this.ParmToTestObj.ToString()", TString("DebuggerTests.EvaluateMethodTestsClass+ParmToTest")), ("this.objToTest.MyMethod()", TString("methodOK"))); }); [Fact] public async Task EvaluateSimpleMethodCallsWithConstParms() => await CheckInspectLocalsAtBreakpointSite( "DebuggerTests.EvaluateMethodTestsClass.TestEvaluate", "run", 9, "DebuggerTests.EvaluateMethodTestsClass.TestEvaluate.run", "window.setTimeout(function() { invoke_static_method ('[debugger-test] DebuggerTests.EvaluateMethodTestsClass:EvaluateMethods'); })", wait_for_event_fn: async (pause_location) => { var id = pause_location["callFrames"][0]["callFrameId"].Value(); await EvaluateOnCallFrameAndCheck(id, ("this.CallMethodWithParm(10)", TNumber(11)), ("this.CallMethodWithMultipleParms(10, 10)", TNumber(21)), ("this.CallMethodWithParmBool(true)", TString("TRUE")), ("this.CallMethodWithParmBool(false)", TString("FALSE")), ("this.CallMethodWithParmString(\"concat\")", TString("str_const_concat")), ("this.CallMethodWithParmString(\"\\\"\\\"\")", TString("str_const_\"\"")), ("this.CallMethodWithParmString(\"\uD83D\uDEF6\")", TString("str_const_\uD83D\uDEF6")), ("this.CallMethodWithParmString(\"\\uD83D\\uDEF6\")", TString("str_const_\uD83D\uDEF6")), ("this.CallMethodWithParmString(\"\uD83D\uDE80\")", TString("str_const_\uD83D\uDE80")), ("this.CallMethodWithParmString_\u03BB(\"\uD83D\uDE80\")", TString("\u03BB_\uD83D\uDE80")), ("this.CallMethodWithParm(10) + this.a", TNumber(12)), ("this.CallMethodWithObj(null)", TNumber(-1)), ("this.CallMethodWithChar('a')", TString("str_const_a"))); }); [Fact] public async Task EvaluateSimpleMethodCallsWithVariableParms() => await CheckInspectLocalsAtBreakpointSite( "DebuggerTests.EvaluateMethodTestsClass.TestEvaluate", "run", 9, "DebuggerTests.EvaluateMethodTestsClass.TestEvaluate.run", "window.setTimeout(function() { invoke_static_method ('[debugger-test] DebuggerTests.EvaluateMethodTestsClass:EvaluateMethods'); })", wait_for_event_fn: async (pause_location) => { var id = pause_location["callFrames"][0]["callFrameId"].Value(); await EvaluateOnCallFrameAndCheck(id, ("this.CallMethodWithParm(this.a)", TNumber(2)), ("this.CallMethodWithMultipleParms(this.a, 10)", TNumber(12)), ("this.CallMethodWithParmString(this.str)", TString("str_const_str_const_")), ("this.CallMethodWithParmBool(this.t)", TString("TRUE")), ("this.CallMethodWithParmBool(this.f)", TString("FALSE")), ("this.CallMethodWithParm(this.a) + this.a", TNumber(3)), ("this.CallMethodWithObj(this.objToTest)", TNumber(10))); }); [ConditionalFact(nameof(RunningOnChrome))] public async Task EvaluateIndexingNegative() => await CheckInspectLocalsAtBreakpointSite( "DebuggerTests.EvaluateLocalsWithIndexingTests", "EvaluateLocals", 5, "DebuggerTests.EvaluateLocalsWithIndexingTests.EvaluateLocals", $"window.setTimeout(function() {{ invoke_static_method ('[debugger-test] DebuggerTests.EvaluateLocalsWithIndexingTests:EvaluateLocals'); 1 }})", wait_for_event_fn: async (pause_location) => { var id = pause_location["callFrames"][0]["callFrameId"].Value(); var (_, res) = await EvaluateOnCallFrame(id, "f.idx0[2]", expect_ok: false ); Assert.Equal("Unable to evaluate element access 'f.idx0[2]': Cannot apply indexing with [] to a primitive object of type 'number'", res.Error["message"]?.Value()); (_, res) = await EvaluateOnCallFrame(id, "f[1]", expect_ok: false ); Assert.Equal( "Unable to evaluate element access 'f[1]': Cannot apply indexing with [] to an object of type 'DebuggerTests.EvaluateLocalsWithIndexingTests.TestEvaluate'", res.Error["message"]?.Value()); }); [Fact] public async Task EvaluateIndexingsByConstant() => await CheckInspectLocalsAtBreakpointSite( "DebuggerTests.EvaluateLocalsWithIndexingTests", "EvaluateLocals", 5, "DebuggerTests.EvaluateLocalsWithIndexingTests.EvaluateLocals", "window.setTimeout(function() { invoke_static_method ('[debugger-test] DebuggerTests.EvaluateLocalsWithIndexingTests:EvaluateLocals'); })", wait_for_event_fn: async (pause_location) => { var id = pause_location["callFrames"][0]["callFrameId"].Value(); await EvaluateOnCallFrameAndCheck(id, ("f.numList[0]", TNumber(1)), ("f.textList[1]", TString("2")), ("f.numArray[1]", TNumber(2)), ("f.textArray[0]", TString("1"))); }); [Fact] public async Task EvaluateIndexingByLocalVariable() => await CheckInspectLocalsAtBreakpointSite( "DebuggerTests.EvaluateLocalsWithIndexingTests", "EvaluateLocals", 5, "DebuggerTests.EvaluateLocalsWithIndexingTests.EvaluateLocals", "window.setTimeout(function() { invoke_static_method ('[debugger-test] DebuggerTests.EvaluateLocalsWithIndexingTests:EvaluateLocals'); })", wait_for_event_fn: async (pause_location) => { var id = pause_location["callFrames"][0]["callFrameId"].Value(); await EvaluateOnCallFrameAndCheck(id, ("f.numList[i]", TNumber(1)), ("f.textList[j]", TString("2")), ("f.numArray[j]", TNumber(2)), ("f.textArray[i]", TString("1"))); }); [Fact] public async Task EvaluateObjectIndexingByNonIntConst() => await CheckInspectLocalsAtBreakpointSite( "DebuggerTests.EvaluateLocalsWithIndexingTests", "EvaluateLocals", 5, "DebuggerTests.EvaluateLocalsWithIndexingTests.EvaluateLocals", "window.setTimeout(function() { invoke_static_method ('[debugger-test] DebuggerTests.EvaluateLocalsWithIndexingTests:EvaluateLocals'); })", wait_for_event_fn: async (pause_location) => { var id = pause_location["callFrames"][0]["callFrameId"].Value(); await EvaluateOnCallFrameAndCheck(id, ("f[\"longstring\"]", TBool(true)), ("f[\"-\"]", TBool(false)), ("f[\'-\']", TString("res_-")), ("f[true]", TString("True")), // ("f[1.23]", TNumber(1)) // Not supported yet - float/double // FixMe: https://github.com/dotnet/runtime/issues/76013 // ("f.indexedByStr[\"1\"]", TBool(true)) // keyNotFoundException // ("f.indexedByStr[\"111\"]", TBool(false)), // keyNotFoundException // ("f.indexedByStr[\"true\"]", TBool(true)), // keyNotFoundException ("f.indexedByChar[\'i\']", TString("I")), ("f.indexedByChar[\'5\']", TString("5")), ("f.indexedByBool[true]", TString("TRUE")), ("f.indexedByBool[false]", TString("FALSE")) ); }); [Fact] public async Task EvaluateObjectByNonIntLocals() => await CheckInspectLocalsAtBreakpointSite( "DebuggerTests.EvaluateLocalsWithIndexingTests", "EvaluateLocals", 12, "DebuggerTests.EvaluateLocalsWithIndexingTests.EvaluateLocals", "window.setTimeout(function() { invoke_static_method ('[debugger-test] DebuggerTests.EvaluateLocalsWithIndexingTests:EvaluateLocals'); })", wait_for_event_fn: async (pause_location) => { var id = pause_location["callFrames"][0]["callFrameId"].Value(); await EvaluateOnCallFrameAndCheck(id, ("f[longString]", TBool(true)), ("f[aBool]", TString("True")), ("f[aChar]", TString("res_9")), ("f[shortString]", TBool(false)) // ("f[aFloat]", TNumber(1)), // ("f[aDouble]", TNumber(2)), // FixMe: https://github.com/dotnet/runtime/issues/76014 // ("f[aDecimal]", TNumber(3)) // object ); }); [Fact] public async Task EvaluateNestedObjectIndexingByNonIntLocals() => await CheckInspectLocalsAtBreakpointSite( "DebuggerTests.EvaluateLocalsWithIndexingTests", "EvaluateLocals", 12, "DebuggerTests.EvaluateLocalsWithIndexingTests.EvaluateLocals", "window.setTimeout(function() { invoke_static_method ('[debugger-test] DebuggerTests.EvaluateLocalsWithIndexingTests:EvaluateLocals'); })", wait_for_event_fn: async (pause_location) => { var id = pause_location["callFrames"][0]["callFrameId"].Value(); await EvaluateOnCallFrameAndCheck(id, ("f[f.textArray[0]]", TBool(false)), // f["1"] ("f[f.textArray[j]]", TBool(false)) // f["2"] ); }); // ToDo: https://github.com/dotnet/runtime/issues/76015 [Fact] public async Task EvaluateIndexingByExpression() => await CheckInspectLocalsAtBreakpointSite( "DebuggerTests.EvaluateLocalsWithIndexingTests", "EvaluateLocals", 5, "DebuggerTests.EvaluateLocalsWithIndexingTests.EvaluateLocals", "window.setTimeout(function() { invoke_static_method ('[debugger-test] DebuggerTests.EvaluateLocalsWithIndexingTests:EvaluateLocals'); })", wait_for_event_fn: async (pause_location) => { var id = pause_location["callFrames"][0]["callFrameId"].Value(); await EvaluateOnCallFrameAndCheck(id, ("f.numList[i + 1]", TNumber(2)), ("f.textList[(2 * j) - 1]", TString("2")), ("f.textList[j - 1]", TString("1")), ("f.numArray[f.numList[j - 1]]", TNumber(2)) ); }); [Fact] public async Task EvaluateIndexingByExpressionMultidimensional() => await CheckInspectLocalsAtBreakpointSite( "DebuggerTests.EvaluateLocalsWithMultidimensionalIndexingTests", "EvaluateLocals", 5, "DebuggerTests.EvaluateLocalsWithMultidimensionalIndexingTests.EvaluateLocals", "window.setTimeout(function() { invoke_static_method ('[debugger-test] DebuggerTests.EvaluateLocalsWithMultidimensionalIndexingTests:EvaluateLocals'); })", wait_for_event_fn: async (pause_location) => { var id = pause_location["callFrames"][0]["callFrameId"].Value(); await EvaluateOnCallFrameAndCheck(id, ("f.numArray2D[0, j - 1]", TNumber(1)), // 0, 0 ("f.numArray2D[f.idx1, i + j]", TNumber(4)), // 1, 1 ("f.numArray2D[(f.idx1 - j) * 5, i + j]", TNumber(2)), // 0, 1 ("f.numArray2D[i + j, f.idx1 - 1]", TNumber(3)) // 1, 0 ); }); [ConditionalFact(nameof(RunningOnChrome))] public async Task EvaluateIndexingByExpressionNegative() => await CheckInspectLocalsAtBreakpointSite( "DebuggerTests.EvaluateLocalsWithIndexingTests", "EvaluateLocals", 5, "DebuggerTests.EvaluateLocalsWithIndexingTests.EvaluateLocals", $"window.setTimeout(function() {{ invoke_static_method ('[debugger-test] DebuggerTests.EvaluateLocalsWithIndexingTests:EvaluateLocals'); 1 }})", wait_for_event_fn: async (pause_location) => { // indexing with expression of a wrong type var id = pause_location["callFrames"][0]["callFrameId"].Value(); var (_, res) = await EvaluateOnCallFrame(id, "f.numList[\"a\" + 1]", expect_ok: false ); Assert.Equal("Unable to evaluate element access 'f.numList[\"a\" + 1]': Cannot index with an object of type 'string'", res.Error["message"]?.Value()); }); [ConditionalFact(nameof(RunningOnChrome))] public async Task EvaluateIndexingByExpressionContainingUnknownIdentifier() => await CheckInspectLocalsAtBreakpointSite( "DebuggerTests.EvaluateLocalsWithIndexingTests", "EvaluateLocals", 5, "DebuggerTests.EvaluateLocalsWithIndexingTests.EvaluateLocals", $"window.setTimeout(function() {{ invoke_static_method ('[debugger-test] DebuggerTests.EvaluateLocalsWithIndexingTests:EvaluateLocals'); 1 }})", wait_for_event_fn: async (pause_location) => { // indexing with expression of a wrong type var id = pause_location["callFrames"][0]["callFrameId"].Value(); var (_, res) = await EvaluateOnCallFrame(id, "f.numList[\"a\" + x]", expect_ok: false); Assert.Equal("The name x does not exist in the current context", res.Error["result"]?["description"]?.Value()); }); [Fact] public async Task EvaluateIndexingByMemberVariables() => await CheckInspectLocalsAtBreakpointSite( "DebuggerTests.EvaluateLocalsWithIndexingTests", "EvaluateLocals", 5, "DebuggerTests.EvaluateLocalsWithIndexingTests.EvaluateLocals", "window.setTimeout(function() { invoke_static_method ('[debugger-test] DebuggerTests.EvaluateLocalsWithIndexingTests:EvaluateLocals'); })", wait_for_event_fn: async (pause_location) => { var id = pause_location["callFrames"][0]["callFrameId"].Value(); await EvaluateOnCallFrameAndCheck(id, ("f.idx0", TNumber(0)), ("f.idx1", TNumber(1)), ("f.numList[f.idx0]", TNumber(1)), ("f.textList[f.idx1]", TString("2")), ("f.numArray[f.idx1]", TNumber(2)), ("f.textArray[f.idx0]", TString("1"))); }); [Fact] public async Task EvaluateIndexingNested() => await CheckInspectLocalsAtBreakpointSite( "DebuggerTests.EvaluateLocalsWithIndexingTests", "EvaluateLocals", 5, "DebuggerTests.EvaluateLocalsWithIndexingTests.EvaluateLocals", "window.setTimeout(function() { invoke_static_method ('[debugger-test] DebuggerTests.EvaluateLocalsWithIndexingTests:EvaluateLocals'); })", wait_for_event_fn: async (pause_location) => { var id = pause_location["callFrames"][0]["callFrameId"].Value(); await EvaluateOnCallFrameAndCheck(id, ("f.idx0", TNumber(0)), ("f.numList[f.numList[f.idx0]]", TNumber(2)), ("f.textList[f.numList[f.idx0]]", TString("2")), ("f.numArray[f.numArray[f.idx0]]", TNumber(2)), ("f.textArray[f.numArray[f.idx0]]", TString("2"))); }); [ConditionalFact(nameof(RunningOnChrome))] public async Task EvaluateIndexingMultidimensional() => await CheckInspectLocalsAtBreakpointSite( "DebuggerTests.EvaluateLocalsWithMultidimensionalIndexingTests", "EvaluateLocals", 5, "DebuggerTests.EvaluateLocalsWithMultidimensionalIndexingTests.EvaluateLocals", "window.setTimeout(function() { invoke_static_method ('[debugger-test] DebuggerTests.EvaluateLocalsWithMultidimensionalIndexingTests:EvaluateLocals'); })", wait_for_event_fn: async (pause_location) => { var id = pause_location["callFrames"][0]["callFrameId"].Value(); await EvaluateOnCallFrameAndCheck(id, ("j", TNumber(1)), ("f.idx1", TNumber(1)), ("f.numArray2D[0, 0]", TNumber(1)), ("f.numArray2D[0, 1]", TNumber(2)), ("f.numArray2D[1, 0]", TNumber(3)), ("f.numArray2D[1 ,1]", TNumber(4)), ("f.numArray3D[0, 0, 0]", TNumber(1)), ("f.numArray3D[0 ,0 ,1]", TNumber(2)), ("f.numArray3D[0 ,0, 2]", TNumber(3)), ("f.numArray3D[1, 1, 0]", TNumber(10)), ("f.numArray3D[1, 1, 1]", TNumber(11)), ("f.numArray3D[1 , 1, 2]", TNumber(12)), ("f.numArray2D[0,0]", TNumber(1)), ("f.numArray2D[0,1]", TNumber(2)), ("f.numArray2D[1,0]", TNumber(3)), ("f.numArray2D[1,1]", TNumber(4)), ("f.numArray3D[0,0,0]", TNumber(1)), ("f.numArray3D[0,0,1]", TNumber(2)), ("f.numArray3D[0,0,2]", TNumber(3)), ("f.numArray3D[1,1,0]", TNumber(10)), ("f.numArray3D[1,1,1]", TNumber(11)), ("f.numArray3D[1,1,2]", TNumber(12)), ("f.textArray2D[0,0]", TString("one")), ("f.textArray2D[0,1]", TString("two")), ("f.textArray2D[1,0]", TString("three")), ("f.textArray2D[1,1]", TString("four")), ("f.numArray2D[i,i]", TNumber(1)), ("f.numArray2D[i,j]", TNumber(2)), ("f.numArray2D[j,i]", TNumber(3)), ("f.numArray2D[j,j]", TNumber(4)), ("f.numArray3D[i,i,i]", TNumber(1)), ("f.numArray3D[i,i,j]", TNumber(2)), ("f.numArray3D[i,i,2]", TNumber(3)), ("f.numArray3D[j,j,i]", TNumber(10)), ("f.numArray3D[j,j,1]", TNumber(11)), ("f.numArray3D[j,j,2]", TNumber(12)), ("f.textArray2D[i,i]", TString("one")), ("f.textArray2D[i,j]", TString("two")), ("f.textArray2D[j,i]", TString("three")), ("f.textArray2D[j,j]", TString("four")), ("f.numArray2D[f.idx0,f.idx0]", TNumber(1)), ("f.numArray2D[f.idx0,f.idx1]", TNumber(2)), ("f.numArray2D[f.idx1,f.idx0]", TNumber(3)), ("f.numArray2D[f.idx1,f.idx1]", TNumber(4)), ("f.numArray3D[f.idx0,f.idx0,f.idx0]", TNumber(1)), ("f.numArray3D[f.idx0,f.idx0,f.idx1]", TNumber(2)), ("f.numArray3D[f.idx0,f.idx0,2]", TNumber(3)), ("f.numArray3D[f.idx1,f.idx1,f.idx0]", TNumber(10)), ("f.numArray3D[f.idx1,f.idx1,f.idx1]", TNumber(11)), ("f.numArray3D[f.idx1,f.idx1,2]", TNumber(12)), ("f.textArray2D[f.idx0,f.idx0]", TString("one")), ("f.textArray2D[f.idx0,f.idx1]", TString("two")), ("f.textArray2D[f.idx1,f.idx0]", TString("three")), ("f.textArray2D[f.idx1,f.idx1]", TString("four"))); }); [ConditionalFact(nameof(RunningOnChrome))] public async Task EvaluateIndexingJagged() => await CheckInspectLocalsAtBreakpointSite( "DebuggerTests.EvaluateLocalsWithIndexingTests", "EvaluateLocals", 5, "DebuggerTests.EvaluateLocalsWithIndexingTests.EvaluateLocals", "window.setTimeout(function() { invoke_static_method ('[debugger-test] DebuggerTests.EvaluateLocalsWithIndexingTests:EvaluateLocals'); })", wait_for_event_fn: async (pause_location) => { var id = pause_location["callFrames"][0]["callFrameId"].Value(); await EvaluateOnCallFrameAndCheck(id, ("j", TNumber(1)), ("f.idx1", TNumber(1)), ("f.numArrayOfArrays[1][1]", TNumber(2)), ("f.numArrayOfArrays[j][j]", TNumber(2)), ("f.numArrayOfArrays[f.idx1][f.idx1]", TNumber(2)), ("f.numListOfLists[1][1]", TNumber(2)), ("f.numListOfLists[j][j]", TNumber(2)), ("f.numListOfLists[f.idx1][f.idx1]", TNumber(2)), ("f.textArrayOfArrays[1][1]", TString("2")), ("f.textArrayOfArrays[j][j]", TString("2")), ("f.textArrayOfArrays[f.idx1][f.idx1]", TString("2")), ("f.textListOfLists[1][1]", TString("2")), ("f.textListOfLists[j][j]", TString("2")), ("f.textListOfLists[f.idx1][f.idx1]", TString("2"))); }); [ConditionalFact(nameof(RunningOnChrome))] public async Task EvaluateSimpleMethodCallsCheckChangedValue() => await CheckInspectLocalsAtBreakpointSite( "DebuggerTests.EvaluateMethodTestsClass.TestEvaluate", "run", 9, "DebuggerTests.EvaluateMethodTestsClass.TestEvaluate.run", "window.setTimeout(function() { invoke_static_method ('[debugger-test] DebuggerTests.EvaluateMethodTestsClass:EvaluateMethods'); })", wait_for_event_fn: async (pause_location) => { var id = pause_location["callFrames"][0]["callFrameId"].Value(); var frame = pause_location["callFrames"][0]; var props = await GetObjectOnFrame(frame, "this"); CheckNumber(props, "a", 1); await EvaluateOnCallFrameAndCheck(id, ("this.CallMethodChangeValue()", TObject("object", is_null : true))); frame = pause_location["callFrames"][0]; props = await GetObjectOnFrame(frame, "this"); CheckNumber(props, "a", 11); }); [Theory] [InlineData("DebuggerTestsV2.EvaluateStaticFieldsInStaticClass", "Run", "DebuggerTestsV2", "EvaluateStaticFieldsInStaticClass", "EvaluateMethods", 1, 2)] [InlineData("DebuggerTests.EvaluateStaticFieldsInStaticClass", "Run", "DebuggerTests", "EvaluateStaticFieldsInStaticClass", "EvaluateMethods", 1, 1)] [InlineData("DebuggerTests.EvaluateStaticFieldsInStaticClass", "RunAsync", "DebuggerTests", "EvaluateStaticFieldsInStaticClass", "EvaluateMethodsAsync", 1, 1)] [InlineData("DebuggerTests.EvaluateStaticFieldsInInstanceClass", "RunStatic", "DebuggerTests", "EvaluateStaticFieldsInInstanceClass", "EvaluateMethods", 1, 7)] [InlineData("DebuggerTests.EvaluateStaticFieldsInInstanceClass", "RunStaticAsync", "DebuggerTests", "EvaluateStaticFieldsInInstanceClass", "EvaluateMethodsAsync", 1, 7)] [InlineData("DebuggerTests.EvaluateStaticFieldsInInstanceClass", "Run", "DebuggerTests", "EvaluateStaticFieldsInInstanceClass", "EvaluateMethods", 1, 7)] [InlineData("DebuggerTests.EvaluateStaticFieldsInInstanceClass", "RunAsync", "DebuggerTests", "EvaluateStaticFieldsInInstanceClass", "EvaluateMethodsAsync", 1, 7)] public async Task EvaluateStaticFields( string bpLocation, string bpMethod, string namespaceName, string className, string triggeringMethod, int bpLine, int expectedInt) => await CheckInspectLocalsAtBreakpointSite( bpLocation, bpMethod, bpLine, $"{bpLocation}.{bpMethod}", $"window.setTimeout(function() {{ invoke_static_method ('[debugger-test] DebuggerTests.EvaluateMethodTestsClass:{triggeringMethod}'); }})", wait_for_event_fn: async (pause_location) => { var id = pause_location["callFrames"][0]["callFrameId"].Value(); foreach (var pad in new[] { String.Empty, " " }) { await EvaluateOnCallFrameAndCheck(id, ($"{pad}{namespaceName}.{className}.StaticField", TNumber(expectedInt * 10)), ($"{pad}{namespaceName}{pad}.{className}.{pad}StaticProperty", TString($"StaticProperty{expectedInt}")), ($"{namespaceName}.{pad}{className}.StaticPropertyWithError", TString($"System.Exception: not implemented {expectedInt}")), ($"{pad}{className}.{pad}StaticField", TNumber(expectedInt * 10)), ($"{pad}{pad}{className}.StaticProperty", TString($"StaticProperty{expectedInt}")), ($"{pad}{className}.StaticPropertyWithError", TString($"System.Exception: not implemented {expectedInt}")), ($"{pad}StaticField{pad}", TNumber(expectedInt * 10)), ($"{pad}StaticProperty", TString($"StaticProperty{expectedInt}")), ($"{pad}StaticPropertyWithError", TString($"System.Exception: not implemented {expectedInt}")) ); } }); [ConditionalFact(nameof(RunningOnChrome))] public async Task EvaluateStaticClassesNested() => await CheckInspectLocalsAtBreakpointSite( "DebuggerTests.EvaluateMethodTestsClass", "EvaluateMethods", 3, "DebuggerTests.EvaluateMethodTestsClass.EvaluateMethods", "window.setTimeout(function() { invoke_static_method ('[debugger-test] DebuggerTests.EvaluateMethodTestsClass:EvaluateMethods'); })", wait_for_event_fn: async (pause_location) => { var id = pause_location["callFrames"][0]["callFrameId"].Value(); foreach (var pad in new[] { String.Empty, " " }) { await EvaluateOnCallFrameAndCheck(id, ($"{pad}DebuggerTests{pad}.EvaluateStaticFieldsInStaticClass.NestedClass1.{pad}NestedClass2.NestedClass3.{pad}StaticField", TNumber(3)), ($"{pad}DebuggerTests.EvaluateStaticFieldsInStaticClass.NestedClass1.NestedClass2.NestedClass3.StaticProperty", TString("StaticProperty3")), ($"{pad}{pad}DebuggerTests.{pad}EvaluateStaticFieldsInStaticClass.NestedClass1.NestedClass2.NestedClass3.{pad}StaticPropertyWithError", TString("System.Exception: not implemented 3")), ($"EvaluateStaticFieldsInStaticClass.{pad}NestedClass1.{pad}NestedClass2.NestedClass3.StaticField", TNumber(3)), ($"EvaluateStaticFieldsInStaticClass.NestedClass1.{pad}{pad}NestedClass2.NestedClass3.{pad}StaticProperty", TString("StaticProperty3")), ($"{pad}EvaluateStaticFieldsInStaticClass.NestedClass1.{pad}NestedClass2.{pad}NestedClass3.StaticPropertyWithError", TString("System.Exception: not implemented 3"))); } }); [Fact] public async Task EvaluateStaticClassesNestedWithNoNamespace() => await CheckInspectLocalsAtBreakpointSite( "NoNamespaceClass", "EvaluateMethods", 1, "NoNamespaceClass.EvaluateMethods", "window.setTimeout(function() { invoke_static_method ('[debugger-test] NoNamespaceClass:EvaluateMethods'); })", wait_for_event_fn: async (pause_location) => { var id = pause_location["callFrames"][0]["callFrameId"].Value(); foreach (var pad in new[] { String.Empty, " " }) { await EvaluateOnCallFrameAndCheck(id, ($"{pad}NoNamespaceClass.NestedClass1.NestedClass2.{pad}NestedClass3.StaticField", TNumber(30)), ($"NoNamespaceClass.NestedClass1.{pad}NestedClass2.NestedClass3.StaticProperty", TString("StaticProperty30")), ($"NoNamespaceClass.{pad}NestedClass1.NestedClass2.NestedClass3.{pad}StaticPropertyWithError", TString("System.Exception: not implemented 30"))); } }); [Fact] public async Task EvaluateStaticClassesNestedWithSameNames() => await CheckInspectLocalsAtBreakpointSite( "NestedWithSameNames.B.NestedWithSameNames.B", "Run", 1, "NestedWithSameNames.B.NestedWithSameNames.B.Run", "window.setTimeout(function() { invoke_static_method ('[debugger-test] NestedWithSameNames:Evaluate'); })", wait_for_event_fn: async (pause_location) => { var id = pause_location["callFrames"][0]["callFrameId"].Value(); foreach (var pad in new[] { String.Empty, " " }) { await EvaluateOnCallFrameAndCheck(id, ($"{pad}NestedWithSameNames", TNumber(90)), ($"B.{pad}NestedWithSameNames", TNumber(90)), ($"{pad}B.{pad}StaticField", TNumber(40)), ($"{pad}{pad}B.StaticProperty", TString("StaticProperty4")), ($"B.{pad}StaticPropertyWithError{pad}", TString("System.Exception: not implemented V4")) ); await CheckEvaluateFail(id, ($"{pad}NestedWithSameNames.B.{pad}StaticField", GetPrimitiveHasNoMembersMessage("B")), ($"NestedWithSameNames.{pad}B.StaticProperty", GetPrimitiveHasNoMembersMessage("B")), ($"{pad}NestedWithSameNames{pad}.{pad}B.StaticPropertyWithError", GetPrimitiveHasNoMembersMessage("B")), ($"{pad}NestedWithSameNames.B.{pad}NestedWithSameNames", GetPrimitiveHasNoMembersMessage("B")), ($"B.NestedWithSameNames.{pad}B{pad}.StaticField", GetPrimitiveHasNoMembersMessage("B")), ($"{pad}B.NestedWithSameNames.{pad}B.StaticProperty", GetPrimitiveHasNoMembersMessage("B")), ($"B.NestedWithSameNames{pad}.B.{pad}StaticPropertyWithError", GetPrimitiveHasNoMembersMessage("B")), ($"{pad}NestedWithSameNames.B{pad}.NestedWithSameNames.B{pad}.NestedWithSameNames{pad}", GetPrimitiveHasNoMembersMessage("B")), ($"NestedWithSameNames.B{pad}.{pad}{pad}NestedWithDifferentName.B.{pad}StaticField", GetPrimitiveHasNoMembersMessage("B")), ($"{pad}NestedWithSameNames.B.NestedWithDifferentName.B.StaticProperty", GetPrimitiveHasNoMembersMessage("B")), ($"NestedWithSameNames.{pad}B.{pad}NestedWithDifferentName.B.{pad}StaticPropertyWithError", GetPrimitiveHasNoMembersMessage("B")) ); } string GetPrimitiveHasNoMembersMessage(string name) => $"Cannot find member '{name}' on a primitive type"; }); [ConditionalTheory(nameof(RunningOnChrome))] [InlineData("DebuggerTests", "EvaluateStaticFieldsInInstanceClass", 7, true)] [InlineData("DebuggerTestsV2", "EvaluateStaticFieldsInStaticClass", 2, false)] public async Task EvaluateStaticFieldsFromDifferentNamespaceInDifferentFrames( string namespaceName, string className, int expectedInt, bool isFromDifferentNamespace) => await CheckInspectLocalsAtBreakpointSite( "DebuggerTestsV2.EvaluateStaticFieldsInStaticClass", "Run", 1, "DebuggerTestsV2.EvaluateStaticFieldsInStaticClass.Run", "window.setTimeout(function() { invoke_static_method ('[debugger-test] DebuggerTests.EvaluateMethodTestsClass:EvaluateMethods'); })", wait_for_event_fn: async (pause_location) => { var id_top = pause_location["callFrames"][0]["callFrameId"].Value(); var id_second = pause_location["callFrames"][1]["callFrameId"].Value(); int expectedIntInPrevFrame = isFromDifferentNamespace ? 7 : 1; foreach (var pad in new[] { String.Empty, " " }) { await EvaluateOnCallFrameAndCheck(id_top, ($"{pad}StaticField", TNumber(20)), ($"{pad}{namespaceName}.{pad}{className}.StaticField{pad}", TNumber(expectedInt * 10)), ($"{pad}StaticProperty", TString($"StaticProperty2")), ($"{pad}{namespaceName}.{pad}{className}.StaticProperty", TString($"StaticProperty{expectedInt}")), ($"{pad}StaticPropertyWithError", TString($"System.Exception: not implemented 2")), ($"{pad}{namespaceName}{pad}.{pad}{className}.StaticPropertyWithError", TString($"System.Exception: not implemented {expectedInt}")) ); if (!isFromDifferentNamespace) { await EvaluateOnCallFrameAndCheck(id_top, ($"{pad}{className}.StaticField", TNumber(expectedInt * 10)), ($"{className}{pad}.StaticProperty{pad}", TString($"StaticProperty{expectedInt}")), ($"{className}{pad}.{pad}StaticPropertyWithError", TString($"System.Exception: not implemented {expectedInt}")) ); } await EvaluateOnCallFrameAndCheck(id_second, ($"{pad}{namespaceName}.{pad}{className}.{pad}StaticField", TNumber(expectedInt * 10)), ($"{pad}{className}.StaticField", TNumber(expectedIntInPrevFrame * 10)), ($"{namespaceName}{pad}.{pad}{className}.StaticProperty", TString($"StaticProperty{expectedInt}")), ($"{pad}{className}.StaticProperty", TString($"StaticProperty{expectedIntInPrevFrame}")), ($"{pad}{namespaceName}.{className}.StaticPropertyWithError", TString($"System.Exception: not implemented {expectedInt}")), ($"{className}{pad}.StaticPropertyWithError{pad}", TString($"System.Exception: not implemented {expectedIntInPrevFrame}")) ); await CheckEvaluateFail(id_second, ($"{pad}StaticField", GetNonExistingVarMessage("StaticField")), ($"{pad}{pad}StaticProperty", GetNonExistingVarMessage("StaticProperty")), ($"{pad}StaticPropertyWithError{pad}", GetNonExistingVarMessage("StaticPropertyWithError")) ); } string GetNonExistingVarMessage(string name) => $"The name {name} does not exist in the current context"; }); [ConditionalFact(nameof(RunningOnChrome))] public async Task EvaluateStaticClassInvalidField() => await CheckInspectLocalsAtBreakpointSite( "DebuggerTests.EvaluateMethodTestsClass.TestEvaluate", "run", 9, "DebuggerTests.EvaluateMethodTestsClass.TestEvaluate.run", "window.setTimeout(function() { invoke_static_method ('[debugger-test] DebuggerTests.EvaluateMethodTestsClass:EvaluateMethods'); })", wait_for_event_fn: async (pause_location) => { var id = pause_location["callFrames"][0]["callFrameId"].Value(); var (_, res) = await EvaluateOnCallFrame(id, "DebuggerTests.EvaluateStaticFieldsInStaticClass.StaticProperty2", expect_ok: false); AssertEqual("Failed to resolve member access for DebuggerTests.EvaluateStaticFieldsInStaticClass.StaticProperty2", res.Error["result"]?["description"]?.Value(), "wrong error message"); (_, res) = await EvaluateOnCallFrame(id, "DebuggerTests.InvalidEvaluateStaticClass.StaticProperty2", expect_ok: false); AssertEqual("Failed to resolve member access for DebuggerTests.InvalidEvaluateStaticClass.StaticProperty2", res.Error["result"]?["description"]?.Value(), "wrong error message"); }); [ConditionalFact(nameof(RunningOnChrome))] public async Task AsyncLocalsInContinueWithBlock() => await CheckInspectLocalsAtBreakpointSite( "DebuggerTests.AsyncTests.ContinueWithTests", "ContinueWithStaticAsync", 4, "DebuggerTests.AsyncTests.ContinueWithTests.ContinueWithStaticAsync.AnonymousMethod__3_0", "window.setTimeout(function() { invoke_static_method('[debugger-test] DebuggerTests.AsyncTests.ContinueWithTests:RunAsync'); })", wait_for_event_fn: async (pause_location) => { var frame_locals = await GetProperties(pause_location["callFrames"][0]["callFrameId"].Value()); var id = pause_location["callFrames"][0]["callFrameId"].Value(); await EvaluateOnCallFrameAndCheck(id, ($"t.Status", TEnum("System.Threading.Tasks.TaskStatus", "RanToCompletion")), ($" t.Status", TEnum("System.Threading.Tasks.TaskStatus", "RanToCompletion")) ); await EvaluateOnCallFrameFail(id, ("str", "ReferenceError"), (" str", "ReferenceError") ); }); [ConditionalFact(nameof(RunningOnChrome))] public async Task EvaluateConstantValueUsingRuntimeEvaluate() => await CheckInspectLocalsAtBreakpointSite( "DebuggerTests.EvaluateTestsClass", "EvaluateLocals", 9, "DebuggerTests.EvaluateTestsClass.EvaluateLocals", "window.setTimeout(function() { invoke_static_method ('[debugger-test] DebuggerTests.EvaluateTestsClass:EvaluateLocals'); })", wait_for_event_fn: async (pause_location) => { var dt = new DateTime(2020, 1, 2, 3, 4, 5); await RuntimeEvaluateAndCheck( ("15\n//comment as vs does\n", TNumber(15)), ("15", TNumber(15)), ("\"15\"\n//comment as vs does\n", TString("15")), ("\"15\"", TString("15"))); }); [ConditionalTheory(nameof(RunningOnChrome))] [InlineData("EvaluateBrowsableClass", "TestEvaluateFieldsNone", "testFieldsNone", 10)] [InlineData("EvaluateBrowsableClass", "TestEvaluatePropertiesNone", "testPropertiesNone", 10)] [InlineData("EvaluateBrowsableStruct", "TestEvaluateFieldsNone", "testFieldsNone", 10)] [InlineData("EvaluateBrowsableStruct", "TestEvaluatePropertiesNone", "testPropertiesNone", 10)] [InlineData("EvaluateBrowsableClassStatic", "TestEvaluateFieldsNone", "testFieldsNone", 10)] [InlineData("EvaluateBrowsableClassStatic", "TestEvaluatePropertiesNone", "testPropertiesNone", 10)] [InlineData("EvaluateBrowsableStructStatic", "TestEvaluateFieldsNone", "testFieldsNone", 10)] [InlineData("EvaluateBrowsableStructStatic", "TestEvaluatePropertiesNone", "testPropertiesNone", 10)] [InlineData("EvaluateBrowsableNonAutoPropertiesClass", "TestEvaluatePropertiesNone", "testPropertiesNone", 5, true)] [InlineData("EvaluateBrowsableNonAutoPropertiesStruct", "TestEvaluatePropertiesNone", "testPropertiesNone", 5, true)] [InlineData("EvaluateBrowsableNonAutoPropertiesClassStatic", "TestEvaluatePropertiesNone", "testPropertiesNone", 5, true)] [InlineData("EvaluateBrowsableNonAutoPropertiesStructStatic", "TestEvaluatePropertiesNone", "testPropertiesNone", 5, true)] public async Task EvaluateBrowsableNone( string outerClassName, string className, string localVarName, int breakLine, bool allMembersAreProperties = false) => await CheckInspectLocalsAtBreakpointSite( $"DebuggerTests.{outerClassName}", "Evaluate", breakLine, $"DebuggerTests.{outerClassName}.Evaluate", $"window.setTimeout(function() {{ invoke_static_method ('[debugger-test] DebuggerTests.{outerClassName}:Evaluate'); 1 }})", wait_for_event_fn: async (pause_location) => { var id = pause_location["callFrames"][0]["callFrameId"].Value(); var (testNone, _) = await EvaluateOnCallFrame(id, localVarName); await CheckValue(testNone, TObject($"DebuggerTests.{outerClassName}.{className}"), nameof(testNone)); var testNoneProps = await GetProperties(testNone["objectId"]?.Value()); if (allMembersAreProperties) await CheckProps(testNoneProps, new { list = TGetter("list", TObject("System.Collections.Generic.List", description: "Count = 2")), array = TGetter("array", TObject("int[]", description: "int[2]")), text = TGetter("text", TString("text")), nullNone = TGetter("nullNone", TObject("bool[]", is_null: true)), valueTypeEnum = TGetter("valueTypeEnum", TEnum("DebuggerTests.SampleEnum", "yes")), sampleStruct = TGetter("sampleStruct", TObject("DebuggerTests.SampleStructure", description: "DebuggerTests.SampleStructure")), sampleClass = TGetter("sampleClass", TObject("DebuggerTests.SampleClass", description: "DebuggerTests.SampleClass")) }, "testNoneProps#1"); else await CheckProps(testNoneProps, new { list = TObject("System.Collections.Generic.List", description: "Count = 2"), array = TObject("int[]", description: "int[2]"), text = TString("text"), nullNone = TObject("bool[]", is_null: true), valueTypeEnum = TEnum("DebuggerTests.SampleEnum", "yes"), sampleStruct = TObject("DebuggerTests.SampleStructure", description: "DebuggerTests.SampleStructure"), sampleClass = TObject("DebuggerTests.SampleClass", description: "DebuggerTests.SampleClass") }, "testNoneProps#1"); }); [ConditionalTheory(nameof(RunningOnChrome))] [InlineData("EvaluateBrowsableClass", "TestEvaluateFieldsNever", "testFieldsNever", 10)] [InlineData("EvaluateBrowsableClass", "TestEvaluatePropertiesNever", "testPropertiesNever", 10)] [InlineData("EvaluateBrowsableStruct", "TestEvaluateFieldsNever", "testFieldsNever", 10)] [InlineData("EvaluateBrowsableStruct", "TestEvaluatePropertiesNever", "testPropertiesNever", 10)] [InlineData("EvaluateBrowsableClassStatic", "TestEvaluateFieldsNever", "testFieldsNever", 10)] [InlineData("EvaluateBrowsableClassStatic", "TestEvaluatePropertiesNever", "testPropertiesNever", 10)] [InlineData("EvaluateBrowsableStructStatic", "TestEvaluateFieldsNever", "testFieldsNever", 10)] [InlineData("EvaluateBrowsableStructStatic", "TestEvaluatePropertiesNever", "testPropertiesNever", 10)] [InlineData("EvaluateBrowsableNonAutoPropertiesClass", "TestEvaluatePropertiesNever", "testPropertiesNever", 5)] [InlineData("EvaluateBrowsableNonAutoPropertiesStruct", "TestEvaluatePropertiesNever", "testPropertiesNever", 5)] [InlineData("EvaluateBrowsableNonAutoPropertiesClassStatic", "TestEvaluatePropertiesNever", "testPropertiesNever", 5)] [InlineData("EvaluateBrowsableNonAutoPropertiesStructStatic", "TestEvaluatePropertiesNever", "testPropertiesNever", 5)] public async Task EvaluateBrowsableNever(string outerClassName, string className, string localVarName, int breakLine) => await CheckInspectLocalsAtBreakpointSite( $"DebuggerTests.{outerClassName}", "Evaluate", breakLine, $"DebuggerTests.{outerClassName}.Evaluate", $"window.setTimeout(function() {{ invoke_static_method ('[debugger-test] DebuggerTests.{outerClassName}:Evaluate'); 1 }})", wait_for_event_fn: async (pause_location) => { var id = pause_location["callFrames"][0]["callFrameId"].Value(); var (testNever, _) = await EvaluateOnCallFrame(id, localVarName); await CheckValue(testNever, TObject($"DebuggerTests.{outerClassName}.{className}"), nameof(testNever)); var testNeverProps = await GetProperties(testNever["objectId"]?.Value()); await CheckProps(testNeverProps, new { }, "testNeverProps#1"); }); [ConditionalTheory(nameof(RunningOnChrome))] [InlineData("EvaluateBrowsableClass", "TestEvaluateFieldsCollapsed", "testFieldsCollapsed", 10)] [InlineData("EvaluateBrowsableClass", "TestEvaluatePropertiesCollapsed", "testPropertiesCollapsed", 10)] [InlineData("EvaluateBrowsableStruct", "TestEvaluateFieldsCollapsed", "testFieldsCollapsed", 10)] [InlineData("EvaluateBrowsableStruct", "TestEvaluatePropertiesCollapsed", "testPropertiesCollapsed", 10)] [InlineData("EvaluateBrowsableClassStatic", "TestEvaluateFieldsCollapsed", "testFieldsCollapsed", 10)] [InlineData("EvaluateBrowsableClassStatic", "TestEvaluatePropertiesCollapsed", "testPropertiesCollapsed", 10)] [InlineData("EvaluateBrowsableStructStatic", "TestEvaluateFieldsCollapsed", "testFieldsCollapsed", 10)] [InlineData("EvaluateBrowsableStructStatic", "TestEvaluatePropertiesCollapsed", "testPropertiesCollapsed", 10)] [InlineData("EvaluateBrowsableNonAutoPropertiesClass", "TestEvaluatePropertiesCollapsed", "testPropertiesCollapsed", 5, true)] [InlineData("EvaluateBrowsableNonAutoPropertiesStruct", "TestEvaluatePropertiesCollapsed", "testPropertiesCollapsed", 5, true)] [InlineData("EvaluateBrowsableNonAutoPropertiesClassStatic", "TestEvaluatePropertiesCollapsed", "testPropertiesCollapsed", 5, true)] [InlineData("EvaluateBrowsableNonAutoPropertiesStructStatic", "TestEvaluatePropertiesCollapsed", "testPropertiesCollapsed", 5, true)] public async Task EvaluateBrowsableCollapsed( string outerClassName, string className, string localVarName, int breakLine, bool allMembersAreProperties = false) => await CheckInspectLocalsAtBreakpointSite( $"DebuggerTests.{outerClassName}", "Evaluate", breakLine, $"DebuggerTests.{outerClassName}.Evaluate", $"window.setTimeout(function() {{ invoke_static_method ('[debugger-test] DebuggerTests.{outerClassName}:Evaluate'); 1 }})", wait_for_event_fn: async (pause_location) => { var id = pause_location["callFrames"][0]["callFrameId"].Value(); var (testCollapsed, _) = await EvaluateOnCallFrame(id, localVarName); await CheckValue(testCollapsed, TObject($"DebuggerTests.{outerClassName}.{className}"), nameof(testCollapsed)); var testCollapsedProps = await GetProperties(testCollapsed["objectId"]?.Value()); if (allMembersAreProperties) await CheckProps(testCollapsedProps, new { listCollapsed = TGetter("listCollapsed", TObject("System.Collections.Generic.List", description: "Count = 2")), arrayCollapsed = TGetter("arrayCollapsed", TObject("int[]", description: "int[2]")), textCollapsed = TGetter("textCollapsed", TString("textCollapsed")), nullCollapsed = TGetter("nullCollapsed", TObject("bool[]", is_null: true)), valueTypeEnumCollapsed = TGetter("valueTypeEnumCollapsed", TEnum("DebuggerTests.SampleEnum", "yes")), sampleStructCollapsed = TGetter("sampleStructCollapsed", TObject("DebuggerTests.SampleStructure", description: "DebuggerTests.SampleStructure")), sampleClassCollapsed = TGetter("sampleClassCollapsed", TObject("DebuggerTests.SampleClass", description: "DebuggerTests.SampleClass")) }, "testCollapsedProps#1"); else await CheckProps(testCollapsedProps, new { listCollapsed = TObject("System.Collections.Generic.List", description: "Count = 2"), arrayCollapsed = TObject("int[]", description: "int[2]"), textCollapsed = TString("textCollapsed"), nullCollapsed = TObject("bool[]", is_null: true), valueTypeEnumCollapsed = TEnum("DebuggerTests.SampleEnum", "yes"), sampleStructCollapsed = TObject("DebuggerTests.SampleStructure", description: "DebuggerTests.SampleStructure"), sampleClassCollapsed = TObject("DebuggerTests.SampleClass", description: "DebuggerTests.SampleClass") }, "testCollapsedProps#1"); }); // [ConditionalTheory(nameof(RunningOnChrome))] [InlineData("EvaluateBrowsableClass", "TestEvaluateFieldsRootHidden", "testFieldsRootHidden", 10)] [InlineData("EvaluateBrowsableClass", "TestEvaluatePropertiesRootHidden", "testPropertiesRootHidden", 10)] [InlineData("EvaluateBrowsableStruct", "TestEvaluateFieldsRootHidden", "testFieldsRootHidden", 10)] [InlineData("EvaluateBrowsableStruct", "TestEvaluatePropertiesRootHidden", "testPropertiesRootHidden", 10)] [InlineData("EvaluateBrowsableClassStatic", "TestEvaluateFieldsRootHidden", "testFieldsRootHidden", 10)] [InlineData("EvaluateBrowsableClassStatic", "TestEvaluatePropertiesRootHidden", "testPropertiesRootHidden", 10)] [InlineData("EvaluateBrowsableStructStatic", "TestEvaluateFieldsRootHidden", "testFieldsRootHidden", 10)] [InlineData("EvaluateBrowsableStructStatic", "TestEvaluatePropertiesRootHidden", "testPropertiesRootHidden", 10)] [InlineData("EvaluateBrowsableNonAutoPropertiesClass", "TestEvaluatePropertiesRootHidden", "testPropertiesRootHidden", 5)] [InlineData("EvaluateBrowsableNonAutoPropertiesStruct", "TestEvaluatePropertiesRootHidden", "testPropertiesRootHidden", 5)] [InlineData("EvaluateBrowsableNonAutoPropertiesClassStatic", "TestEvaluatePropertiesRootHidden", "testPropertiesRootHidden", 5)] [InlineData("EvaluateBrowsableNonAutoPropertiesStructStatic", "TestEvaluatePropertiesRootHidden", "testPropertiesRootHidden", 5)] public async Task EvaluateBrowsableRootHidden( string outerClassName, string className, string localVarName, int breakLine) => await CheckInspectLocalsAtBreakpointSite( $"DebuggerTests.{outerClassName}", "Evaluate", breakLine, $"DebuggerTests.{outerClassName}.Evaluate", $"window.setTimeout(function() {{ invoke_static_method ('[debugger-test] DebuggerTests.{outerClassName}:Evaluate'); 1 }})", wait_for_event_fn: async (pause_location) => { var id = pause_location["callFrames"][0]["callFrameId"].Value(); var (testRootHidden, _) = await EvaluateOnCallFrame(id, localVarName); await CheckValue(testRootHidden, TObject($"DebuggerTests.{outerClassName}.{className}"), nameof(testRootHidden)); var testRootHiddenProps = await GetProperties(testRootHidden["objectId"]?.Value()); JObject[] expectedTestRootHiddenProps = new[] { JObject.FromObject(new { value = TNumber(1), name = "listRootHidden[0]"}), JObject.FromObject(new { value = TNumber(2), name = "listRootHidden[1]"}), JObject.FromObject(new { value = TNumber(11), name = "arrayRootHidden[0]"}), JObject.FromObject(new { value = TNumber(22), name = "arrayRootHidden[1]"}), JObject.FromObject(new { value = TNumber(100), name = "sampleStructRootHidden.Id"}), JObject.FromObject(new { value = TBool(true), name = "sampleStructRootHidden.IsStruct"}), JObject.FromObject(new { value = TNumber(200), name = "sampleClassRootHidden.ClassId"}), JObject.FromObject(new { value = TObject("System.Collections.Generic.List", description: "Count = 1"), name = "sampleClassRootHidden.Items"}) }; await CheckProps(testRootHiddenProps, expectedTestRootHiddenProps, "listRootHidden"); }); [ConditionalFact(nameof(RunningOnChrome))] public async Task EvaluateStaticAttributeInAssemblyNotRelatedButLoaded() => await CheckInspectLocalsAtBreakpointSite( "DebuggerTests.EvaluateTestsClass", "EvaluateLocals", 9, "DebuggerTests.EvaluateTestsClass.EvaluateLocals", "window.setTimeout(function() { invoke_static_method ('[debugger-test] DebuggerTests.EvaluateTestsClass:EvaluateLocals'); })", wait_for_event_fn: async (pause_location) => { await RuntimeEvaluateAndCheck( ("ClassToBreak.valueToCheck", TNumber(10))); }); [ConditionalFact(nameof(RunningOnChrome))] public async Task EvaluateLocalObjectFromAssemblyNotRelatedButLoaded() => await CheckInspectLocalsAtBreakpointSite( "DebuggerTests.EvaluateTestsClass", "EvaluateLocalsFromAnotherAssembly", 5, "DebuggerTests.EvaluateTestsClass.EvaluateLocalsFromAnotherAssembly", "window.setTimeout(function() { invoke_static_method ('[debugger-test] DebuggerTests.EvaluateTestsClass:EvaluateLocalsFromAnotherAssembly'); })", wait_for_event_fn: async (pause_location) => { await RuntimeEvaluateAndCheck( ("a.valueToCheck", TNumber(20))); }); [ConditionalFact(nameof(RunningOnChrome))] public async Task StructureGetters() => await CheckInspectLocalsAtBreakpointSite( "DebuggerTests.StructureGetters", "Evaluate", 2, $"DebuggerTests.StructureGetters.Evaluate", "window.setTimeout(function() { invoke_static_method ('[debugger-test] DebuggerTests.StructureGetters:Evaluate'); })", wait_for_event_fn: async (pause_location) => { var id = pause_location["callFrames"][0]["callFrameId"].Value(); var (obj, _) = await EvaluateOnCallFrame(id, "s"); var props = await GetProperties(obj["objectId"]?.Value()); await CheckProps(props, new { Id = TGetter("Id", TNumber(123)) }, "s#1"); }); [ConditionalFact(nameof(RunningOnChrome))] public async Task EvaluateMethodWithDefaultParam() => await CheckInspectLocalsAtBreakpointSite( $"DebuggerTests.DefaultParamMethods", "Evaluate", 2, "DebuggerTests.DefaultParamMethods.Evaluate", $"window.setTimeout(function() {{ invoke_static_method ('[debugger-test] DebuggerTests.DefaultParamMethods:Evaluate'); 1 }})", wait_for_event_fn: async (pause_location) => { var id = pause_location["callFrames"][0]["callFrameId"].Value(); await EvaluateOnCallFrameAndCheck(id, ("test.GetByte()", TNumber(1)), ("test.GetSByte()", TNumber(1)), ("test.GetByteNullable()", TNumber(1)), ("test.GetSByteNullable()", TNumber(1)), ("test.GetInt16()", TNumber(1)), ("test.GetUInt16()", TNumber(1)), ("test.GetInt16Nullable()", TNumber(1)), ("test.GetUInt16Nullable()", TNumber(1)), ("test.GetInt32()", TNumber(1)), ("test.GetUInt32()", TNumber(1)), ("test.GetInt32Nullable()", TNumber(1)), ("test.GetUInt32Nullable()", TNumber(1)), ("test.GetInt64()", TNumber(1)), ("test.GetUInt64()", TNumber(1)), ("test.GetInt64Nullable()", TNumber(1)), ("test.GetUInt64Nullable()", TNumber(1)), ("test.GetChar()", TChar('T')), ("test.GetCharNullable()", TChar('T')), ("test.GetUnicodeChar()", TChar('\u0105')), ("test.GetString()", TString("1.23")), ("test.GetUnicodeString()", TString("\u017C\u00F3\u0142\u0107")), ("test.GetString(null)", TString(null)), ("test.GetStringNullable()", TString("1.23")), ("test.GetSingle()", TNumber("1.23", isDecimal: true)), ("test.GetDouble()", TNumber("1.23", isDecimal: true)), ("test.GetSingleNullable()", TNumber("1.23", isDecimal: true)), ("test.GetDoubleNullable()", TNumber("1.23", isDecimal: true)), ("test.GetBool()", TBool(true)), ("test.GetBoolNullable()", TBool(true)), ("test.GetNull()", TBool(true)), ("test.GetDefaultAndRequiredParam(2)", TNumber(5)), ("test.GetDefaultAndRequiredParam(3, 2)", TNumber(5)), ("test.GetDefaultAndRequiredParamMixedTypes(\"a\")", TString("a; -1; False")), ("test.GetDefaultAndRequiredParamMixedTypes(\"a\", 23)", TString("a; 23; False")), ("test.GetDefaultAndRequiredParamMixedTypes(\"a\", 23, true)", TString("a; 23; True")) ); var (_, res) = await EvaluateOnCallFrame(id, "test.GetDefaultAndRequiredParamMixedTypes(\"a\", 23, true, 1.23f)", expect_ok: false); AssertEqual("Unable to evaluate method 'GetDefaultAndRequiredParamMixedTypes'. Too many arguments passed.", res.Error["result"]["description"]?.Value(), "wrong error message"); }); [Fact] public async Task EvaluateMethodWithLinq() => await CheckInspectLocalsAtBreakpointSite( $"DebuggerTests.DefaultParamMethods", "Evaluate", 2, "DebuggerTests.DefaultParamMethods.Evaluate", $"window.setTimeout(function() {{ invoke_static_method ('[debugger-test] DebuggerTests.DefaultParamMethods:Evaluate'); 1 }})", wait_for_event_fn: async (pause_location) => { var id = pause_location["callFrames"][0]["callFrameId"].Value(); await EvaluateOnCallFrameAndCheck(id, ("test.listToLinq.ToList()", TObject("System.Collections.Generic.List", description: "Count = 11")) ); }); [ConditionalFact(nameof(RunningOnChrome))] public async Task EvaluateNullObjectPropertiesPositive() => await CheckInspectLocalsAtBreakpointSite( $"DebuggerTests.EvaluateNullableProperties", "Evaluate", 11, "DebuggerTests.EvaluateNullableProperties.Evaluate", $"window.setTimeout(function() {{ invoke_static_method ('[debugger-test] DebuggerTests.EvaluateNullableProperties:Evaluate'); 1 }})", wait_for_event_fn: async (pause_location) => { var id = pause_location["callFrames"][0]["callFrameId"].Value(); // we have no way of returning int? for null values, // so we return the last non-null class name await EvaluateOnCallFrameAndCheck(id, ("list.Count", TNumber(1)), ("list!.Count", TNumber(1)), ("list?.Count", TNumber(1)), ("listNull", TObject("System.Collections.Generic.List", is_null: true)), ("listNull?.Count", TObject("System.Collections.Generic.List", is_null: true)), ("tc?.MemberList?.Count", TNumber(2)), ("tc!.MemberList?.Count", TNumber(2)), ("tc!.MemberList!.Count", TNumber(2)), ("tc?.MemberListNull?.Count", TObject("System.Collections.Generic.List", is_null: true)), ("tc.MemberListNull?.Count", TObject("System.Collections.Generic.List", is_null: true)), ("tcNull?.MemberListNull?.Count", TObject("DebuggerTests.EvaluateNullableProperties.TestClass", is_null: true)), ("str!.Length", TNumber(9)), ("str?.Length", TNumber(9)), ("str_null?.Length", TObject("string", is_null: true)) ); }); [Fact] public async Task EvaluateNullObjectPropertiesNegative() => await CheckInspectLocalsAtBreakpointSite( $"DebuggerTests.EvaluateNullableProperties", "Evaluate", 6, "DebuggerTests.EvaluateNullableProperties.Evaluate", $"window.setTimeout(function() {{ invoke_static_method ('[debugger-test] DebuggerTests.EvaluateNullableProperties:Evaluate'); 1 }})", wait_for_event_fn: async (pause_location) => { var id = pause_location["callFrames"][0]["callFrameId"].Value(); await CheckEvaluateFail(id, ("list.Count.x", "Cannot find member 'x' on a primitive type"), ("listNull.Count", GetNullReferenceErrorOn("\"Count\"")), ("listNull!.Count", GetNullReferenceErrorOn("\"Count\"")), ("tcNull.MemberListNull.Count", GetNullReferenceErrorOn("\"MemberListNull\"")), ("tc.MemberListNull.Count", GetNullReferenceErrorOn("\"Count\"")), ("tcNull?.MemberListNull.Count", GetNullReferenceErrorOn("\"Count\"")), ("listNull?.Count.NonExistingProperty", GetNullReferenceErrorOn("\"NonExistingProperty\"")), ("tc?.MemberListNull! .Count", GetNullReferenceErrorOn("\"Count\"")), ("tc?. MemberListNull!.Count", GetNullReferenceErrorOn("\"Count\"")), ("tc?.MemberListNull.Count", GetNullReferenceErrorOn("\"Count\"")), ("tc! .MemberListNull!.Count", GetNullReferenceErrorOn("\"Count\"")), ("tc!.MemberListNull. Count", GetNullReferenceErrorOn("\"Count\"")), ("tcNull?.Sibling.MemberListNull?.Count", GetNullReferenceErrorOn("\"MemberListNull?\"")), ("listNull?", "Expected expression."), ("listNull!.Count", GetNullReferenceErrorOn("\"Count\"")), ("x?.p", "Operation '?' not allowed on primitive type - 'x?'"), ("str_null.Length", GetNullReferenceErrorOn("\"Length\"")), ("str_null!.Length", GetNullReferenceErrorOn("\"Length\"")) ); string GetNullReferenceErrorOn(string name) => $"Expression threw NullReferenceException trying to access {name} on a null-valued object."; }); [Fact] public async Task EvaluateMethodsOnPrimitiveTypesReturningPrimitives() => await CheckInspectLocalsAtBreakpointSite( "DebuggerTests.PrimitiveTypeMethods", "Evaluate", 11, "DebuggerTests.PrimitiveTypeMethods.Evaluate", "window.setTimeout(function() { invoke_static_method ('[debugger-test] DebuggerTests.PrimitiveTypeMethods:Evaluate'); })", wait_for_event_fn: async (pause_location) => { var id = pause_location["callFrames"][0]["callFrameId"].Value(); await EvaluateOnCallFrameAndCheck(id, ("test.propInt.ToString()", TString("12")), ("test.propUint.ToString()", TString("12")), ("test.propLong.ToString()", TString("12")), ("test.propUlong.ToString()", TString("12")), ("test.propBool.ToString()", TString("True")), ("test.propChar.ToString()", TString("X")), ("test.propString.ToString()", TString("s_t_r")), ("test.propString.EndsWith('r')", TBool(true)), ("test.propString.StartsWith('S')", TBool(false)), ("localInt.ToString()", TString("2")), ("localUint.ToString()", TString("2")), ("localLong.ToString()", TString("2")), ("localUlong.ToString()", TString("2")), ("localBool.ToString()", TString("False")), ("localBool.GetHashCode()", TNumber(0)), ("localBool.GetTypeCode()", TObject("System.TypeCode", "Boolean")), ("localChar.ToString()", TString("Y")), ("localString.ToString()", TString("S*T*R")), ("localString.EndsWith('r')", TBool(false)), ("localString.StartsWith('S')", TBool(true)) ); }); [Fact] public async Task EvaluateMethodsOnPrimitiveTypesReturningPrimitivesCultureDependant() => await CheckInspectLocalsAtBreakpointSite( "DebuggerTests.PrimitiveTypeMethods", "Evaluate", 11, "DebuggerTests.PrimitiveTypeMethods.Evaluate", "window.setTimeout(function() { invoke_static_method ('[debugger-test] DebuggerTests.PrimitiveTypeMethods:Evaluate'); })", wait_for_event_fn: async (pause_location) => { var id = pause_location["callFrames"][0]["callFrameId"].Value(); var (floatMemberVal, _) = await EvaluateOnCallFrame(id, "test.propFloat"); var (doubleMemberVal, _) = await EvaluateOnCallFrame(id, "test.propDouble"); var (floatLocalVal, _) = await EvaluateOnCallFrame(id, "localFloat"); var (doubleLocalVal, _) = await EvaluateOnCallFrame(id, "localDouble"); // expected value depends on the debugger's user culture and is equal to // description of the number that also respects user's culture settings await EvaluateOnCallFrameAndCheck(id, ("test.propFloat.ToString()", TString(floatMemberVal["description"]?.Value())), ("test.propDouble.ToString()", TString(doubleMemberVal["description"]?.Value())), ("localFloat.ToString()", TString(floatLocalVal["description"]?.Value())), ("localDouble.ToString()", TString(doubleLocalVal["description"]?.Value()))); }); [Fact] public async Task EvaluateMethodsOnPrimitiveTypesReturningObjects() => await CheckInspectLocalsAtBreakpointSite( "DebuggerTests.PrimitiveTypeMethods", "Evaluate", 11, "DebuggerTests.PrimitiveTypeMethods.Evaluate", "window.setTimeout(function() { invoke_static_method ('[debugger-test] DebuggerTests.PrimitiveTypeMethods:Evaluate'); })", wait_for_event_fn: async (pause_location) => { var id = pause_location["callFrames"][0]["callFrameId"].Value(); var (res, _) = await EvaluateOnCallFrame(id, "test.propString.Split('_', 3, System.StringSplitOptions.TrimEntries)"); var props = await GetProperties(res["objectId"]?.Value()); var expected_props = new[] { TString("s"), TString("t"), TString("r") }; await CheckProps(props, expected_props, "props#1"); (res, _) = await EvaluateOnCallFrame(id, "localString.Split('*', 3, System.StringSplitOptions.RemoveEmptyEntries)"); props = await GetProperties(res["objectId"]?.Value()); expected_props = new[] { TString("S"), TString("T"), TString("R") }; await CheckProps(props, expected_props, "props#2"); }); [Theory] [InlineData("DefaultMethod", "IDefaultInterface", "Evaluate")] [InlineData("DefaultMethod2", "IExtendIDefaultInterface", "Evaluate")] [InlineData("DefaultMethodAsync", "IDefaultInterface", "EvaluateAsync", true)] public async Task EvaluateLocalsInDefaultInterfaceMethod(string pauseMethod, string methodInterface, string entryMethod, bool isAsync = false) => await CheckInspectLocalsAtBreakpointSite( methodInterface, pauseMethod, 2, methodInterface + "." + pauseMethod, $"window.setTimeout(function() {{ invoke_static_method ('[debugger-test] DefaultInterfaceMethod:{entryMethod}'); }})", wait_for_event_fn: async (pause_location) => { var id = pause_location["callFrames"][0]["callFrameId"].Value(); await EvaluateOnCallFrameAndCheck(id, ("localString", TString($"{pauseMethod}()")), ("this", TObject("DIMClass")), ("this.dimClassMember", TNumber(123))); }); [Theory] [InlineData("DefaultMethodStatic", "IDefaultInterface", "EvaluateStatic")] [InlineData("DefaultMethodAsyncStatic", "IDefaultInterface", "EvaluateAsyncStatic", true)] public async Task EvaluateLocalsInDefaultInterfaceMethodStatic(string pauseMethod, string methodInterface, string entryMethod, bool isAsync = false) => await CheckInspectLocalsAtBreakpointSite( methodInterface, pauseMethod, 2, methodInterface + "." + pauseMethod, $"window.setTimeout(function() {{ invoke_static_method ('[debugger-test] DefaultInterfaceMethod:{entryMethod}'); }})", wait_for_event_fn: async (pause_location) => { var id = pause_location["callFrames"][0]["callFrameId"].Value(); await EvaluateOnCallFrameAndCheck(id, ("localString", TString($"{pauseMethod}()")), ("IDefaultInterface.defaultInterfaceMember", TString("defaultInterfaceMember")), ("defaultInterfaceMember", TString("defaultInterfaceMember")) ); }); [Fact] public async Task EvaluateStringProperties() => await CheckInspectLocalsAtBreakpointSite( $"DebuggerTests.TypeProperties", "Run", 3, "DebuggerTests.TypeProperties.Run", $"window.setTimeout(function() {{ invoke_static_method ('[debugger-test] DebuggerTests.TypeProperties:Run'); 1 }})", wait_for_event_fn: async (pause_location) => { var id = pause_location["callFrames"][0]["callFrameId"].Value(); await EvaluateOnCallFrameAndCheck(id, ("localString.Length", TNumber(5)), ("localString[1]", TChar('B')), ("instance.str.Length", TNumber(5)), ("instance.str[3]", TChar('c')) ); }); } }