Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix ManagedNameHelper to support namespaceless methods. #4003

Merged
merged 1 commit into from Sep 13, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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
Haplois marked this conversation as resolved.
Show resolved Hide resolved
{
[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]);
}
}
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