Skip to content

Commit

Permalink
Fix ManagedNameHelper to support namespaceless methods.
Browse files Browse the repository at this point in the history
  • Loading branch information
Haplois committed Sep 12, 2022
1 parent 1d9a342 commit b14ac5d
Show file tree
Hide file tree
Showing 5 changed files with 249 additions and 73 deletions.
Expand Up @@ -78,7 +78,7 @@ public static void GetManagedName(MethodBase method, out string managedTypeName,
/// More information about <paramref name="managedTypeName"/> and <paramref name="managedMethodName"/> can be found in
/// <see href="https://github.com/microsoft/vstest-docs/blob/main/RFCs/0017-Managed-TestCase-Properties.md">the RFC</see>.
/// </remarks>
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);
Expand All @@ -102,14 +102,14 @@ public static void GetManagedName(MethodBase method, out string managedTypeName,
/// <returns>
/// The hierarchy values.
/// </returns>
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));

Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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)
Expand Down
Expand Up @@ -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
@@ -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]);
}
}
159 changes: 97 additions & 62 deletions test/Microsoft.TestPlatform.AdapterUtilities.UnitTests/TestClasses.cs
Expand Up @@ -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) { }
Expand All @@ -23,83 +23,118 @@ internal class Inner
}
}

internal class OuterPrime : Outer { }

internal class Outer<T>
internal record NamespacelessRecord
{
public void Method0() { }
public void Method1(T t) { }
public void Method2<U>(U[] u) { }
public void Method3<U>(T t, U u) { }
public void Method1(int i) { }
public void Method2(List<string> ls) { }
public void Method3(string p, int l) { }
internal record Inner
{
public void Method0() { }
public void Method1(int i) { }
public void Method2<U>(int i) { }
public void Method3<U, T>(int i) { }
}
}

namespace TestClasses
{
internal class Outer
{
public void Method0() { }
public void Method1(int i) { }
public void Method2(List<string> ls) { }
public void Method3(string p, int l) { }
internal class Inner
{
public void Method0() { }
public void Method1(int i) { }
public void Method2<U>(int i) { }
public void Method3<U, T>(int i) { }
}
}

internal class OuterPrime : Outer { }

internal class Inner<V>
internal class Outer<T>
{
public void Method0() { }
public void Method1(T t) { }
public void Method2(V v) { }
public void Method3<U>(T t, U u, V v) { }
public void Method4<U, X>(X x, U u) { }
public void Method5<U, X>(List<X> x, U u) { }
public void Method2<U>(U[] u) { }
public void Method3<U>(T t, U u) { }

internal class MoreInner<I>
internal class Inner<V>
{
public void Method0<U>(T t, V v, I i, U u) { }
public void Method0() { }
public void Method1(T t) { }
public void Method2(V v) { }
public void Method3<U>(T t, U u, V v) { }
public void Method4<U, X>(X x, U u) { }
public void Method5<U, X>(List<X> x, U u) { }

internal class MoreInner<I>
{
public void Method0<U>(T t, V v, I i, U u) { }
}
}
}
}

internal class OuterPrime<Z> : Outer<Z> { }
internal class OuterPrime<Z> : Outer<Z> { }

internal class OuterPrime<Y, Z> : Outer<Z> { }
internal class OuterPrime<Y, Z> : Outer<Z> { }

internal class OuterString : Outer<string> { }
internal class OuterString : Outer<string> { }

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<T>
{
void ImplMethod0();
void ImplMethod1(T t);
void ImplMethod2<U>(T t, U u, string s);
}
internal interface IImplementation<T>
{
void ImplMethod0();
void ImplMethod1(T t);
void ImplMethod2<U>(T t, U u, string s);
}

internal class Impl<T> : IImplementation<T>
{
void IImplementation<T>.ImplMethod0() { }
void IImplementation<T>.ImplMethod1(T t) { }
void IImplementation<T>.ImplMethod2<U>(T t, U u, string s) { }
}
internal class Impl<T> : IImplementation<T>
{
void IImplementation<T>.ImplMethod0() { }
void IImplementation<T>.ImplMethod1(T t) { }
void IImplementation<T>.ImplMethod2<U>(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 u) { }
public void Overload0<U>() { }
public void Overload0<U, T>() { }
public void Overload0<U>(U[] u) { }
public void Overload0<U>(U[][] u) { }
public void Overload0<U>(U[,] u) { }
public void Overload0<U>(U[,,] u) { }
public void Overload0<U>(List<int> l) { }
public void Overload0<U>(List<U> l) { }
public void Overload0<U, V>(Tuple<U, V> t0, Tuple<V, U> t1) { }
public void Overload0(Tuple<Tuple<string[,], int>> t0) { }
public void Overload0(Tuple<Tuple<string>, Tuple<int>> t) { }
public void Overload0<U>(Tuple<Tuple<Outer<U>.Inner<U>>> 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 u) { }
public void Overload0<U>() { }
public void Overload0<U, T>() { }
public void Overload0<U>(U[] u) { }
public void Overload0<U>(U[][] u) { }
public void Overload0<U>(U[,] u) { }
public void Overload0<U>(U[,,] u) { }
public void Overload0<U>(List<int> l) { }
public void Overload0<U>(List<U> l) { }
public void Overload0<U, V>(Tuple<U, V> t0, Tuple<V, U> t1) { }
public void Overload0(Tuple<Tuple<string[,], int>> t0) { }
public void Overload0(Tuple<Tuple<string>, Tuple<int>> t) { }
public void Overload0<U>(Tuple<Tuple<Outer<U>.Inner<U>>> 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

0 comments on commit b14ac5d

Please sign in to comment.