From 0ab2c1e92e2383b3969688ede5bbcf106527bbcb Mon Sep 17 00:00:00 2001 From: Ilona Tomkowicz <32700855+ilonatommy@users.noreply.github.com> Date: Fri, 8 Jul 2022 12:31:34 +0200 Subject: [PATCH] [wasm][debugger] Enable onCallFrame evaluation of static fields in classes/interfaces from a static method. (#70560) * Test for DIM - expected behavior. * Static tests: renaming variables and small refactoring. * Added new testcases and merged existing tests into Theories. * Fix for resolving the name with namespace prefix matching the current frame location. * Fix for tests failing on InvokeMethod in runtime. * Applied smallest suggestions of @radical's review. * Reverted deleting and renaming tests - only adding new. * Corrected the logic + added new tests. * Removed unnecessary logging. --- .../MemberReferenceResolver.cs | 107 +++++++---- .../DebuggerTestSuite/DebuggerTestBase.cs | 9 + .../EvaluateOnCallFrameTests.cs | 172 ++++++++++++++---- .../debugger-test/debugger-evaluate-test.cs | 93 +++++++++- 4 files changed, 304 insertions(+), 77 deletions(-) diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/MemberReferenceResolver.cs b/src/mono/wasm/debugger/BrowserDebugProxy/MemberReferenceResolver.cs index aa67403542f80d..fa928ab990328e 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/MemberReferenceResolver.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/MemberReferenceResolver.cs @@ -77,53 +77,73 @@ public async Task GetValueFromObject(JToken objRet, CancellationToken t return null; } - public async Task<(JObject containerObject, ArraySegment remaining)> ResolveStaticMembersInStaticTypes(ArraySegment parts, CancellationToken token) + public async Task<(JObject containerObject, ArraySegment remaining)> ResolveStaticMembersInStaticTypes(ArraySegment expressionParts, CancellationToken token) { - string classNameToFind = ""; var store = await proxy.LoadStore(sessionId, false, token); var methodInfo = context.CallStack.FirstOrDefault(s => s.Id == scopeId)?.Method?.Info; if (methodInfo == null) return (null, null); - int typeId = -1; - for (int i = 0; i < parts.Count; i++) + string[] parts = expressionParts.ToArray(); + + string fullName = methodInfo.IsAsync == 0 ? methodInfo.TypeInfo.FullName : StripAsyncPartOfFullName(methodInfo.TypeInfo.FullName); + string[] fullNameParts = fullName.Split(".", StringSplitOptions.TrimEntries).ToArray(); + for (int i = 0; i < fullNameParts.Length; i++) { - string part = parts[i]; + string[] fullNamePrefix = fullNameParts[..^i]; + var (memberObject, remaining) = await FindStaticMemberMatchingParts(parts, fullNamePrefix); + if (memberObject != null) + return (memberObject, remaining); + } + return await FindStaticMemberMatchingParts(parts); - if (typeId != -1) + async Task<(JObject, ArraySegment)> FindStaticMemberMatchingParts(string[] parts, string[] fullNameParts = null) + { + string classNameToFind = fullNameParts == null ? "" : string.Join(".", fullNameParts); + int typeId = -1; + for (int i = 0; i < parts.Length; i++) { - JObject memberObject = await FindStaticMemberInType(classNameToFind, part, typeId); - if (memberObject != null) + if (!string.IsNullOrEmpty(methodInfo.TypeInfo.Namespace)) { - ArraySegment remaining = null; - if (i < parts.Count - 1) - remaining = parts[i..]; - - return (memberObject, remaining); + typeId = await FindStaticTypeId(methodInfo.TypeInfo.Namespace + "." + classNameToFind); + if (typeId != -1) + continue; } + typeId = await FindStaticTypeId(classNameToFind); - // Didn't find a member named `part` in `typeId`. - // Could be a nested type. Let's continue the search - // with `part` added to the type name + string part = parts[i]; + if (typeId != -1) + { + JObject memberObject = await FindStaticMemberInType(classNameToFind, part, typeId); + if (memberObject != null) + { + ArraySegment remaining = null; + if (i < parts.Length - 1) + remaining = parts[i..]; + return (memberObject, remaining); + } - typeId = -1; - } + // Didn't find a member named `part` in `typeId`. + // Could be a nested type. Let's continue the search + // with `part` added to the type name - if (classNameToFind.Length > 0) - classNameToFind += "."; - classNameToFind += part; + typeId = -1; + } - if (!string.IsNullOrEmpty(methodInfo?.TypeInfo?.Namespace)) - { - typeId = await FindStaticTypeId(methodInfo?.TypeInfo?.Namespace + "." + classNameToFind); - if (typeId != -1) - continue; + if (classNameToFind.Length > 0) + classNameToFind += "."; + classNameToFind += part; } - typeId = await FindStaticTypeId(classNameToFind); + return (null, null); } - return (null, null); + // async function full name has a form: namespaceName.d__integer + static string StripAsyncPartOfFullName(string fullName) + => fullName.IndexOf(".<") is int index && index < 0 + ? fullName + : fullName.Substring(0, index); + async Task FindStaticMemberInType(string classNameToFind, string name, int typeId) { @@ -138,11 +158,20 @@ async Task FindStaticMemberInType(string classNameToFind, string name, { isInitialized = await context.SdbAgent.TypeInitialize(typeId, token); } - var staticFieldValue = await context.SdbAgent.GetFieldValue(typeId, field.Id, token); - var valueRet = await GetValueFromObject(staticFieldValue, token); - // we need the full name here - valueRet["className"] = classNameToFind; - return valueRet; + try + { + var staticFieldValue = await context.SdbAgent.GetFieldValue(typeId, field.Id, token); + var valueRet = await GetValueFromObject(staticFieldValue, token); + // we need the full name here + valueRet["className"] = classNameToFind; + return valueRet; + } + catch (Exception ex) + { + logger.LogDebug(ex, $"Failed to get value of field {field.Name} on {classNameToFind} " + + $"because {field.Name} is not a static member of {classNameToFind}."); + } + return null; } var methodId = await context.SdbAgent.GetPropertyMethodIdByName(typeId, name, token); @@ -150,8 +179,16 @@ async Task FindStaticMemberInType(string classNameToFind, string name, { using var commandParamsObjWriter = new MonoBinaryWriter(); commandParamsObjWriter.Write(0); //param count - var retMethod = await context.SdbAgent.InvokeMethod(commandParamsObjWriter.GetParameterBuffer(), methodId, token); - return await GetValueFromObject(retMethod, token); + try + { + var retMethod = await context.SdbAgent.InvokeMethod(commandParamsObjWriter.GetParameterBuffer(), methodId, token); + return await GetValueFromObject(retMethod, token); + } + catch (Exception ex) + { + logger.LogDebug(ex, $"Failed to invoke getter of id={methodId} on {classNameToFind}.{name} " + + $"because {name} is not a static member of {classNameToFind}."); + } } return null; } diff --git a/src/mono/wasm/debugger/DebuggerTestSuite/DebuggerTestBase.cs b/src/mono/wasm/debugger/DebuggerTestSuite/DebuggerTestBase.cs index 21c1f4dbc7afe2..ec8b181493a6a1 100644 --- a/src/mono/wasm/debugger/DebuggerTestSuite/DebuggerTestBase.cs +++ b/src/mono/wasm/debugger/DebuggerTestSuite/DebuggerTestBase.cs @@ -1416,6 +1416,15 @@ internal async Task SetJustMyCode(bool enabled) Assert.True(res.IsOk); Assert.Equal(res.Value["justMyCodeEnabled"], enabled); } + + internal async Task CheckEvaluateFail(string id, params (string expression, string message)[] args) + { + foreach (var arg in args) + { + (_, Result _res) = await EvaluateOnCallFrame(id, arg.expression, expect_ok: false).ConfigureAwait(false);; + AssertEqual(arg.message, _res.Error["result"]?["description"]?.Value(), $"Expression '{arg.expression}' - wrong error message"); + } + } } class DotnetObjectId diff --git a/src/mono/wasm/debugger/DebuggerTestSuite/EvaluateOnCallFrameTests.cs b/src/mono/wasm/debugger/DebuggerTestSuite/EvaluateOnCallFrameTests.cs index 39255e01dce987..2125338b574e5f 100644 --- a/src/mono/wasm/debugger/DebuggerTestSuite/EvaluateOnCallFrameTests.cs +++ b/src/mono/wasm/debugger/DebuggerTestSuite/EvaluateOnCallFrameTests.cs @@ -703,6 +703,34 @@ await EvaluateOnCallFrameAndCheck(id, CheckNumber(props, "a", 11); }); + [Theory] + [InlineData("DebuggerTestsV2.EvaluateStaticClass", "Run", "DebuggerTestsV2", "EvaluateStaticClass", 1, 2)] + [InlineData("DebuggerTests.EvaluateStaticClass", "Run", "DebuggerTests", "EvaluateStaticClass", 1, 1)] + [InlineData("DebuggerTests.EvaluateStaticClass", "RunAsync", "DebuggerTests", "EvaluateStaticClass", 1, 1, true)] + [InlineData("DebuggerTests.EvaluateNonStaticClassWithStaticFields", "RunStatic", "DebuggerTests", "EvaluateNonStaticClassWithStaticFields", 1, 7)] + [InlineData("DebuggerTests.EvaluateNonStaticClassWithStaticFields", "RunStaticAsync", "DebuggerTests", "EvaluateNonStaticClassWithStaticFields", 1, 7, true)] + [InlineData("DebuggerTests.EvaluateNonStaticClassWithStaticFields", "Run", "DebuggerTests", "EvaluateNonStaticClassWithStaticFields", 1, 7)] + [InlineData("DebuggerTests.EvaluateNonStaticClassWithStaticFields", "RunAsync", "DebuggerTests", "EvaluateNonStaticClassWithStaticFields", 1, 7, true)] + public async Task EvaluateStaticFields(string bpLocation, string bpMethod, string namespaceName, string className, int bpLine, int expectedInt, bool isAsync = false) => + await CheckInspectLocalsAtBreakpointSite( + bpLocation, bpMethod, bpLine, isAsync ? "MoveNext" : bpMethod, + "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, + ($"{namespaceName}.{className}.StaticField1", TNumber(expectedInt * 10)), + ($"{namespaceName}.{className}.StaticProperty1", TString($"StaticProperty{expectedInt}")), + ($"{namespaceName}.{className}.StaticPropertyWithError", TString($"System.Exception: not implemented {expectedInt}")), + ($"{className}.StaticField1", TNumber(expectedInt * 10)), + ($"{className}.StaticProperty1",TString($"StaticProperty{expectedInt}")), + ($"{className}.StaticPropertyWithError", TString($"System.Exception: not implemented {expectedInt}")), + ("StaticField1", TNumber(expectedInt * 10)), + ("StaticProperty1", TString($"StaticProperty{expectedInt}")), + ("StaticPropertyWithError", TString($"System.Exception: not implemented {expectedInt}")) + ); + }); + [Fact] public async Task EvaluateStaticClass() => await CheckInspectLocalsAtBreakpointSite( "DebuggerTests.EvaluateMethodTestsClass.TestEvaluate", "run", 9, "run", @@ -718,7 +746,7 @@ await EvaluateOnCallFrameAndCheck(id, await EvaluateOnCallFrameAndCheck(id, ("DebuggerTests.EvaluateStaticClass.StaticProperty1", TString("StaticProperty1"))); await EvaluateOnCallFrameAndCheck(id, - ("DebuggerTests.EvaluateStaticClass.StaticPropertyWithError", TString("System.Exception: not implemented"))); + ("DebuggerTests.EvaluateStaticClass.StaticPropertyWithError", TString("System.Exception: not implemented 1"))); }); [Theory] @@ -737,10 +765,10 @@ public async Task EvaluateStaticClassFromStaticMethod(string type, string method await EvaluateOnCallFrameAndCheck(id, ("EvaluateStaticClass.StaticField1", TNumber(10)), ("EvaluateStaticClass.StaticProperty1", TString("StaticProperty1")), - ("EvaluateStaticClass.StaticPropertyWithError", TString("System.Exception: not implemented")), + ("EvaluateStaticClass.StaticPropertyWithError", TString("System.Exception: not implemented 1")), ("DebuggerTests.EvaluateStaticClass.StaticField1", TNumber(10)), ("DebuggerTests.EvaluateStaticClass.StaticProperty1", TString("StaticProperty1")), - ("DebuggerTests.EvaluateStaticClass.StaticPropertyWithError", TString("System.Exception: not implemented"))); + ("DebuggerTests.EvaluateStaticClass.StaticPropertyWithError", TString("System.Exception: not implemented 1"))); }); [Fact] @@ -754,12 +782,12 @@ public async Task EvaluateNonStaticClassWithStaticFields() => await CheckInspect var frame = pause_location["callFrames"][0]; await EvaluateOnCallFrameAndCheck(id, - ("DebuggerTests.EvaluateNonStaticClassWithStaticFields.StaticField1", TNumber(10)), - ("DebuggerTests.EvaluateNonStaticClassWithStaticFields.StaticProperty1", TString("StaticProperty1")), - ("DebuggerTests.EvaluateNonStaticClassWithStaticFields.StaticPropertyWithError", TString("System.Exception: not implemented")), - ("EvaluateNonStaticClassWithStaticFields.StaticField1", TNumber(10)), - ("EvaluateNonStaticClassWithStaticFields.StaticProperty1", TString("StaticProperty1")), - ("EvaluateNonStaticClassWithStaticFields.StaticPropertyWithError", TString("System.Exception: not implemented"))); + ("DebuggerTests.EvaluateNonStaticClassWithStaticFields.StaticField1", TNumber(70)), + ("DebuggerTests.EvaluateNonStaticClassWithStaticFields.StaticProperty1", TString("StaticProperty7")), + ("DebuggerTests.EvaluateNonStaticClassWithStaticFields.StaticPropertyWithError", TString("System.Exception: not implemented 7")), + ("EvaluateNonStaticClassWithStaticFields.StaticField1", TNumber(70)), + ("EvaluateNonStaticClassWithStaticFields.StaticProperty1", TString("StaticProperty7")), + ("EvaluateNonStaticClassWithStaticFields.StaticPropertyWithError", TString("System.Exception: not implemented 7"))); }); [ConditionalFact(nameof(RunningOnChrome))] @@ -797,6 +825,84 @@ await EvaluateOnCallFrameAndCheck(id, ("NoNamespaceClass.NestedClass1.NestedClass2.NestedClass3.StaticPropertyWithError", TString("System.Exception: not implemented 30"))); }); + [ConditionalFact(nameof(RunningOnChrome))] + public async Task EvaluateStaticClassesNestedWithSameNames() => await CheckInspectLocalsAtBreakpointSite( + "NestedWithSameNames.B.NestedWithSameNames.B", "Run", 1, "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(); + + await EvaluateOnCallFrameAndCheck(id, + ("NestedWithSameNames", TNumber(90)), + ("B.NestedWithSameNames", TNumber(90)), + ("B.StaticField1", TNumber(40)), + ("B.StaticProperty1", TString("StaticProperty4")), + ("B.StaticPropertyWithError", TString("System.Exception: not implemented V4")) + ); + + await CheckEvaluateFail(id, + ("NestedWithSameNames.B.StaticField1", GetPrimitiveHasNoMembersMessage("B")), + ("NestedWithSameNames.B.StaticProperty1", GetPrimitiveHasNoMembersMessage("B")), + ("NestedWithSameNames.B.StaticPropertyWithError", GetPrimitiveHasNoMembersMessage("B")), + ("NestedWithSameNames.B.NestedWithSameNames", GetPrimitiveHasNoMembersMessage("B")), + ("B.NestedWithSameNames.B.StaticField1", GetPrimitiveHasNoMembersMessage("B")), + ("B.NestedWithSameNames.B.StaticProperty1", GetPrimitiveHasNoMembersMessage("B")), + ("B.NestedWithSameNames.B.StaticPropertyWithError", GetPrimitiveHasNoMembersMessage("B")), + ("NestedWithSameNames.B.NestedWithSameNames.B.NestedWithSameNames", GetPrimitiveHasNoMembersMessage("B")), + ("NestedWithSameNames.B.NestedWithDifferentName.B.StaticField1", GetPrimitiveHasNoMembersMessage("B")), + ("NestedWithSameNames.B.NestedWithDifferentName.B.StaticProperty1", GetPrimitiveHasNoMembersMessage("B")), + ("NestedWithSameNames.B.NestedWithDifferentName.B.StaticPropertyWithError", GetPrimitiveHasNoMembersMessage("B")) + ); + string GetPrimitiveHasNoMembersMessage(string name) => $"Cannot find member '{name}' on a primitive type"; + }); + + [ConditionalTheory(nameof(RunningOnChrome))] + [InlineData("DebuggerTests", "EvaluateNonStaticClassWithStaticFields", 7, true)] + [InlineData("DebuggerTestsV2", "EvaluateStaticClass", 2)] + public async Task EvaluateStaticFieldsFromDifferentNamespaceInDifferentFrames(string namespaceName, string className, int expectedInt, bool isFromDifferentNamespace = false) => await CheckInspectLocalsAtBreakpointSite( + "DebuggerTestsV2.EvaluateStaticClass", "Run", 1, "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(); + await EvaluateOnCallFrameAndCheck(id_top, + ("StaticField1", TNumber(20)), + ($"{namespaceName}.{className}.StaticField1", TNumber(expectedInt * 10)), + ("StaticProperty1", TString($"StaticProperty2")), + ($"{namespaceName}.{className}.StaticProperty1", TString($"StaticProperty{expectedInt}")), + ("StaticPropertyWithError", TString($"System.Exception: not implemented 2")), + ($"{namespaceName}.{className}.StaticPropertyWithError", TString($"System.Exception: not implemented {expectedInt}")) + ); + + if (!isFromDifferentNamespace) + { + await EvaluateOnCallFrameAndCheck(id_top, + ($"{className}.StaticField1", TNumber(expectedInt * 10)), + ($"{className}.StaticProperty1", TString($"StaticProperty{expectedInt}")), + ($"{className}.StaticPropertyWithError", TString($"System.Exception: not implemented {expectedInt}")) + ); + } + + var id_second = pause_location["callFrames"][1]["callFrameId"].Value(); + int expectedIntInPrevFrame = isFromDifferentNamespace ? 7 : 1; + await EvaluateOnCallFrameAndCheck(id_second, + ($"{namespaceName}.{className}.StaticField1", TNumber(expectedInt * 10)), + ($"{className}.StaticField1", TNumber(expectedIntInPrevFrame * 10)), + ($"{namespaceName}.{className}.StaticProperty1", TString($"StaticProperty{expectedInt}")), + ($"{className}.StaticProperty1", TString($"StaticProperty{expectedIntInPrevFrame}")), + ($"{namespaceName}.{className}.StaticPropertyWithError", TString($"System.Exception: not implemented {expectedInt}")), + ($"{className}.StaticPropertyWithError", TString($"System.Exception: not implemented {expectedIntInPrevFrame}")) + ); + + await CheckEvaluateFail(id_second, + ("StaticField1", GetNonExistingVarMessage("StaticField1")), + ("StaticProperty1", GetNonExistingVarMessage("StaticProperty1")), + ("StaticPropertyWithError", GetNonExistingVarMessage("StaticPropertyWithError")) + ); + string GetNonExistingVarMessage(string name) => $"The name {name} does not exist in the current context"; + }); + [ConditionalFact(nameof(RunningOnChrome))] public async Task EvaluateStaticClassesFromDifferentNamespaceInDifferentFrames() => await CheckInspectLocalsAtBreakpointSite( "DebuggerTestsV2.EvaluateStaticClass", "Run", 1, "Run", @@ -809,14 +915,14 @@ public async Task EvaluateStaticClassesFromDifferentNamespaceInDifferentFrames() await EvaluateOnCallFrameAndCheck(id_top, ("EvaluateStaticClass.StaticField1", TNumber(20)), ("EvaluateStaticClass.StaticProperty1", TString("StaticProperty2")), - ("EvaluateStaticClass.StaticPropertyWithError", TString("System.Exception: not implemented"))); + ("EvaluateStaticClass.StaticPropertyWithError", TString("System.Exception: not implemented 2"))); var id_second = pause_location["callFrames"][1]["callFrameId"].Value(); await EvaluateOnCallFrameAndCheck(id_second, ("EvaluateStaticClass.StaticField1", TNumber(10)), ("EvaluateStaticClass.StaticProperty1", TString("StaticProperty1")), - ("EvaluateStaticClass.StaticPropertyWithError", TString("System.Exception: not implemented"))); + ("EvaluateStaticClass.StaticPropertyWithError", TString("System.Exception: not implemented 1"))); }); [ConditionalFact(nameof(RunningOnChrome))] @@ -1182,30 +1288,25 @@ public async Task EvaluateNullObjectPropertiesNegative() => await CheckInspectLo wait_for_event_fn: async (pause_location) => { var id = pause_location["callFrames"][0]["callFrameId"].Value(); - await CheckEvaluateFail("list.Count.x", "Cannot find member 'x' on a primitive type"); - await CheckEvaluateFail("listNull.Count", GetNullReferenceErrorOn("\"Count\"")); - await CheckEvaluateFail("listNull!.Count", GetNullReferenceErrorOn("\"Count\"")); - await CheckEvaluateFail("tcNull.MemberListNull.Count", GetNullReferenceErrorOn("\"MemberListNull\"")); - await CheckEvaluateFail("tc.MemberListNull.Count", GetNullReferenceErrorOn("\"Count\"")); - await CheckEvaluateFail("tcNull?.MemberListNull.Count", GetNullReferenceErrorOn("\"Count\"")); - await CheckEvaluateFail("listNull?.Count.NonExistingProperty", GetNullReferenceErrorOn("\"NonExistingProperty\"")); - await CheckEvaluateFail("tc?.MemberListNull! .Count", GetNullReferenceErrorOn("\"Count\"")); - await CheckEvaluateFail("tc?. MemberListNull!.Count", GetNullReferenceErrorOn("\"Count\"")); - await CheckEvaluateFail("tc?.MemberListNull.Count", GetNullReferenceErrorOn("\"Count\"")); - await CheckEvaluateFail("tc! .MemberListNull!.Count", GetNullReferenceErrorOn("\"Count\"")); - await CheckEvaluateFail("tc!.MemberListNull. Count", GetNullReferenceErrorOn("\"Count\"")); - await CheckEvaluateFail("tcNull?.Sibling.MemberListNull?.Count", GetNullReferenceErrorOn("\"MemberListNull?\"")); - await CheckEvaluateFail("listNull?", "Expected expression."); - await CheckEvaluateFail("listNull!.Count", GetNullReferenceErrorOn("\"Count\"")); - await CheckEvaluateFail("x?.p", "Operation '?' not allowed on primitive type - 'x?'"); - + 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?'") + ); string GetNullReferenceErrorOn(string name) => $"Expression threw NullReferenceException trying to access {name} on a null-valued object."; - - async Task CheckEvaluateFail(string expr, string message) - { - (_, Result _res) = await EvaluateOnCallFrame(id, expr, expect_ok: false); - AssertEqual(message, _res.Error["result"]?["description"]?.Value(), $"Expression '{expr}' - wrong error message"); - } }); [Fact] @@ -1311,7 +1412,8 @@ await CheckInspectLocalsAtBreakpointSite( var id = pause_location["callFrames"][0]["callFrameId"].Value(); await EvaluateOnCallFrameAndCheck(id, ("localString", TString($"{pauseMethod}()")), - ("IDefaultInterface.defaultInterfaceMember", TString("defaultInterfaceMember")) //without interface name: "defaultInterfaceMember" fails; Issue #70135 + ("IDefaultInterface.defaultInterfaceMember", TString("defaultInterfaceMember")), + ("defaultInterfaceMember", TString("defaultInterfaceMember")) ); }); } diff --git a/src/mono/wasm/debugger/tests/debugger-test/debugger-evaluate-test.cs b/src/mono/wasm/debugger/tests/debugger-test/debugger-evaluate-test.cs index 539ab3e3c7ad78..b24676a72a6882 100644 --- a/src/mono/wasm/debugger/tests/debugger-test/debugger-evaluate-test.cs +++ b/src/mono/wasm/debugger/tests/debugger-test/debugger-evaluate-test.cs @@ -422,7 +422,13 @@ public static void EvaluateMethods() TestEvaluate f = new TestEvaluate(); f.run(100, 200, "9000", "test", 45); DebuggerTestsV2.EvaluateStaticClass.Run(); - var a = 0; + DebuggerTests.EvaluateStaticClass.Run(); + DebuggerTests.EvaluateStaticClass.RunAsync(); + DebuggerTests.EvaluateNonStaticClassWithStaticFields.RunStatic(); + DebuggerTests.EvaluateNonStaticClassWithStaticFields.RunStaticAsync(); + var instanceWithStaticFields = new EvaluateNonStaticClassWithStaticFields(); + instanceWithStaticFields.Run(); + instanceWithStaticFields.RunAsync(); } public static void EvaluateAsyncMethods() @@ -430,14 +436,23 @@ public static void EvaluateAsyncMethods() var staticClass = new EvaluateNonStaticClassWithStaticFields(); staticClass.run(); } - } public static class EvaluateStaticClass { public static int StaticField1 = 10; public static string StaticProperty1 => "StaticProperty1"; - public static string StaticPropertyWithError => throw new Exception("not implemented"); + public static string StaticPropertyWithError => throw new Exception("not implemented 1"); + + public static void Run() + { + bool stop = true; + } + + public async static void RunAsync() + { + await Task.FromResult(0); + } public static class NestedClass1 { @@ -455,9 +470,29 @@ public static class NestedClass3 public class EvaluateNonStaticClassWithStaticFields { - public static int StaticField1 = 10; - public static string StaticProperty1 => "StaticProperty1"; - public static string StaticPropertyWithError => throw new Exception("not implemented"); + public static int StaticField1 = 70; + public static string StaticProperty1 => "StaticProperty7"; + public static string StaticPropertyWithError => throw new Exception("not implemented 7"); + + public void Run() + { + bool stop = true; + } + + public async void RunAsync() + { + await Task.FromResult(0); + } + + public static void RunStatic() + { + bool stop = true; + } + + public static async void RunStaticAsync() + { + await Task.FromResult(0); + } private int HelperMethod() { @@ -1433,7 +1468,7 @@ public static class EvaluateStaticClass { public static int StaticField1 = 20; public static string StaticProperty1 => "StaticProperty2"; - public static string StaticPropertyWithError => throw new Exception("not implemented"); + public static string StaticPropertyWithError => throw new Exception("not implemented 2"); public static void Run() { @@ -1442,6 +1477,50 @@ public static void Run() } } +public static class NestedWithSameNames +{ + public static int StaticField1 = 30; + public static string StaticProperty1 => "StaticProperty3"; + public static string StaticPropertyWithError => throw new Exception("not implemented V3"); + + public static class B + { + public static int StaticField1 = 60; + public static string StaticProperty1 => "StaticProperty6"; + public static string StaticPropertyWithError => throw new Exception("not implemented V6"); + + public static class NestedWithSameNames + { + public static class B + { + public static int NestedWithSameNames = 90; + public static int StaticField1 = 40; + public static string StaticProperty1 => "StaticProperty4"; + public static string StaticPropertyWithError => throw new Exception("not implemented V4"); + + public static void Run() + { + var a = 0; + } + } + } + public static class NestedWithDifferentName + { + public static class B + { + public static int StaticField1 = 70; + public static string StaticProperty1 => "StaticProperty7"; + public static string StaticPropertyWithError => throw new Exception("not implemented V7"); + } + } + } + + public static void Evaluate() + { + B.NestedWithSameNames.B.Run(); + } +} + public static class NoNamespaceClass {