From 1e28f0a91988c0f4da2bdb066dc353d9f9383482 Mon Sep 17 00:00:00 2001 From: Ilona Tomkowicz Date: Tue, 29 Mar 2022 09:27:16 +0200 Subject: [PATCH 1/6] Added testcase for structures. --- .../EvaluateOnCallFrameTests.cs | 44 +++++++++++-------- .../debugger-test/debugger-evaluate-test.cs | 21 ++++++++- 2 files changed, 44 insertions(+), 21 deletions(-) diff --git a/src/mono/wasm/debugger/DebuggerTestSuite/EvaluateOnCallFrameTests.cs b/src/mono/wasm/debugger/DebuggerTestSuite/EvaluateOnCallFrameTests.cs index 3c012012651bbd..62f3e4815d193c 100644 --- a/src/mono/wasm/debugger/DebuggerTestSuite/EvaluateOnCallFrameTests.cs +++ b/src/mono/wasm/debugger/DebuggerTestSuite/EvaluateOnCallFrameTests.cs @@ -997,26 +997,32 @@ await RuntimeEvaluateAndCheck( ("a.valueToCheck", TNumber(20))); }); - [Fact] - public async Task EvaluateProtectionLevels() => await CheckInspectLocalsAtBreakpointSite( - "DebuggerTests.EvaluateProtectionLevels", "Evaluate", 2, "Evaluate", - "window.setTimeout(function() { invoke_static_method ('[debugger-test] DebuggerTests.EvaluateProtectionLevels:Evaluate'); })", + [Theory] + [InlineData("EvaluateClass", true)] + [InlineData("EvaluateStruct", false)] + public async Task EvaluateProtectionLevels(string entryMethod, bool hasProtectedLevel) => await CheckInspectLocalsAtBreakpointSite( + "DebuggerTests.EvaluateProtectionLevels", entryMethod, 2, entryMethod, + $"window.setTimeout(function() {{ invoke_static_method ('[debugger-test] DebuggerTests.EvaluateProtectionLevels:{entryMethod}'); }})", wait_for_event_fn: async (pause_location) => - { - var id = pause_location["callFrames"][0]["callFrameId"].Value(); - var (obj, _) = await EvaluateOnCallFrame(id, "testClass"); - var (pub, internalAndProtected, priv) = await GetPropertiesSortedByProtectionLevels(obj["objectId"]?.Value()); - - Assert.True(pub[0] != null); - Assert.True(internalAndProtected[0] != null); - Assert.True(internalAndProtected[1] != null); - Assert.True(priv[0] != null); - - Assert.Equal(pub[0]["value"]["value"], "public"); - Assert.Equal(internalAndProtected[0]["value"]["value"], "internal"); - Assert.Equal(internalAndProtected[1]["value"]["value"], "protected"); - Assert.Equal(priv[0]["value"]["value"], "private"); - }); + { + var id = pause_location["callFrames"][0]["callFrameId"].Value(); + var (obj, _) = await EvaluateOnCallFrame(id, "test"); + var (pub, internalAndProtected, priv) = await GetPropertiesSortedByProtectionLevels(obj["objectId"]?.Value()); + + Assert.True(pub[0] != null); + Assert.Equal(pub[0]["value"]["value"], "public"); + + Assert.True(internalAndProtected[0] != null); + Assert.Equal(internalAndProtected[0]["value"]["value"], "internal"); + if (hasProtectedLevel) + { + Assert.True(internalAndProtected[1] != null); + Assert.Equal(internalAndProtected[1]["value"]["value"], "protected"); + } + Assert.True(priv[0] != null); + Assert.Equal(priv[0]["value"]["value"], "private"); + + }); [Fact] public async Task StructureGetters() => await CheckInspectLocalsAtBreakpointSite( 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 baa6bac36b157a..d790d1674d83a1 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 @@ -838,9 +838,26 @@ public TestClass() } } - public static void Evaluate() + public struct TestStruct + { + public string fieldPublic = "public"; + private string fieldPrivate = "private"; + internal string fieldInternal = "internal"; + + public TestStruct() + { + var a = fieldPrivate; + } + } + + public static void EvaluateClass() + { + var test = new TestClass(); + } + + public static void EvaluateStruct() { - var testClass = new TestClass(); + var test = new TestStruct(); } } From 56b6d52dc9f04989ddf522934392990e25298307 Mon Sep 17 00:00:00 2001 From: Ilona Tomkowicz Date: Tue, 29 Mar 2022 09:38:02 +0200 Subject: [PATCH 2/6] Refactoring of ValueTypeClass. --- .../BrowserDebugProxy/MonoSDBHelper.cs | 43 +++++++++++-------- 1 file changed, 25 insertions(+), 18 deletions(-) diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs b/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs index f8ad79aa8a8f74..779bda8de4e824 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs @@ -710,23 +710,23 @@ public FieldTypeClass(int id, string name, int typeId, bool isNotPrivate, FieldA internal class ValueTypeClass { public byte[] valueTypeBuffer; - public JArray valueTypeJson; - public JArray valueTypeJsonProps; + public JArray json; + public JArray jsonProps; public int typeId; public JArray valueTypeProxy; public string valueTypeVarName; public bool valueTypeAutoExpand; - public int Id; + public string Id; public ValueTypeClass(string varName, byte[] buffer, JArray json, int id, bool expand_properties, int valueTypeId) { valueTypeBuffer = buffer; - valueTypeJson = json; + this.json = json; typeId = id; - valueTypeJsonProps = null; + jsonProps = null; valueTypeProxy = null; valueTypeVarName = varName; valueTypeAutoExpand = expand_properties; - Id = valueTypeId; + Id = $"dotnet:valuetype:{valueTypeId}"; } } internal class PointerValue @@ -1699,7 +1699,7 @@ public async Task GetPointerContent(int pointerId, CancellationToken to public async Task GetPropertiesValuesOfValueType(int valueTypeId, CancellationToken token) { - JArray ret = new JArray(); + JArray properties = new JArray(); var valueType = valueTypes[valueTypeId]; using var commandParamsWriter = new MonoBinaryWriter(); commandParamsWriter.Write(valueType.typeId); @@ -1707,17 +1707,24 @@ public async Task GetPropertiesValuesOfValueType(int valueTypeId, Cancel var parentsCount = retDebuggerCmdReader.ReadInt32(); List typesToGetProperties = new List(); typesToGetProperties.Add(valueType.typeId); - for (int i = 0 ; i < parentsCount; i++) + for (int i = 0; i < parentsCount; i++) { typesToGetProperties.Add(retDebuggerCmdReader.ReadInt32()); } - for (int i = 0 ; i < typesToGetProperties.Count; i++) + for (int i = 0; i < typesToGetProperties.Count; i++) { - var properties = await CreateJArrayForProperties(typesToGetProperties[i], ElementType.ValueType, valueType.valueTypeBuffer, valueType.valueTypeJson, valueType.valueTypeAutoExpand, $"dotnet:valuetype:{valueType.Id}", i == 0, token); - ret = new JArray(ret.Union(properties)); + var props = await CreateJArrayForProperties( + typesToGetProperties[i], + ElementType.ValueType, + valueType.valueTypeBuffer, + valueType.json, + valueType.valueTypeAutoExpand, + valueType.Id, + isOwn: i == 0, + token); + properties.AddRange(props); } - - return ret; + return properties; } private static bool AutoExpandable(string className) { @@ -2205,13 +2212,13 @@ public async Task StackFrameGetValues(MethodInfoWithDebugInformation met public async Task GetValueTypeValues(int valueTypeId, bool accessorPropertiesOnly, CancellationToken token) { - if (valueTypes[valueTypeId].valueTypeJsonProps == null) + if (valueTypes[valueTypeId].jsonProps == null) { - valueTypes[valueTypeId].valueTypeJsonProps = await GetPropertiesValuesOfValueType(valueTypeId, token); + valueTypes[valueTypeId].jsonProps = await GetPropertiesValuesOfValueType(valueTypeId, token); } if (accessorPropertiesOnly) - return valueTypes[valueTypeId].valueTypeJsonProps; - var ret = new JArray(valueTypes[valueTypeId].valueTypeJson.Union(valueTypes[valueTypeId].valueTypeJsonProps)); + return valueTypes[valueTypeId].jsonProps; + var ret = new JArray(valueTypes[valueTypeId].jsonProps.Union(valueTypes[valueTypeId].jsonProps)); return ret; } @@ -2219,7 +2226,7 @@ public async Task GetValueTypeProxy(int valueTypeId, CancellationToken t { if (valueTypes[valueTypeId].valueTypeProxy != null) return valueTypes[valueTypeId].valueTypeProxy; - valueTypes[valueTypeId].valueTypeProxy = new JArray(valueTypes[valueTypeId].valueTypeJson); + valueTypes[valueTypeId].valueTypeProxy = new JArray(valueTypes[valueTypeId].json); var retDebuggerCmdReader = await GetTypePropertiesReader(valueTypes[valueTypeId].typeId, token); if (retDebuggerCmdReader == null) From 88d5d7f92cf7d9ff57af516404b0496b60b4f5de Mon Sep 17 00:00:00 2001 From: Ilona Tomkowicz Date: Tue, 29 Mar 2022 09:50:49 +0200 Subject: [PATCH 3/6] Implemented sorting in value type. --- .../debugger/BrowserDebugProxy/MonoProxy.cs | 2 +- .../BrowserDebugProxy/MonoSDBHelper.cs | 126 ++++++++++++------ 2 files changed, 88 insertions(+), 40 deletions(-) diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs b/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs index f269430a6d9508..0d5b9297008261 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs @@ -757,7 +757,7 @@ internal async Task> RuntimeGetPropertiesInternal(SessionId } case "valuetype": { - var resValType = await context.SdbAgent.GetValueTypeValues(objectId.Value, accessorPropertiesOnly, token); + var resValType = await context.SdbAgent.GetValueTypeValues(objectId.Value, accessorPropertiesOnly, token, sortByAccessLevel); return resValType switch { null => ValueOrError.WithError($"Could not get properties for {objectId}"), diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs b/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs index 779bda8de4e824..493b28b91e9e27 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs @@ -710,14 +710,14 @@ public FieldTypeClass(int id, string name, int typeId, bool isNotPrivate, FieldA internal class ValueTypeClass { public byte[] valueTypeBuffer; - public JArray json; + public JObject json; public JArray jsonProps; public int typeId; public JArray valueTypeProxy; public string valueTypeVarName; public bool valueTypeAutoExpand; public string Id; - public ValueTypeClass(string varName, byte[] buffer, JArray json, int id, bool expand_properties, int valueTypeId) + public ValueTypeClass(string varName, byte[] buffer, JObject json, int id, bool expand_properties, int valueTypeId) { valueTypeBuffer = buffer; this.json = json; @@ -1633,7 +1633,7 @@ public async Task GetPropertyMethodIdByName(int typeId, string propertyName return -1; } - public async Task CreateJArrayForProperties(int typeId, ElementType elementType, ArraySegment object_buffer, JArray attributes, bool isAutoExpandable, string objectIdStr, bool isOwn, CancellationToken token) + public async Task CreateJArrayForProperties(int typeId, ArraySegment object_buffer, bool isAutoExpandable, string objectIdStr, bool isOwn, CancellationToken token, params JToken[] attributesCollections) { JArray ret = new JArray(); using var retDebuggerCmdReader = await GetTypePropertiesReader(typeId, token); @@ -1652,32 +1652,36 @@ public async Task CreateJArrayForProperties(int typeId, ElementType elem if (getMethodId == 0 || await GetParamCount(getMethodId, token) != 0 || await MethodIsStatic(getMethodId, token)) continue; JObject propRet = null; - if (attributes.Where(attribute => attribute["name"].Value().Equals(propertyNameStr)).Any()) + if (attributesCollections + .Any(attributes => attributes + .Where(attribute => attribute["name"].Value().Equals(propertyNameStr)).Any())) continue; if (isAutoExpandable) { - try { + try + { propRet = await InvokeMethod(object_buffer, getMethodId, propertyNameStr, token); } - catch (Exception) + catch (Exception ex) { - continue; + logger.LogDebug($"Method {getMethodId} of object {objectId.Value} could not be ivoked as AutoExpandable, error - {ex.Message}."); } } - else + if (propRet == null) { - propRet = JObject.FromObject(new { - get = new - { - type = "function", - objectId = $"dotnet:methodId:{objectId.Value}:{getMethodId}:{elementType}", - className = "Function", - description = "get " + propertyNameStr + " ()", - methodId = getMethodId, - objectIdValue = objectIdStr - }, - name = propertyNameStr - }); + propRet = JObject.FromObject(new + { + get = new + { + type = "function", + objectId = $"dotnet:methodId:{objectId.Value}:{getMethodId}", + className = "Function", + description = "get " + propertyNameStr + " ()", + methodId = getMethodId, + objectIdValue = objectIdStr + }, + name = propertyNameStr + }); } if (isOwn) propRet["isOwn"] = true; @@ -1715,13 +1719,14 @@ public async Task GetPropertiesValuesOfValueType(int valueTypeId, Cancel { var props = await CreateJArrayForProperties( typesToGetProperties[i], - ElementType.ValueType, valueType.valueTypeBuffer, - valueType.json, valueType.valueTypeAutoExpand, valueType.Id, isOwn: i == 0, - token); + token, + valueType.json["result"], + valueType.json["internalProperties"], + valueType.json["privateProperties"]); properties.AddRange(props); } return properties; @@ -1878,7 +1883,6 @@ public async Task CreateJObjectForValueType(MonoBinaryReader retDebugge var description = className; var numFields = retDebuggerCmdReader.ReadInt32(); var fields = await GetTypeFields(typeId, token); - JArray valueTypeFields = new JArray(); if (className.IndexOf("System.Nullable<") == 0) //should we call something on debugger-agent to check??? { retDebuggerCmdReader.ReadByte(); //ignoring the boolean type @@ -1889,10 +1893,28 @@ public async Task CreateJObjectForValueType(MonoBinaryReader retDebugge else return CreateJObject(null, "object", className, false, className, null, null, "null", true); } - for (int i = 0; i < numFields ; i++) + + JArray fieldsPublic = new JArray(); + JArray fieldsInternal = new JArray(); + JArray fieldsPrivate = new JArray(); + for (int i = 0; i < numFields; i++) { - fieldValueType = await CreateJObjectForVariableValue(retDebuggerCmdReader, fields.ElementAt(i).Name, true, fields.ElementAt(i).TypeId, false, token); - valueTypeFields.Add(fieldValueType); + fieldValueType = await CreateJObjectForVariableValue(retDebuggerCmdReader, fields[i].Name, true, fields[i].TypeId, false, token); + switch (fields[i].ProtectionLevel) + { + case FieldAttributes.Public: + fieldsPublic.Add(fieldValueType); + break; + case FieldAttributes.FamANDAssem: + case FieldAttributes.Private: + fieldsPrivate.Add(fieldValueType); + break; + case FieldAttributes.Family: + case FieldAttributes.Assembly: + case FieldAttributes.FamORAssem: + fieldsInternal.Add(fieldValueType); + break; + } } long endPos = retDebuggerCmdReader.BaseStream.Position; @@ -1902,6 +1924,12 @@ public async Task CreateJObjectForValueType(MonoBinaryReader retDebugge byte[] valueTypeBuffer = new byte[endPos - initialPos]; retDebuggerCmdReader.Read(valueTypeBuffer, 0, (int)(endPos - initialPos)); retDebuggerCmdReader.BaseStream.Position = endPos; + var valueTypeFields = JObject.FromObject(new + { + result = fieldsPublic, + internalProperties = fieldsInternal, + privateProperties = fieldsPrivate + }); valueTypes[valueTypeId] = new ValueTypeClass(name, valueTypeBuffer, valueTypeFields, typeId, AutoExpandable(className), valueTypeId); if (AutoInvokeToString(className) || isEnum == 1) { int methodId = await GetMethodIdByName(typeId, "ToString", token); @@ -2210,16 +2238,31 @@ public async Task StackFrameGetValues(MethodInfoWithDebugInformation met } - public async Task GetValueTypeValues(int valueTypeId, bool accessorPropertiesOnly, CancellationToken token) + public async Task GetValueTypeValues(int valueTypeId, bool accessorPropertiesOnly, CancellationToken token, bool sortByAccessLevel) { if (valueTypes[valueTypeId].jsonProps == null) - { valueTypes[valueTypeId].jsonProps = await GetPropertiesValuesOfValueType(valueTypeId, token); - } if (accessorPropertiesOnly) - return valueTypes[valueTypeId].jsonProps; - var ret = new JArray(valueTypes[valueTypeId].jsonProps.Union(valueTypes[valueTypeId].jsonProps)); - return ret; + return sortByAccessLevel ? + JObject.FromObject(new + { + result = valueTypes[valueTypeId].jsonProps, + internalProperties = new JArray(), + privateProperties = new JArray() + }) : + valueTypes[valueTypeId].jsonProps; + var publicValues = valueTypes[valueTypeId].json["result"].Union(valueTypes[valueTypeId].jsonProps); + var internalValues = valueTypes[valueTypeId].json["internalProperties"]; + var privateValues = valueTypes[valueTypeId].json["privateProperties"]; + + return sortByAccessLevel ? + JObject.FromObject(new + { + result = publicValues, + internalProperties = internalValues, + privateProperties = privateValues + }) : + new JArray(publicValues.Union(internalValues).Union(privateValues)); } public async Task GetValueTypeProxy(int valueTypeId, CancellationToken token) @@ -2232,6 +2275,12 @@ public async Task GetValueTypeProxy(int valueTypeId, CancellationToken t if (retDebuggerCmdReader == null) return null; + valueTypes[valueTypeId].valueTypeProxy = new JArray(); + valueTypes[valueTypeId].valueTypeProxy.AddRange( + valueTypes[valueTypeId].json["result"], + valueTypes[valueTypeId].json["internalProperties"], + valueTypes[valueTypeId].json["privateProperties"]); + var nProperties = retDebuggerCmdReader.ReadInt32(); for (int i = 0 ; i < nProperties; i++) @@ -2455,13 +2504,12 @@ public async Task GetObjectValues(int objectId, GetObjectCommandOptions commandParamsObjWriter.WriteObj(new DotnetObjectId("object", objectId), this); var props = await CreateJArrayForProperties( typeId, - ElementType.Class, commandParamsObjWriter.GetParameterBuffer(), - new JArray(objects.Values), getCommandType.HasFlag(GetObjectCommandOptions.ForDebuggerProxyAttribute), $"dotnet:object:{objectId}", i == 0, - token); + token, + new JArray(objects.Values)); var properties = await GetProperties(props, allFields, typeId, token); objects.TryAddRange(properties); @@ -2806,10 +2854,10 @@ public async Task ApplyUpdates(int moduleId, string dmeta, string dil, str internal static class HelperExtensions { - public static void AddRange(this JArray arr, JArray addedArr) + public static void AddRange(this JArray arr, params JToken[] addedArrays) { - foreach (var item in addedArr) - arr.Add(item); + foreach (var addedArray in addedArrays) + arr.Merge(addedArray); } public static void TryAddRange(this Dictionary dict, JArray addedArr) From 6ae168d513190c3ab5cf80cb748ae663fd5f8a0b Mon Sep 17 00:00:00 2001 From: Ilona Tomkowicz Date: Fri, 1 Apr 2022 09:08:42 +0200 Subject: [PATCH 4/6] Fixed failing tests after merge. --- src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs b/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs index 4b62adf904decf..5aac63b4785e3c 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs @@ -1632,7 +1632,7 @@ public async Task GetPropertyMethodIdByName(int typeId, string propertyName return -1; } - public async Task CreateJArrayForProperties(int typeId, ArraySegment object_buffer, bool isAutoExpandable, string objectIdStr, bool isOwn, CancellationToken token, params JToken[] attributesCollections) + public async Task CreateJArrayForProperties(int typeId, ElementType elementType, ArraySegment object_buffer, bool isAutoExpandable, string objectIdStr, bool isOwn, CancellationToken token, params JToken[] attributesCollections) { JArray ret = new JArray(); using var retDebuggerCmdReader = await GetTypePropertiesReader(typeId, token); @@ -1673,7 +1673,7 @@ public async Task CreateJArrayForProperties(int typeId, ArraySegment GetPropertiesValuesOfValueType(int valueTypeId, Cancel { var props = await CreateJArrayForProperties( typesToGetProperties[i], + ElementType.ValueType, valueType.valueTypeBuffer, valueType.valueTypeAutoExpand, valueType.Id, @@ -2506,6 +2507,7 @@ public async Task GetObjectValues(int objectId, GetObjectCommandOptions commandParamsObjWriter.WriteObj(new DotnetObjectId("object", objectId), this); var props = await CreateJArrayForProperties( typeId, + ElementType.Class, commandParamsObjWriter.GetParameterBuffer(), getCommandType.HasFlag(GetObjectCommandOptions.ForDebuggerProxyAttribute), $"dotnet:object:{objectId}", From 693c4f680684b581b565888874c3491fd916872b Mon Sep 17 00:00:00 2001 From: Ilona Tomkowicz Date: Mon, 4 Apr 2022 10:30:53 +0200 Subject: [PATCH 5/6] Remove redundant writing to field as it's overwritten later. Change to Extentions is not needed in this situation. --- .../BrowserDebugProxy/MonoSDBHelper.cs | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs b/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs index 5aac63b4785e3c..5bd65b4dffed9a 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs @@ -2272,21 +2272,19 @@ public async Task GetValueTypeProxy(int valueTypeId, CancellationToken t { if (valueTypes[valueTypeId].valueTypeProxy != null) return valueTypes[valueTypeId].valueTypeProxy; - valueTypes[valueTypeId].valueTypeProxy = new JArray(valueTypes[valueTypeId].json); - var retDebuggerCmdReader = await GetTypePropertiesReader(valueTypes[valueTypeId].typeId, token); - if (retDebuggerCmdReader == null) - return null; - - valueTypes[valueTypeId].valueTypeProxy = new JArray(); - valueTypes[valueTypeId].valueTypeProxy.AddRange( + valueTypes[valueTypeId].valueTypeProxy = new JArray( valueTypes[valueTypeId].json["result"], valueTypes[valueTypeId].json["internalProperties"], valueTypes[valueTypeId].json["privateProperties"]); + var retDebuggerCmdReader = await GetTypePropertiesReader(valueTypes[valueTypeId].typeId, token); + if (retDebuggerCmdReader == null) + return null; + var nProperties = retDebuggerCmdReader.ReadInt32(); - for (int i = 0 ; i < nProperties; i++) + for (int i = 0; i < nProperties; i++) { retDebuggerCmdReader.ReadInt32(); //propertyId string propertyNameStr = retDebuggerCmdReader.ReadString(); @@ -2858,10 +2856,10 @@ public async Task ApplyUpdates(int moduleId, string dmeta, string dil, str internal static class HelperExtensions { - public static void AddRange(this JArray arr, params JToken[] addedArrays) + public static void AddRange(this JArray arr, JArray addedArr) { - foreach (var addedArray in addedArrays) - arr.Merge(addedArray); + foreach (var item in addedArr) + arr.Add(item); } public static void TryAddRange(this Dictionary dict, JArray addedArr) From 6ddb49f8473b31ed3394ffd57c4d554f25872831 Mon Sep 17 00:00:00 2001 From: Ilona Tomkowicz Date: Wed, 6 Apr 2022 13:59:34 +0200 Subject: [PATCH 6/6] Made tests more complex - it revealed that sorting is not fully correct. --- .../EvaluateOnCallFrameTests.cs | 27 ----- .../DebuggerTestSuite/GetPropertiesTests.cs | 98 +++++++++++++++++++ .../debugger-test/debugger-evaluate-test.cs | 38 ------- .../debugger-get-properties-test.cs | 4 + 4 files changed, 102 insertions(+), 65 deletions(-) diff --git a/src/mono/wasm/debugger/DebuggerTestSuite/EvaluateOnCallFrameTests.cs b/src/mono/wasm/debugger/DebuggerTestSuite/EvaluateOnCallFrameTests.cs index 9d1bb7b6dc73e5..2f7158b7142638 100644 --- a/src/mono/wasm/debugger/DebuggerTestSuite/EvaluateOnCallFrameTests.cs +++ b/src/mono/wasm/debugger/DebuggerTestSuite/EvaluateOnCallFrameTests.cs @@ -997,33 +997,6 @@ await RuntimeEvaluateAndCheck( ("a.valueToCheck", TNumber(20))); }); - [Theory] - [InlineData("EvaluateClass", true)] - [InlineData("EvaluateStruct", false)] - public async Task EvaluateProtectionLevels(string entryMethod, bool hasProtectedLevel) => await CheckInspectLocalsAtBreakpointSite( - "DebuggerTests.EvaluateProtectionLevels", entryMethod, 2, entryMethod, - $"window.setTimeout(function() {{ invoke_static_method ('[debugger-test] DebuggerTests.EvaluateProtectionLevels:{entryMethod}'); }})", - wait_for_event_fn: async (pause_location) => - { - var id = pause_location["callFrames"][0]["callFrameId"].Value(); - var (obj, _) = await EvaluateOnCallFrame(id, "test"); - var (pub, internalAndProtected, priv) = await GetPropertiesSortedByProtectionLevels(obj["objectId"]?.Value()); - - Assert.True(pub[0] != null); - Assert.Equal(pub[0]["value"]["value"], "public"); - - Assert.True(internalAndProtected[0] != null); - Assert.Equal(internalAndProtected[0]["value"]["value"], "internal"); - if (hasProtectedLevel) - { - Assert.True(internalAndProtected[1] != null); - Assert.Equal(internalAndProtected[1]["value"]["value"], "protected"); - } - Assert.True(priv[0] != null); - Assert.Equal(priv[0]["value"]["value"], "private"); - - }); - [Fact] public async Task StructureGetters() => await CheckInspectLocalsAtBreakpointSite( "DebuggerTests.StructureGetters", "Evaluate", 2, "Evaluate", diff --git a/src/mono/wasm/debugger/DebuggerTestSuite/GetPropertiesTests.cs b/src/mono/wasm/debugger/DebuggerTestSuite/GetPropertiesTests.cs index f91ba3c012effb..0de5d2b438b778 100644 --- a/src/mono/wasm/debugger/DebuggerTestSuite/GetPropertiesTests.cs +++ b/src/mono/wasm/debugger/DebuggerTestSuite/GetPropertiesTests.cs @@ -24,6 +24,9 @@ public class GetPropertiesTests : DebuggerTestBase {"_dateTime", (TDateTime(new DateTime(2020, 7, 6, 5, 4, 3)), true)}, {"_DTProp", (TGetter("_DTProp"), true)}, + // internal + {"b", (TBool(true), true)}, + // own public {"a", (TNumber(4), true)}, {"DateTime", (TGetter("DateTime"), true)}, @@ -126,6 +129,9 @@ public class GetPropertiesTests : DebuggerTestBase {"_stringField", (TString("CloneableStruct#_stringField"), true)}, {"_dateTime", (TDateTime(new DateTime(2020, 7, 6, 5, 4, 3 + 3)), true)}, {"_DTProp", (TGetter("_DTProp"), true)}, + + // internal + {"b", (TBool(true), true)}, // own public {"a", (TNumber(4), true)}, @@ -401,5 +407,97 @@ private static void AssertHasOnlyExpectedProperties(string[] expected_names, IEn } } + public static TheoryData, Dictionary, Dictionary, string> ClassGetPropertiesByProtectionLevels() + { + var data = new TheoryData, Dictionary, Dictionary, string>(); + // object DerivedClass: + var public_props = new Dictionary() + { + {"_DTProp", TGetter("_DTProp")}, // private: should not be here, is a property + + // own + {"a", TNumber(4)}, + {"DateTime", TGetter("DateTime")}, + // {"AutoStringProperty", TString("DerivedClass#AutoStringProperty")}, // should be here + {"FirstName", TGetter("FirstName")}, + // {"DateTimeForOverride", TGetter("DateTimeForOverride")}, // should be here + + // {"StringPropertyForOverrideWithAutoProperty", TString("DerivedClass#StringPropertyForOverrideWithAutoProperty")}, // should be here + {"Base_AutoStringPropertyForOverrideWithField", TString("DerivedClass#Base_AutoStringPropertyForOverrideWithField")}, + {"Base_GetterForOverrideWithField", TString("DerivedClass#Base_GetterForOverrideWithField")}, + {"BaseBase_MemberForOverride", TString("DerivedClass#BaseBase_MemberForOverride")}, + + {"_base_dateTime", TGetter("_base_dateTime")}, // private: should not be here + + // inherited public - should be here! + // {"Base_AutoStringProperty", TString("base#Base_AutoStringProperty")}, // should be here + + {"LastName", TGetter("LastName")} + }; + + var internal_protected_props = new Dictionary(){ + // internal + {"b", TBool(true)}, + // inherited protected + {"base_num", TNumber(5)} + }; + + var private_props = new Dictionary(){ + {"_stringField", TString("DerivedClass#_stringField")}, + {"_dateTime", TDateTime(new DateTime(2020, 7, 6, 5, 4, 3))}, + {"AutoStringProperty", TString("DerivedClass#AutoStringProperty")}, // public: should not be here + {"StringPropertyForOverrideWithAutoProperty", TString("DerivedClass#StringPropertyForOverrideWithAutoProperty")}, // public: should not be here + {"_base_name", TString("private_name")}, + {"Base_AutoStringProperty", TString("base#Base_AutoStringProperty")}, // public: should not be here + {"DateTimeForOverride", TGetter("DateTimeForOverride")} // public: should not be here + }; + // data.Add(public_props, internal_protected_props, private_props, "DerivedClass"); + + // structure CloneableStruct: + public_props = new Dictionary() + { + {"_DTProp", TGetter("_DTProp")}, // private: should not be here + + // own + {"a", TNumber(4)}, + {"DateTime", TGetter("DateTime")}, + // {"AutoStringProperty", TString("CloneableStruct#AutoStringProperty")}, // should be here + {"FirstName", TGetter("FirstName")}, + {"LastName", TGetter("LastName")} + }; + internal_protected_props = new Dictionary() + { + // internal + {"b", TBool(true)} + }; + private_props = new Dictionary() + { + {"_stringField", TString("CloneableStruct#_stringField")}, + {"_dateTime", TDateTime(new DateTime(2020, 7, 6, 5, 4, 3 + 3))}, + // {"_DTProp", TGetter("_DTProp")}, // should be here + + {"AutoStringProperty", TString("CloneableStruct#AutoStringProperty")} // public: should not be here + }; + data.Add(public_props, internal_protected_props, private_props, "CloneableStruct"); + return data; + } + + [Theory] + [MemberData(nameof(ClassGetPropertiesByProtectionLevels))] + public async Task PropertiesSortedByProtectionLevel( + Dictionary expectedPublic, Dictionary expectedProtInter, Dictionary expectedPriv, string entryMethod) => + await CheckInspectLocalsAtBreakpointSite( + $"DebuggerTests.GetPropertiesTests.{entryMethod}", "InstanceMethod", 1, "InstanceMethod", + $"window.setTimeout(function() {{ invoke_static_method ('[debugger-test] DebuggerTests.GetPropertiesTests.{entryMethod}:run'); }})", + wait_for_event_fn: async (pause_location) => + { + var id = pause_location["callFrames"][0]["callFrameId"].Value(); + var (obj, _) = await EvaluateOnCallFrame(id, "this"); + var (pub, internalAndProtected, priv) = await GetPropertiesSortedByProtectionLevels(obj["objectId"]?.Value()); + + await CheckProps(pub, expectedPublic, "public"); + await CheckProps(internalAndProtected, expectedProtInter, "internalAndProtected"); + await CheckProps(priv, expectedPriv, "private"); + }); } } 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 d790d1674d83a1..80db1d2c310eed 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 @@ -823,44 +823,6 @@ public static void Evaluate() } } - public static class EvaluateProtectionLevels - { - public class TestClass - { - public string fieldPublic = "public"; - private string fieldPrivate = "private"; - internal string fieldInternal = "internal"; - protected string fieldProtected = "protected"; - - public TestClass() - { - var a = fieldPrivate; - } - } - - public struct TestStruct - { - public string fieldPublic = "public"; - private string fieldPrivate = "private"; - internal string fieldInternal = "internal"; - - public TestStruct() - { - var a = fieldPrivate; - } - } - - public static void EvaluateClass() - { - var test = new TestClass(); - } - - public static void EvaluateStruct() - { - var test = new TestStruct(); - } - } - public static class StructureGetters { public struct Point diff --git a/src/mono/wasm/debugger/tests/debugger-test/debugger-get-properties-test.cs b/src/mono/wasm/debugger/tests/debugger-test/debugger-get-properties-test.cs index d591a34ce140ae..c14dc5779c209e 100644 --- a/src/mono/wasm/debugger/tests/debugger-test/debugger-get-properties-test.cs +++ b/src/mono/wasm/debugger/tests/debugger-test/debugger-get-properties-test.cs @@ -64,6 +64,8 @@ public class DerivedClass : BaseClass, ICloneable private DateTime _dateTime = new DateTime(2020, 7, 6, 5, 4, 3); private DateTime _DTProp => new DateTime(2200, 5, 6, 7, 8, 9); + internal bool b = true; + public int a; public DateTime DateTime => _DTProp.AddMinutes(10); public string AutoStringProperty { get; set; } @@ -117,6 +119,8 @@ public struct CloneableStruct : ICloneable, IName private DateTime _dateTime; private DateTime _DTProp => new DateTime(2200, 5, 6, 7, 8, 9); + internal bool b = true; + public int a; public DateTime DateTime => _DTProp.AddMinutes(10); public string AutoStringProperty { get; set; }