From b14ac5d5b6173459c2a9a35e3012667bdb6543cd Mon Sep 17 00:00:00 2001
From: Medeni Baykal <433724+Haplois@users.noreply.github.com>
Date: Thu, 8 Sep 2022 22:37:30 +0200
Subject: [PATCH] Fix ManagedNameHelper to support namespaceless methods.
---
.../ManagedNameHelper.Reflection.cs | 31 +++-
.../PublicAPI/PublicAPI.Shipped.txt | 4 +-
.../ManagedNameGeneratorTests.cs | 126 ++++++++++++++
.../TestClasses.cs | 159 +++++++++++-------
test/TestAssets/CILProject/CILProject.proj | 2 +-
5 files changed, 249 insertions(+), 73 deletions(-)
create mode 100644 test/Microsoft.TestPlatform.AdapterUtilities.UnitTests/ManagedNameUtilities/ManagedNameGeneratorTests.cs
diff --git a/src/Microsoft.TestPlatform.AdapterUtilities/ManagedNameUtilities/ManagedNameHelper.Reflection.cs b/src/Microsoft.TestPlatform.AdapterUtilities/ManagedNameUtilities/ManagedNameHelper.Reflection.cs
index f7c42c9f42..b5d0c32227 100644
--- a/src/Microsoft.TestPlatform.AdapterUtilities/ManagedNameUtilities/ManagedNameHelper.Reflection.cs
+++ b/src/Microsoft.TestPlatform.AdapterUtilities/ManagedNameUtilities/ManagedNameHelper.Reflection.cs
@@ -78,7 +78,7 @@ public static void GetManagedName(MethodBase method, out string managedTypeName,
/// More information about and can be found in
/// the RFC.
///
- public static void GetManagedName(MethodBase method, out string managedTypeName, out string managedMethodName, out string[] hierarchyValues)
+ public static void GetManagedName(MethodBase method, out string managedTypeName, out string managedMethodName, out string?[] hierarchyValues)
{
GetManagedName(method, out managedTypeName, out managedMethodName);
GetManagedNameAndHierarchy(method, true, out _, out _, out hierarchyValues);
@@ -102,14 +102,14 @@ public static void GetManagedName(MethodBase method, out string managedTypeName,
///
/// The hierarchy values.
///
- public static string[] GetManagedHierarchy(MethodBase method)
+ public static string?[] GetManagedHierarchy(MethodBase method)
{
GetManagedNameAndHierarchy(method, true, out _, out _, out var hierarchyValues);
return hierarchyValues;
}
- private static void GetManagedNameAndHierarchy(MethodBase method, bool useClosedTypes, out string managedTypeName, out string managedMethodName, out string[] hierarchyValues)
+ private static void GetManagedNameAndHierarchy(MethodBase method, bool useClosedTypes, out string managedTypeName, out string managedMethodName, out string?[] hierarchyValues)
{
_ = method ?? throw new ArgumentNullException(nameof(method));
@@ -191,8 +191,16 @@ private static void GetManagedNameAndHierarchy(MethodBase method, bool useClosed
hierarchyValues = new string[HierarchyConstants.Levels.TotalLevelCount];
hierarchyValues[HierarchyConstants.Levels.TestGroupIndex] = managedMethodName.Substring(0, methodNameEndIndex);
- hierarchyValues[HierarchyConstants.Levels.ClassIndex] = managedTypeName.Substring(hierarchyPos[1] + 1, hierarchyPos[2] - hierarchyPos[1] - 1);
- hierarchyValues[HierarchyConstants.Levels.NamespaceIndex] = managedTypeName.Substring(hierarchyPos[0], hierarchyPos[1] - hierarchyPos[0]);
+ if (hierarchyPos[1] == hierarchyPos[0]) // No namespace
+ {
+ hierarchyValues[HierarchyConstants.Levels.ClassIndex] = managedTypeName.Substring(0, hierarchyPos[2]);
+ hierarchyValues[HierarchyConstants.Levels.NamespaceIndex] = null;
+ }
+ else
+ {
+ hierarchyValues[HierarchyConstants.Levels.ClassIndex] = managedTypeName.Substring(hierarchyPos[1] + 1, hierarchyPos[2] - hierarchyPos[1] - 1);
+ hierarchyValues[HierarchyConstants.Levels.NamespaceIndex] = managedTypeName.Substring(hierarchyPos[0], hierarchyPos[1] - hierarchyPos[0]);
+ }
hierarchyValues[HierarchyConstants.Levels.ContainerIndex] = method.DeclaringType?.GetTypeInfo()?.Assembly?.GetName()?.Name ?? string.Empty;
}
@@ -328,10 +336,17 @@ bool Filter(MemberInfo mbr, object? param)
hierarchies = new int[3];
hierarchies[0] = b.Length;
- AppendNamespace(b, type.Namespace);
- hierarchies[1] = b.Length;
+ if (type.Namespace != null)
+ {
+ AppendNamespace(b, type.Namespace);
+ hierarchies[1] = b.Length;
- b.Append('.');
+ b.Append('.');
+ }
+ else
+ {
+ hierarchies[1] = hierarchies[0];
+ }
AppendNestedTypeName(b, type, closedType);
if (closedType)
diff --git a/src/Microsoft.TestPlatform.AdapterUtilities/PublicAPI/PublicAPI.Shipped.txt b/src/Microsoft.TestPlatform.AdapterUtilities/PublicAPI/PublicAPI.Shipped.txt
index a758469bac..6defd02fc2 100644
--- a/src/Microsoft.TestPlatform.AdapterUtilities/PublicAPI/PublicAPI.Shipped.txt
+++ b/src/Microsoft.TestPlatform.AdapterUtilities/PublicAPI/PublicAPI.Shipped.txt
@@ -26,8 +26,8 @@ Microsoft.TestPlatform.AdapterUtilities.TestIdProvider.GetHash() -> byte[]!
Microsoft.TestPlatform.AdapterUtilities.TestIdProvider.GetId() -> System.Guid
Microsoft.TestPlatform.AdapterUtilities.TestIdProvider.TestIdProvider() -> void
static Microsoft.TestPlatform.AdapterUtilities.ManagedNameUtilities.ManagedNameHelper.GetManagedName(System.Reflection.MethodBase! method, out string! managedTypeName, out string! managedMethodName) -> void
-static Microsoft.TestPlatform.AdapterUtilities.ManagedNameUtilities.ManagedNameHelper.GetManagedName(System.Reflection.MethodBase! method, out string! managedTypeName, out string! managedMethodName, out string![]! hierarchyValues) -> void
-static Microsoft.TestPlatform.AdapterUtilities.ManagedNameUtilities.ManagedNameHelper.GetManagedHierarchy(System.Reflection.MethodBase! method) -> string![]!
+static Microsoft.TestPlatform.AdapterUtilities.ManagedNameUtilities.ManagedNameHelper.GetManagedName(System.Reflection.MethodBase! method, out string! managedTypeName, out string! managedMethodName, out string?[]! hierarchyValues) -> void
+static Microsoft.TestPlatform.AdapterUtilities.ManagedNameUtilities.ManagedNameHelper.GetManagedHierarchy(System.Reflection.MethodBase! method) -> string?[]!
static Microsoft.TestPlatform.AdapterUtilities.ManagedNameUtilities.ManagedNameHelper.GetMethod(System.Reflection.Assembly! assembly, string! managedTypeName, string! managedMethodName) -> System.Reflection.MethodBase!
static Microsoft.TestPlatform.AdapterUtilities.ManagedNameUtilities.ManagedNameParser.ParseManagedMethodName(string! managedMethodName, out string! methodName, out int arity, out string![]? parameterTypes) -> void
static Microsoft.TestPlatform.AdapterUtilities.ManagedNameUtilities.ManagedNameParser.ParseManagedTypeName(string! managedTypeName, out string! namespaceName, out string! typeName) -> void
diff --git a/test/Microsoft.TestPlatform.AdapterUtilities.UnitTests/ManagedNameUtilities/ManagedNameGeneratorTests.cs b/test/Microsoft.TestPlatform.AdapterUtilities.UnitTests/ManagedNameUtilities/ManagedNameGeneratorTests.cs
new file mode 100644
index 0000000000..01406c4f6f
--- /dev/null
+++ b/test/Microsoft.TestPlatform.AdapterUtilities.UnitTests/ManagedNameUtilities/ManagedNameGeneratorTests.cs
@@ -0,0 +1,126 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+
+namespace Microsoft.TestPlatform.AdapterUtilities.ManagedNameUtilities.UnitTests;
+
+[TestClass]
+public class ManagedNameGeneratorTests
+{
+ [TestMethod]
+ public void Namespaceless_ClassMembers_ShouldNotReportANamespace()
+ {
+ // Arrange
+ var methodBase = typeof(global::NamespacelessClass).GetMethod("Method0")!;
+
+ // Act
+ ManagedNameHelper.GetManagedName(methodBase, out var managedTypeName, out var managedMethodName);
+
+ // Assert
+ Assert.AreEqual("NamespacelessClass", managedTypeName);
+ Assert.AreEqual("Method0", managedMethodName);
+ }
+
+ [TestMethod]
+ public void Namespaceless_RecordMembers_ShouldNotReportANamespace()
+ {
+ // Arrange
+ var methodBase = typeof(global::NamespacelessRecord).GetMethod("Method0")!;
+
+ // Act
+ ManagedNameHelper.GetManagedName(methodBase, out var managedTypeName, out var managedMethodName);
+
+ // Assert
+ Assert.AreEqual("NamespacelessRecord", managedTypeName);
+ Assert.AreEqual("Method0", managedMethodName);
+ }
+
+ [TestMethod]
+ public void Namespaceless_InnerClassMembers_ShouldNotReportANamespace()
+ {
+ // Arrange
+ var methodBase = typeof(global::NamespacelessClass.Inner).GetMethod("Method0")!;
+
+ // Act
+ ManagedNameHelper.GetManagedName(methodBase, out var managedTypeName, out var managedMethodName);
+
+ // Assert
+ Assert.AreEqual("NamespacelessClass+Inner", managedTypeName);
+ Assert.AreEqual("Method0", managedMethodName);
+ }
+
+ [TestMethod]
+ public void Namespaceless_InnerRecordMembers_ShouldNotReportANamespace()
+ {
+ // Arrange
+ var methodBase = typeof(global::NamespacelessRecord.Inner).GetMethod("Method0")!;
+
+ // Act
+ ManagedNameHelper.GetManagedName(methodBase, out var managedTypeName, out var managedMethodName);
+
+ // Assert
+ Assert.AreEqual("NamespacelessRecord+Inner", managedTypeName);
+ Assert.AreEqual("Method0", managedMethodName);
+ }
+
+ [TestMethod]
+ public void Namespaceless_ClassMembers_ShouldNotReportANamespace_InHierarchy()
+ {
+ // Arrange
+ var methodBase = typeof(global::NamespacelessClass).GetMethod("Method0")!;
+
+ // Act
+ ManagedNameHelper.GetManagedName(methodBase, out var managedTypeName, out var managedMethodName, out var hierarchyValues);
+
+ // Assert
+ Assert.AreEqual("NamespacelessClass", managedTypeName);
+ Assert.AreEqual("Method0", managedMethodName);
+ Assert.IsNull(hierarchyValues[HierarchyConstants.Levels.NamespaceIndex]);
+ }
+
+ [TestMethod]
+ public void Namespaceless_RecordMembers_ShouldNotReportANamespace_InHierarch()
+ {
+ // Arrange
+ var methodBase = typeof(global::NamespacelessRecord).GetMethod("Method0")!;
+
+ // Act
+ ManagedNameHelper.GetManagedName(methodBase, out var managedTypeName, out var managedMethodName, out var hierarchyValues);
+
+ // Assert
+ Assert.AreEqual("NamespacelessRecord", managedTypeName);
+ Assert.AreEqual("Method0", managedMethodName);
+ Assert.IsNull(hierarchyValues[HierarchyConstants.Levels.NamespaceIndex]);
+ }
+
+ [TestMethod]
+ public void Namespaceless_InnerClassMembers_ShouldNotReportANamespace_InHierarchy()
+ {
+ // Arrange
+ var methodBase = typeof(global::NamespacelessClass.Inner).GetMethod("Method0")!;
+
+ // Act
+ ManagedNameHelper.GetManagedName(methodBase, out var managedTypeName, out var managedMethodName, out var hierarchyValues);
+
+ // Assert
+ Assert.AreEqual("NamespacelessClass+Inner", managedTypeName);
+ Assert.AreEqual("Method0", managedMethodName);
+ Assert.IsNull(hierarchyValues[HierarchyConstants.Levels.NamespaceIndex]);
+ }
+
+ [TestMethod]
+ public void Namespaceless_InnerRecordMembers_ShouldNotReportANamespace_InHierarchy()
+ {
+ // Arrange
+ var methodBase = typeof(global::NamespacelessRecord.Inner).GetMethod("Method0")!;
+
+ // Act
+ ManagedNameHelper.GetManagedName(methodBase, out var managedTypeName, out var managedMethodName, out var hierarchyValues);
+
+ // Assert
+ Assert.AreEqual("NamespacelessRecord+Inner", managedTypeName);
+ Assert.AreEqual("Method0", managedMethodName);
+ Assert.IsNull(hierarchyValues[HierarchyConstants.Levels.NamespaceIndex]);
+ }
+}
diff --git a/test/Microsoft.TestPlatform.AdapterUtilities.UnitTests/TestClasses.cs b/test/Microsoft.TestPlatform.AdapterUtilities.UnitTests/TestClasses.cs
index 77d0a713ce..44c8f3f1ca 100644
--- a/test/Microsoft.TestPlatform.AdapterUtilities.UnitTests/TestClasses.cs
+++ b/test/Microsoft.TestPlatform.AdapterUtilities.UnitTests/TestClasses.cs
@@ -4,11 +4,11 @@
using System;
using System.Collections.Generic;
-namespace TestClasses;
-
#pragma warning disable IDE0060 // Remove unused parameter
#pragma warning disable CA1822 // Mark members as static
-internal class Outer
+#pragma warning disable IDE0161 // Convert to file-scoped namespace
+
+internal class NamespacelessClass
{
public void Method0() { }
public void Method1(int i) { }
@@ -23,83 +23,118 @@ public void Method3(int i) { }
}
}
-internal class OuterPrime : Outer { }
-
-internal class Outer
+internal record NamespacelessRecord
{
public void Method0() { }
- public void Method1(T t) { }
- public void Method2(U[] u) { }
- public void Method3(T t, U u) { }
+ public void Method1(int i) { }
+ public void Method2(List ls) { }
+ public void Method3(string p, int l) { }
+ internal record Inner
+ {
+ public void Method0() { }
+ public void Method1(int i) { }
+ public void Method2(int i) { }
+ public void Method3(int i) { }
+ }
+}
+
+namespace TestClasses
+{
+ internal class Outer
+ {
+ public void Method0() { }
+ public void Method1(int i) { }
+ public void Method2(List ls) { }
+ public void Method3(string p, int l) { }
+ internal class Inner
+ {
+ public void Method0() { }
+ public void Method1(int i) { }
+ public void Method2(int i) { }
+ public void Method3(int i) { }
+ }
+ }
+
+ internal class OuterPrime : Outer { }
- internal class Inner
+ internal class Outer
{
public void Method0() { }
public void Method1(T t) { }
- public void Method2(V v) { }
- public void Method3(T t, U u, V v) { }
- public void Method4(X x, U u) { }
- public void Method5(List x, U u) { }
+ public void Method2(U[] u) { }
+ public void Method3(T t, U u) { }
- internal class MoreInner
+ internal class Inner
{
- public void Method0(T t, V v, I i, U u) { }
+ public void Method0() { }
+ public void Method1(T t) { }
+ public void Method2(V v) { }
+ public void Method3(T t, U u, V v) { }
+ public void Method4(X x, U u) { }
+ public void Method5(List x, U u) { }
+
+ internal class MoreInner
+ {
+ public void Method0(T t, V v, I i, U u) { }
+ }
}
}
-}
-internal class OuterPrime : Outer { }
+ internal class OuterPrime : Outer { }
-internal class OuterPrime : Outer { }
+ internal class OuterPrime : Outer { }
-internal class OuterString : Outer { }
+ internal class OuterString : Outer { }
-internal interface IImplementation
-{
- void ImplMethod0();
- void ImplMethod1(int i);
-}
+ internal interface IImplementation
+ {
+ void ImplMethod0();
+ void ImplMethod1(int i);
+ }
-internal class Impl : IImplementation
-{
- void IImplementation.ImplMethod0() { }
- void IImplementation.ImplMethod1(int i) { }
-}
+ internal class Impl : IImplementation
+ {
+ void IImplementation.ImplMethod0() { }
+ void IImplementation.ImplMethod1(int i) { }
+ }
-internal interface IImplementation
-{
- void ImplMethod0();
- void ImplMethod1(T t);
- void ImplMethod2(T t, U u, string s);
-}
+ internal interface IImplementation
+ {
+ void ImplMethod0();
+ void ImplMethod1(T t);
+ void ImplMethod2(T t, U u, string s);
+ }
-internal class Impl : IImplementation
-{
- void IImplementation.ImplMethod0() { }
- void IImplementation.ImplMethod1(T t) { }
- void IImplementation.ImplMethod2(T t, U u, string s) { }
-}
+ internal class Impl : IImplementation
+ {
+ void IImplementation.ImplMethod0() { }
+ void IImplementation.ImplMethod1(T t) { }
+ void IImplementation.ImplMethod2(T t, U u, string s) { }
+ }
-internal class Overloads
-{
- public void Overload0() { }
- public void Overload0(int i) { }
- public void Overload0(int i, Overloads c) { }
- public unsafe void Overload0(int* p) { }
- public void Overload0(dynamic d) { }
- public void Overload0(U u) { }
- public void Overload0() { }
- public void Overload0() { }
- public void Overload0(U[] u) { }
- public void Overload0(U[][] u) { }
- public void Overload0(U[,] u) { }
- public void Overload0(U[,,] u) { }
- public void Overload0(List l) { }
- public void Overload0(List l) { }
- public void Overload0(Tuple t0, Tuple t1) { }
- public void Overload0(Tuple> t0) { }
- public void Overload0(Tuple, Tuple> t) { }
- public void Overload0(Tuple.Inner>> t) { }
+ internal class Overloads
+ {
+ public void Overload0() { }
+ public void Overload0(int i) { }
+ public void Overload0(int i, Overloads c) { }
+ public unsafe void Overload0(int* p) { }
+ public void Overload0(dynamic d) { }
+ public void Overload0(U u) { }
+ public void Overload0() { }
+ public void Overload0() { }
+ public void Overload0(U[] u) { }
+ public void Overload0(U[][] u) { }
+ public void Overload0(U[,] u) { }
+ public void Overload0(U[,,] u) { }
+ public void Overload0(List l) { }
+ public void Overload0(List l) { }
+ public void Overload0(Tuple t0, Tuple t1) { }
+ public void Overload0(Tuple> t0) { }
+ public void Overload0(Tuple, Tuple> t) { }
+ public void Overload0(Tuple.Inner>> t) { }
+ }
}
+
+#pragma warning restore IDE0161 // Convert to file-scoped namespace
#pragma warning restore IDE0060 // Remove unused parameter
#pragma warning restore CA1822 // Mark members as static
diff --git a/test/TestAssets/CILProject/CILProject.proj b/test/TestAssets/CILProject/CILProject.proj
index 9d57990289..ec8caa12cf 100644
--- a/test/TestAssets/CILProject/CILProject.proj
+++ b/test/TestAssets/CILProject/CILProject.proj
@@ -10,7 +10,7 @@
- net462
+ $(NetFrameworkMinimum)
bin\$(Configuration)
true
false