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

ManagedNames implementation refactored. #766

Merged
merged 1 commit into from
Feb 4, 2021
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion scripts/build/TestFx.Versions.targets
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<TestPlatformVersion Condition=" '$(TestPlatformVersion)' == '' ">16.9.0-preview-20210129-05</TestPlatformVersion>
<TestPlatformVersion Condition=" '$(TestPlatformVersion)' == '' ">16.10.0-preview-20210204-01</TestPlatformVersion>
<MinimumVisualStudioVersion>11.0</MinimumVisualStudioVersion>
</PropertyGroup>
</Project>
1 change: 1 addition & 0 deletions src/Adapter/MSTest.CoreAdapter/Discovery/TypeEnumerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ internal Collection<UnitTestElement> GetTests(ICollection<string> warnings)
/// <returns> Returns a UnitTestElement.</returns>
internal UnitTestElement GetTestFromMethod(MethodInfo method, bool isDeclaredInTestTypeAssembly, ICollection<string> warnings)
{
// null if the current instance represents a generic type parameter.
Debug.Assert(this.type.AssemblyQualifiedName != null, "AssemblyQualifiedName for method is null.");
Haplois marked this conversation as resolved.
Show resolved Hide resolved

// This allows void returning async test method to be valid test method. Though they will be executed similar to non-async test method.
Expand Down
13 changes: 12 additions & 1 deletion src/Adapter/MSTest.CoreAdapter/Execution/TestAssemblyInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,13 @@ namespace Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Reflection;

using Extensions;

using Microsoft.VisualStudio.TestTools.UnitTesting;

using ObjectModel;

using UnitTestOutcome = Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestOutcome;

/// <summary>
Expand All @@ -25,9 +29,11 @@ public class TestAssemblyInfo
/// <summary>
/// Initializes a new instance of the <see cref="TestAssemblyInfo"/> class.
/// </summary>
internal TestAssemblyInfo()
/// <param name="assembly">Sets the <see cref="Assembly"/> this class is representing. </param>
internal TestAssemblyInfo(Assembly assembly)
{
this.assemblyInfoExecuteSyncObject = new object();
this.Assembly = assembly;
}

/// <summary>
Expand Down Expand Up @@ -101,6 +107,11 @@ public bool HasExecutableCleanupMethod
}
}

/// <summary>
/// Gets the <see cref="Assembly"/> this class represents.
/// </summary>
internal Assembly Assembly { get; }

/// <summary>
/// Runs assembly initialize method.
/// </summary>
Expand Down
53 changes: 43 additions & 10 deletions src/Adapter/MSTest.CoreAdapter/Execution/TypeCache.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ namespace Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution
using System.Reflection;
using System.Security;

using Microsoft.TestPlatform.AdapterUtilities.ManagedNameUtilities;
using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Discovery;
using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Extensions;
using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Helpers;
Expand Down Expand Up @@ -332,7 +333,7 @@ private TestAssemblyInfo GetAssemblyInfo(Type type)
var assemblyInitializeType = typeof(AssemblyInitializeAttribute);
var assemblyCleanupType = typeof(AssemblyCleanupAttribute);

assemblyInfo = new TestAssemblyInfo();
assemblyInfo = new TestAssemblyInfo(assembly);

var types = new AssemblyEnumerator().GetTypes(assembly, assembly.FullName, null);

Expand Down Expand Up @@ -635,9 +636,49 @@ private TestMethodAttribute GetTestMethodAttribute(MethodInfo methodInfo, TestCl
/// <returns> The <see cref="MethodInfo"/>. </returns>
private MethodInfo GetMethodInfoForTestMethod(TestMethod testMethod, TestClassInfo testClassInfo)
Haplois marked this conversation as resolved.
Show resolved Hide resolved
{
var methodsInClass = testClassInfo.ClassType.GetRuntimeMethods().ToArray();
var testMethodInfo = testMethod.HasManagedMethodAndTypeProperties
? this.GetMethodInfoUsingManagedNameHelper(testMethod, testClassInfo)
: this.GetMethodInfoUsingRuntimeMethods(testMethod, testClassInfo);

// if correct method is not found, throw appropriate
// exception about what is wrong.
if (testMethodInfo == null)
{
var errorMessage = string.Format(CultureInfo.CurrentCulture, Resource.UTA_MethodDoesNotExists, testMethod.FullClassName, testMethod.Name);
throw new TypeInspectionException(errorMessage);
}

return testMethodInfo;
}

private MethodInfo GetMethodInfoUsingManagedNameHelper(TestMethod testMethod, TestClassInfo testClassInfo)
{
MethodInfo testMethodInfo = null;
var methodBase = ManagedNameHelper.GetMethod(testClassInfo.Parent.Assembly, testMethod.ManagedTypeName, testMethod.ManagedMethodName);

if (methodBase is MethodInfo mi)
{
testMethodInfo = mi;
}
else if (methodBase != null)
{
var parameters = methodBase.GetParameters().Select(i => i.ParameterType).ToArray();
testMethodInfo = methodBase.DeclaringType.GetRuntimeMethod(methodBase.Name, parameters);
}

testMethodInfo = testMethodInfo?.HasCorrectTestMethodSignature(true) ?? false
? testMethodInfo
: null;

return testMethodInfo;
}

private MethodInfo GetMethodInfoUsingRuntimeMethods(TestMethod testMethod, TestClassInfo testClassInfo)
{
MethodInfo testMethodInfo;

var methodsInClass = testClassInfo.ClassType.GetRuntimeMethods().ToArray();

if (testMethod.DeclaringClassFullName != null)
{
// Only find methods that match the given declaring name.
Expand All @@ -657,14 +698,6 @@ private MethodInfo GetMethodInfoForTestMethod(TestMethod testMethod, TestClassIn
.OrderByDescending(method => method.DeclaringType.FullName.Equals(className)).FirstOrDefault();
}

// if correct method is not found, throw appropriate
// exception about what is wrong.
if (testMethodInfo == null)
{
var errorMessage = string.Format(CultureInfo.CurrentCulture, Resource.UTA_MethodDoesNotExists, testMethod.FullClassName, testMethod.Name);
throw new TypeInspectionException(errorMessage);
}

return testMethodInfo;
}

Expand Down
20 changes: 14 additions & 6 deletions src/Adapter/MSTest.CoreAdapter/Extensions/TestCaseExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,20 @@

namespace Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Extensions
{
using Microsoft.TestPlatform.AdapterUtilities;
using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel;
using Microsoft.VisualStudio.TestPlatform.ObjectModel;

using Constants = Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Constants;
using ManagedNameUtilities = Microsoft.TestPlatform.AdapterUtilities.ManagedNameUtilities;

/// <summary>
/// Extension Methods for TestCase Class
/// </summary>
internal static class TestCaseExtensions
{
internal static readonly TestProperty ManagedTypeProperty = TestProperty.Register(
id: ManagedNameUtilities.Contants.ManagedTypePropertyId,
label: ManagedNameUtilities.Contants.ManagedTypeLabel,
id: ManagedNameConstants.ManagedTypePropertyId,
label: ManagedNameConstants.ManagedTypeLabel,
category: string.Empty,
description: string.Empty,
valueType: typeof(string),
Expand All @@ -25,8 +25,8 @@ internal static class TestCaseExtensions
owner: typeof(TestCase));

internal static readonly TestProperty ManagedMethodProperty = TestProperty.Register(
id: ManagedNameUtilities.Contants.ManagedMethodPropertyId,
label: ManagedNameUtilities.Contants.ManagedMethodLabel,
id: ManagedNameConstants.ManagedMethodPropertyId,
label: ManagedNameConstants.ManagedMethodLabel,
category: string.Empty,
description: string.Empty,
valueType: typeof(string),
Expand All @@ -53,7 +53,15 @@ internal static UnitTestElement ToUnitTestElement(this TestCase testCase, string
? fullyQualifiedName.Remove(0, $"{testClassName}.".Length)
: fullyQualifiedName;

TestMethod testMethod = new TestMethod(name, testClassName, source, isAsync);
TestMethod testMethod;
if (testCase.ContainsManagedMethodAndType())
{
testMethod = new TestMethod(testCase.GetManagedType(), testCase.GetManagedMethod(), name, testClassName, source, isAsync);
}
else
{
testMethod = new TestMethod(name, testClassName, source, isAsync);
}

if (declaringClassName != null && declaringClassName != testClassName)
{
Expand Down
3 changes: 2 additions & 1 deletion src/Adapter/MSTest.CoreAdapter/Friends.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@
using System.Runtime.CompilerServices;

[assembly: InternalsVisibleTo("Microsoft.VisualStudio.TestPlatform.MSTestAdapter.UnitTests, PublicKey=002400000480000094000000060200000024000052534131000400000100010007d1fa57c4aed9f0a32e84aa0faefd0de9e8fd6aec8f87fb03766c834c99921eb23be79ad9d5dcc1dd9ad236132102900b723cf980957fc4e177108fc607774f29e8320e92ea05ece4e821c0a5efe8f1645c4c0c93c1ab99285d622caa652c1dfad63d745d6f2de5f17e5eaf0fc4963d261c8a12436518206dc093344d5ad293")]
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")]
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")]
[assembly: InternalsVisibleTo("MSTestAdapter.Smoke.E2ETests, PublicKey=002400000480000094000000060200000024000052534131000400000100010007d1fa57c4aed9f0a32e84aa0faefd0de9e8fd6aec8f87fb03766c834c99921eb23be79ad9d5dcc1dd9ad236132102900b723cf980957fc4e177108fc607774f29e8320e92ea05ece4e821c0a5efe8f1645c4c0c93c1ab99285d622caa652c1dfad63d745d6f2de5f17e5eaf0fc4963d261c8a12436518206dc093344d5ad293")]
1 change: 1 addition & 0 deletions src/Adapter/MSTest.CoreAdapter/Helpers/ReflectHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ namespace Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Helpers
using System.Linq;
using System.Reflection;
using System.Security;

using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution;
using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel;
using Microsoft.VisualStudio.TestPlatform.ObjectModel;
Expand Down
30 changes: 21 additions & 9 deletions src/Adapter/MSTest.CoreAdapter/ObjectModel/TestMethod.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ public TestMethod(string name, string fullClassName, string assemblyName, bool i
this.IsAsync = isAsync;
}

public TestMethod(MethodBase method, string name, string fullClassName, string assemblyName, bool isAsync)
internal TestMethod(MethodBase method, string name, string fullClassName, string assemblyName, bool isAsync)
: this(name, fullClassName, assemblyName, isAsync)
{
if (method == null)
Expand All @@ -57,8 +57,20 @@ public TestMethod(MethodBase method, string name, string fullClassName, string a

ManagedNameHelper.GetManagedName(method, out var managedType, out var managedMethod);

this.ManagedType = managedType;
this.ManagedMethod = managedMethod;
// ManagedNameHelpers currently does not support spaces in method names.
// If there are spaces in the method name, we'll use the legacy way to find the method.
if (!managedMethod.Contains(" "))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need this check given HasManagedMethodAndType already has a similar check and the consumers already check that today?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It’s is a temporary workaround for this issue. microsoft/vstest#2733

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah, could we add that comment to the code?

{
this.ManagedTypeName = managedType;
this.ManagedMethodName = managedMethod;
}
}

internal TestMethod(string managedTypeName, string managedMethodName, string name, string fullClassName, string assemblyName, bool isAsync)
Haplois marked this conversation as resolved.
Show resolved Hide resolved
: this(name, fullClassName, assemblyName, isAsync)
{
this.ManagedTypeName = managedTypeName;
this.ManagedMethodName = managedMethodName;
}

/// <summary>
Expand Down Expand Up @@ -120,13 +132,13 @@ public string DeclaringClassFullName
/// </summary>
public bool IsAsync { get; private set; }

public string ManagedType { get; }
/// <inheritdoc />
public string ManagedTypeName { get; }

public string ManagedMethod { get; }
/// <inheritdoc />
public string ManagedMethodName { get; }

/// <summary>
/// Gets a value indicating whether both <see cref="ManagedType"/> and <see cref="ManagedMethod"/> are not null or whitespace.
/// </summary>
public bool HasManagedMethodAndType => !string.IsNullOrWhiteSpace(this.ManagedType) && !string.IsNullOrWhiteSpace(this.ManagedMethod);
/// <inheritdoc />
public bool HasManagedMethodAndTypeProperties => !string.IsNullOrWhiteSpace(this.ManagedTypeName) && !string.IsNullOrWhiteSpace(this.ManagedMethodName);
}
}
40 changes: 27 additions & 13 deletions src/Adapter/MSTest.CoreAdapter/ObjectModel/UnitTestElement.cs
Original file line number Diff line number Diff line change
Expand Up @@ -109,20 +109,22 @@ public UnitTestElement(TestMethod testMethod)
/// <returns> An instance of <see cref="TestCase"/>. </returns>
internal TestCase ToTestCase()
{
var fullName = string.Format(
CultureInfo.InvariantCulture,
"{0}.{1}",
this.TestMethod.FullClassName,
this.TestMethod.Name);
string fullName = this.TestMethod.HasManagedMethodAndTypeProperties
? string.Format(CultureInfo.InvariantCulture, "{0}.{1}", this.TestMethod.ManagedTypeName, this.TestMethod.ManagedMethodName)
: string.Format(CultureInfo.InvariantCulture, "{0}.{1}", this.TestMethod.FullClassName, this.TestMethod.Name);

TestCase testCase = new TestCase(fullName, TestAdapter.Constants.ExecutorUri, this.TestMethod.AssemblyName);
testCase.DisplayName = this.GetDisplayName();

testCase.DisplayName = string.IsNullOrEmpty(this.DisplayName) ? this.TestMethod.Name : this.DisplayName;
testCase.SetPropertyValue(TestAdapter.Constants.TestClassNameProperty, this.TestMethod.FullClassName);
if (this.TestMethod.HasManagedMethodAndType)
if (this.TestMethod.HasManagedMethodAndTypeProperties)
{
testCase.SetPropertyValue(TestCaseExtensions.ManagedTypeProperty, this.TestMethod.ManagedType);
testCase.SetPropertyValue(TestCaseExtensions.ManagedMethodProperty, this.TestMethod.ManagedMethod);
testCase.SetPropertyValue(TestCaseExtensions.ManagedTypeProperty, this.TestMethod.ManagedTypeName);
testCase.SetPropertyValue(TestCaseExtensions.ManagedMethodProperty, this.TestMethod.ManagedMethodName);
testCase.SetPropertyValue(TestAdapter.Constants.TestClassNameProperty, this.TestMethod.ManagedTypeName);
Haplois marked this conversation as resolved.
Show resolved Hide resolved
}
else
{
testCase.SetPropertyValue(TestAdapter.Constants.TestClassNameProperty, this.TestMethod.FullClassName);
}

// Set declaring type if present so the correct method info can be retrieved
Expand Down Expand Up @@ -183,12 +185,24 @@ internal TestCase ToTestCase()
// Set the Do not parallelize state if present
if (this.DoNotParallelize)
{
testCase.SetPropertyValue(
TestAdapter.Constants.DoNotParallelizeProperty,
this.DoNotParallelize);
testCase.SetPropertyValue(TestAdapter.Constants.DoNotParallelizeProperty, this.DoNotParallelize);
}

return testCase;
}

private string GetDisplayName()
{
if (string.IsNullOrWhiteSpace(this.DisplayName))
{
return string.IsNullOrWhiteSpace(this.TestMethod.ManagedMethodName)
? this.TestMethod.Name
: this.TestMethod.ManagedMethodName;
}
else
{
return this.DisplayName;
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -501,8 +501,8 @@ private string GetStringPropertyValue(string propertyName)
private void InitializeProperties()
{
this.properties[TestContextPropertyStrings.FullyQualifiedTestClassName] = this.testMethod.FullClassName;
this.properties[TestContextPropertyStrings.ManagedType] = this.testMethod.ManagedType;
this.properties[TestContextPropertyStrings.ManagedMethod] = this.testMethod.ManagedMethod;
this.properties[TestContextPropertyStrings.ManagedType] = this.testMethod.ManagedTypeName;
this.properties[TestContextPropertyStrings.ManagedMethod] = this.testMethod.ManagedMethodName;
this.properties[TestContextPropertyStrings.TestName] = this.testMethod.Name;
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/Adapter/PlatformServices.Desktop/packages.config
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="MicroBuild.Core" version="0.2.0" targetFramework="net451" developmentDependency="true" />
<package id="Microsoft.TestPlatform.ObjectModel" version="16.9.0-preview-20210129-05" targetFramework="net45" />
<package id="Microsoft.TestPlatform.ObjectModel" version="16.10.0-preview-20210204-01" targetFramework="net45" />
<package id="NuGet.Frameworks" version="5.0.0" targetFramework="net45" />
<package id="StyleCop.Analyzers" version="1.0.0" targetFramework="net45" developmentDependency="true" />
<package id="System.Collections.Immutable" version="1.5.0" targetFramework="net45" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,14 +40,19 @@ public interface ITestMethod
/// <example>
/// <code>NamespaceA.NamespaceB.ClassName`1+InnerClass`2</code>
/// </example>
string ManagedType { get; }
string ManagedTypeName { get; }

/// <summary>
/// Gets the fully specified method name metadata format.
/// </summary>
/// <example>
/// <code>MethodName`2(ParamTypeA,ParamTypeB,…)</code>
/// </example>
string ManagedMethod { get; }
string ManagedMethodName { get; }

/// <summary>
/// Gets a value indicating whether both <see cref="ManagedTypeName"/> and <see cref="ManagedMethodName"/> are not null or whitespace.
/// </summary>
bool HasManagedMethodAndTypeProperties { get; }
}
}
2 changes: 1 addition & 1 deletion src/Adapter/PlatformServices.Interface/packages.config
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="MicroBuild.Core" version="0.2.0" targetFramework="portable45-net45+win8+wp8+wpa81" developmentDependency="true" />
<package id="Microsoft.TestPlatform.ObjectModel" version="16.9.0-preview-20210129-05" targetFramework="portable45-net45+win8+wp8+wpa81" />
<package id="Microsoft.TestPlatform.ObjectModel" version="16.10.0-preview-20210204-01" targetFramework="portable45-net45+win8+wp8+wpa81" />
<package id="StyleCop.Analyzers" version="1.0.0" targetFramework="portable45-net45+win8+wp8+wpa81" developmentDependency="true" />
<package id="System.Collections" version="4.3.0" targetFramework="portable45-net45+win8+wp8+wpa81" />
<package id="System.ComponentModel" version="4.3.0" targetFramework="portable45-net45+win8+wp8+wpa81" />
Expand Down
Loading