diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Services/ReflectionOperations.cs b/src/Adapter/MSTestAdapter.PlatformServices/Services/ReflectionOperations.cs
index 6f0a33458f..37fe81d602 100644
--- a/src/Adapter/MSTestAdapter.PlatformServices/Services/ReflectionOperations.cs
+++ b/src/Adapter/MSTestAdapter.PlatformServices/Services/ReflectionOperations.cs
@@ -2,9 +2,6 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Interface;
-#if NETFRAMEWORK
-using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Utilities;
-#endif
namespace Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices;
@@ -24,10 +21,10 @@ internal sealed class ReflectionOperations : IReflectionOperations
[return: NotNullIfNotNull(nameof(memberInfo))]
public object[]? GetCustomAttributes(MemberInfo memberInfo)
#if NETFRAMEWORK
- => [.. ReflectionUtility.GetCustomAttributes(memberInfo)];
+ => [.. GetCustomAttributesCore(memberInfo, type: null)];
#else
{
- object[] attributes = memberInfo.GetCustomAttributes(typeof(Attribute), inherit: true);
+ object[] attributes = memberInfo.GetCustomAttributes(inherit: true);
// Ensures that when the return of this method is used here:
// https://github.com/microsoft/testfx/blob/e101a9d48773cc935c7b536d25d378d9a3211fee/src/Adapter/MSTest.TestAdapter/Helpers/ReflectHelper.cs#L461
@@ -47,7 +44,7 @@ internal sealed class ReflectionOperations : IReflectionOperations
[return: NotNullIfNotNull(nameof(memberInfo))]
public object[]? GetCustomAttributes(MemberInfo memberInfo, Type type) =>
#if NETFRAMEWORK
- [.. ReflectionUtility.GetCustomAttributesCore(memberInfo, type)];
+ [.. GetCustomAttributesCore(memberInfo, type)];
#else
memberInfo.GetCustomAttributes(type, inherit: true);
#endif
@@ -60,7 +57,7 @@ internal sealed class ReflectionOperations : IReflectionOperations
/// The list of attributes of the given type on the member. Empty list if none found.
public object[] GetCustomAttributes(Assembly assembly, Type type) =>
#if NETFRAMEWORK
- ReflectionUtility.GetCustomAttributes(assembly, type).ToArray();
+ GetCustomAttributesForAssembly(assembly, type).ToArray();
#else
assembly.GetCustomAttributes(type, inherit: true);
#endif
@@ -106,4 +103,254 @@ public MethodInfo[] GetRuntimeMethods(Type type)
#pragma warning restore IL2026 // Members attributed with RequiresUnreferencedCode may break when trimming
#pragma warning restore IL2067 // 'target parameter' argument does not satisfy 'DynamicallyAccessedMembersAttribute' in call to 'target method'.
#pragma warning restore IL2057 // Unrecognized value passed to the typeName parameter of 'System.Type.GetType(String)'
+
+#if NETFRAMEWORK
+ ///
+ /// Get custom attributes on a member for both normal and reflection only load.
+ ///
+ /// Member for which attributes needs to be retrieved.
+ /// Type of attribute to retrieve.
+ /// All attributes of give type on member.
+#pragma warning disable CA1859 // Use concrete types when possible for improved performance
+ private static IReadOnlyList GetCustomAttributesCore(MemberInfo memberInfo, Type? type)
+#pragma warning restore CA1859
+ {
+ bool shouldGetAllAttributes = type is null;
+
+ if (!IsReflectionOnlyLoad(memberInfo))
+ {
+ return shouldGetAllAttributes ? memberInfo.GetCustomAttributes(inherit: true) : memberInfo.GetCustomAttributes(type, inherit: true);
+ }
+ else
+ {
+ List nonUniqueAttributes = [];
+ Dictionary uniqueAttributes = [];
+
+ int inheritanceThreshold = 10;
+ int inheritanceLevel = 0;
+
+ if (memberInfo.MemberType == MemberTypes.TypeInfo)
+ {
+ // This code is based on the code for fetching CustomAttributes in System.Reflection.CustomAttribute(RuntimeType type, RuntimeType caType, bool inherit)
+ var tempTypeInfo = memberInfo as TypeInfo;
+
+ do
+ {
+ IList attributes = CustomAttributeData.GetCustomAttributes(tempTypeInfo);
+ AddNewAttributes(
+ attributes,
+ shouldGetAllAttributes,
+ type!,
+ uniqueAttributes,
+ nonUniqueAttributes);
+ tempTypeInfo = tempTypeInfo!.BaseType?.GetTypeInfo();
+ inheritanceLevel++;
+ }
+ while (tempTypeInfo is not null && tempTypeInfo != typeof(object).GetTypeInfo()
+ && inheritanceLevel < inheritanceThreshold);
+ }
+ else if (memberInfo.MemberType == MemberTypes.Method)
+ {
+ // This code is based on the code for fetching CustomAttributes in System.Reflection.CustomAttribute(RuntimeMethodInfo method, RuntimeType caType, bool inherit).
+ var tempMethodInfo = memberInfo as MethodInfo;
+
+ do
+ {
+ IList attributes = CustomAttributeData.GetCustomAttributes(tempMethodInfo);
+ AddNewAttributes(
+ attributes,
+ shouldGetAllAttributes,
+ type!,
+ uniqueAttributes,
+ nonUniqueAttributes);
+ MethodInfo? baseDefinition = tempMethodInfo!.GetBaseDefinition();
+
+ if (baseDefinition is not null
+ && string.Equals(
+ string.Concat(tempMethodInfo.DeclaringType.FullName, tempMethodInfo.Name),
+ string.Concat(baseDefinition.DeclaringType.FullName, baseDefinition.Name), StringComparison.Ordinal))
+ {
+ break;
+ }
+
+ tempMethodInfo = baseDefinition;
+ inheritanceLevel++;
+ }
+ while (tempMethodInfo is not null && inheritanceLevel < inheritanceThreshold);
+ }
+ else
+ {
+ // Ideally we should not be reaching here. We only query for attributes on types/methods currently.
+ // Return the attributes that CustomAttributeData returns in this cases not considering inheritance.
+ IList firstLevelAttributes =
+ CustomAttributeData.GetCustomAttributes(memberInfo);
+ AddNewAttributes(firstLevelAttributes, shouldGetAllAttributes, type!, uniqueAttributes, nonUniqueAttributes);
+ }
+
+ nonUniqueAttributes.AddRange(uniqueAttributes.Values);
+ return nonUniqueAttributes;
+ }
+ }
+
+ private static List GetCustomAttributesForAssembly(Assembly assembly, Type type)
+ {
+ if (!assembly.ReflectionOnly)
+ {
+ return [.. assembly.GetCustomAttributes(type)];
+ }
+
+ List customAttributes = [.. CustomAttributeData.GetCustomAttributes(assembly)];
+
+ List attributesArray = [];
+
+ foreach (CustomAttributeData attribute in customAttributes)
+ {
+ if (!IsTypeInheriting(attribute.Constructor.DeclaringType, type)
+ && !attribute.Constructor.DeclaringType.AssemblyQualifiedName.Equals(
+ type.AssemblyQualifiedName, StringComparison.Ordinal))
+ {
+ continue;
+ }
+
+ Attribute? attributeInstance = CreateAttributeInstance(attribute);
+ if (attributeInstance is not null)
+ {
+ attributesArray.Add(attributeInstance);
+ }
+ }
+
+ return attributesArray;
+ }
+
+ ///
+ /// Create instance of the attribute for reflection only load.
+ ///
+ /// The attribute data.
+ /// An attribute.
+ private static Attribute? CreateAttributeInstance(CustomAttributeData attributeData)
+ {
+ object? attribute = null;
+ try
+ {
+ // Create instance of attribute. For some case, constructor param is returned as ReadOnlyCollection
+ // instead of array. So convert it to array else constructor invoke will fail.
+ var attributeType = Type.GetType(attributeData.Constructor.DeclaringType.AssemblyQualifiedName);
+
+ List constructorParameters = [];
+ List constructorArguments = [];
+ foreach (CustomAttributeTypedArgument parameter in attributeData.ConstructorArguments)
+ {
+ var parameterType = Type.GetType(parameter.ArgumentType.AssemblyQualifiedName);
+ constructorParameters.Add(parameterType);
+ if (!parameterType.IsArray
+ || parameter.Value is not IEnumerable enumerable)
+ {
+ constructorArguments.Add(parameter.Value);
+ continue;
+ }
+
+ ArrayList list = [];
+ foreach (object? item in enumerable)
+ {
+ if (item is CustomAttributeTypedArgument argument)
+ {
+ list.Add(argument.Value);
+ }
+ else
+ {
+ list.Add(item);
+ }
+ }
+
+ constructorArguments.Add(list.ToArray(parameterType.GetElementType()));
+ }
+
+ ConstructorInfo constructor = attributeType.GetConstructor([.. constructorParameters]);
+ attribute = constructor.Invoke([.. constructorArguments]);
+
+ foreach (CustomAttributeNamedArgument namedArgument in attributeData.NamedArguments)
+ {
+ attributeType.GetProperty(namedArgument.MemberInfo.Name).SetValue(attribute, namedArgument.TypedValue.Value, null);
+ }
+ }
+
+ // If not able to create instance of attribute ignore attribute. (May happen for custom user defined attributes).
+ catch (BadImageFormatException)
+ {
+ }
+ catch (FileLoadException)
+ {
+ }
+ catch (TypeLoadException)
+ {
+ }
+
+ return attribute as Attribute;
+ }
+
+ private static void AddNewAttributes(
+ IList customAttributes,
+ bool shouldGetAllAttributes,
+ Type type,
+ Dictionary uniqueAttributes,
+ List nonUniqueAttributes)
+ {
+ foreach (CustomAttributeData attribute in customAttributes)
+ {
+ if (!shouldGetAllAttributes
+ && !IsTypeInheriting(attribute.Constructor.DeclaringType, type)
+ && !attribute.Constructor.DeclaringType.AssemblyQualifiedName.Equals(
+ type.AssemblyQualifiedName, StringComparison.Ordinal))
+ {
+ continue;
+ }
+
+ Attribute? attributeInstance = CreateAttributeInstance(attribute);
+ if (attributeInstance is null)
+ {
+ continue;
+ }
+
+ Type attributeType = attributeInstance.GetType();
+ IReadOnlyList attributeUsageAttributes = GetCustomAttributesCore(
+ attributeType,
+ typeof(AttributeUsageAttribute));
+ if (attributeUsageAttributes.Count > 0
+ && attributeUsageAttributes[0] is AttributeUsageAttribute { AllowMultiple: false })
+ {
+ if (!uniqueAttributes.ContainsKey(attributeType.FullName))
+ {
+ uniqueAttributes.Add(attributeType.FullName, attributeInstance);
+ }
+ }
+ else
+ {
+ nonUniqueAttributes.Add(attributeInstance);
+ }
+ }
+ }
+
+ ///
+ /// Check whether the member is loaded in a reflection only context.
+ ///
+ /// The member Info.
+ /// True if the member is loaded in a reflection only context.
+ private static bool IsReflectionOnlyLoad(MemberInfo? memberInfo)
+ => memberInfo is not null && memberInfo.Module.Assembly.ReflectionOnly;
+
+ private static bool IsTypeInheriting(Type? type1, Type type2)
+ {
+ while (type1 is not null)
+ {
+ if (type1.AssemblyQualifiedName.Equals(type2.AssemblyQualifiedName, StringComparison.Ordinal))
+ {
+ return true;
+ }
+
+ type1 = type1.BaseType;
+ }
+
+ return false;
+ }
+#endif
}
diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Services/TestDeployment.cs b/src/Adapter/MSTestAdapter.PlatformServices/Services/TestDeployment.cs
index 04b26fbfdf..3b0a064c27 100644
--- a/src/Adapter/MSTestAdapter.PlatformServices/Services/TestDeployment.cs
+++ b/src/Adapter/MSTestAdapter.PlatformServices/Services/TestDeployment.cs
@@ -2,6 +2,7 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#if !WINDOWS_UWP
+using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Helpers;
using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Deployment;
#endif
using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Interface;
@@ -38,7 +39,7 @@ internal sealed class TestDeployment : ITestDeployment
/// Initializes a new instance of the class.
///
public TestDeployment()
- : this(new DeploymentItemUtility(new ReflectionUtility()), new DeploymentUtility(), new FileUtility())
+ : this(new DeploymentItemUtility(ReflectHelper.Instance), new DeploymentUtility(), new FileUtility())
{
}
diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Utilities/DeploymentItemUtility.cs b/src/Adapter/MSTestAdapter.PlatformServices/Utilities/DeploymentItemUtility.cs
index 892345da66..19b877e867 100644
--- a/src/Adapter/MSTestAdapter.PlatformServices/Utilities/DeploymentItemUtility.cs
+++ b/src/Adapter/MSTestAdapter.PlatformServices/Utilities/DeploymentItemUtility.cs
@@ -3,6 +3,7 @@
#if !WINDOWS_UWP
+using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Helpers;
using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Deployment;
using Microsoft.VisualStudio.TestPlatform.ObjectModel;
using Microsoft.VisualStudio.TestTools.UnitTesting;
@@ -14,8 +15,7 @@ namespace Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Uti
///
internal sealed class DeploymentItemUtility
{
- // REVIEW: it would be better if this was a ReflectionHelper, because helper is able to cache. But we don't have reflection helper here, because this is platform services dll.
- private readonly ReflectionUtility _reflectionUtility;
+ private readonly ReflectHelper _reflectHelper;
///
/// A cache for class level deployment items.
@@ -25,10 +25,10 @@ internal sealed class DeploymentItemUtility
///
/// Initializes a new instance of the class.
///
- /// The reflect helper.
- internal DeploymentItemUtility(ReflectionUtility reflectionUtility)
+ /// The reflect helper.
+ internal DeploymentItemUtility(ReflectHelper reflectHelper)
{
- _reflectionUtility = reflectionUtility;
+ _reflectHelper = reflectHelper;
_classLevelDeploymentItems = [];
}
@@ -42,9 +42,7 @@ internal IList GetClassLevelDeploymentItems(Type type, ICollecti
{
if (!_classLevelDeploymentItems.TryGetValue(type, out IList? value))
{
- IReadOnlyList deploymentItemAttributes = _reflectionUtility.GetCustomAttributes(
- type,
- typeof(DeploymentItemAttribute));
+ IEnumerable deploymentItemAttributes = _reflectHelper.GetAttributes(type);
value = GetDeploymentItems(deploymentItemAttributes, warnings);
_classLevelDeploymentItems[type] = value;
}
@@ -61,7 +59,8 @@ internal IList GetClassLevelDeploymentItems(Type type, ICollecti
internal KeyValuePair[]? GetDeploymentItems(MethodInfo method, IEnumerable classLevelDeploymentItems,
ICollection warnings)
{
- List testLevelDeploymentItems = GetDeploymentItems(_reflectionUtility.GetCustomAttributes(method, typeof(DeploymentItemAttribute)), warnings);
+ IEnumerable deploymentItemAttributes = _reflectHelper.GetAttributes(method);
+ List testLevelDeploymentItems = GetDeploymentItems(deploymentItemAttributes, warnings);
return ToKeyValuePairs(Concat(testLevelDeploymentItems, classLevelDeploymentItems));
}
@@ -174,11 +173,11 @@ private static bool IsInvalidPath(string path)
return false;
}
- private static List GetDeploymentItems(IEnumerable deploymentItemAttributes, ICollection warnings)
+ private static List GetDeploymentItems(IEnumerable deploymentItemAttributes, ICollection warnings)
{
var deploymentItems = new List();
- foreach (DeploymentItemAttribute deploymentItemAttribute in deploymentItemAttributes.Cast())
+ foreach (DeploymentItemAttribute deploymentItemAttribute in deploymentItemAttributes)
{
if (IsValidDeploymentItem(deploymentItemAttribute.Path, deploymentItemAttribute.OutputDirectory, out string? warning))
{
diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Utilities/DeploymentUtilityBase.cs b/src/Adapter/MSTestAdapter.PlatformServices/Utilities/DeploymentUtilityBase.cs
index fbdba311ab..a6ae34e23b 100644
--- a/src/Adapter/MSTestAdapter.PlatformServices/Utilities/DeploymentUtilityBase.cs
+++ b/src/Adapter/MSTestAdapter.PlatformServices/Utilities/DeploymentUtilityBase.cs
@@ -3,6 +3,7 @@
#if !WINDOWS_UWP
+using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Helpers;
using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Deployment;
using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Extensions;
@@ -24,7 +25,7 @@ internal abstract class DeploymentUtilityBase
protected const string DeploymentFolderPrefix = "Deploy";
public DeploymentUtilityBase()
- : this(new DeploymentItemUtility(new ReflectionUtility()), new AssemblyUtility(), new FileUtility())
+ : this(new DeploymentItemUtility(ReflectHelper.Instance), new AssemblyUtility(), new FileUtility())
{
}
diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Utilities/ReflectionUtility.cs b/src/Adapter/MSTestAdapter.PlatformServices/Utilities/ReflectionUtility.cs
deleted file mode 100644
index fd3a04028c..0000000000
--- a/src/Adapter/MSTestAdapter.PlatformServices/Utilities/ReflectionUtility.cs
+++ /dev/null
@@ -1,282 +0,0 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
-// Licensed under the MIT license. See LICENSE file in the project root for full license information.
-
-#if !WINDOWS_UWP
-
-namespace Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Utilities;
-
-///
-/// Utility for reflection API's.
-///
-[SuppressMessage("Performance", "CA1852: Seal internal types", Justification = "Overrides required for testability")]
-internal class ReflectionUtility
-{
- internal virtual IReadOnlyList GetCustomAttributes(MemberInfo memberInfo, Type? type)
- => GetCustomAttributesCore(memberInfo, type);
-
- ///
- /// Gets all the custom attributes adorned on a member.
- ///
- /// The member.
- /// The list of attributes on the member. Empty list if none found.
- internal static IReadOnlyList GetCustomAttributes(MemberInfo memberInfo)
- => GetCustomAttributesCore(memberInfo, type: null);
-
- ///
- /// Get custom attributes on a member for both normal and reflection only load.
- ///
- /// Member for which attributes needs to be retrieved.
- /// Type of attribute to retrieve.
- /// All attributes of give type on member.
-#pragma warning disable CA1859 // Use concrete types when possible for improved performance
- internal static IReadOnlyList GetCustomAttributesCore(MemberInfo memberInfo, Type? type)
-#pragma warning restore CA1859
- {
-#if NETFRAMEWORK
- bool shouldGetAllAttributes = type == null;
-
- if (!IsReflectionOnlyLoad(memberInfo))
- {
- return shouldGetAllAttributes ? memberInfo.GetCustomAttributes(inherit: true) : memberInfo.GetCustomAttributes(type, inherit: true);
- }
- else
- {
- List nonUniqueAttributes = [];
- Dictionary uniqueAttributes = [];
-
- int inheritanceThreshold = 10;
- int inheritanceLevel = 0;
-
- if (memberInfo.MemberType == MemberTypes.TypeInfo)
- {
- // This code is based on the code for fetching CustomAttributes in System.Reflection.CustomAttribute(RuntimeType type, RuntimeType caType, bool inherit)
- var tempTypeInfo = memberInfo as TypeInfo;
-
- do
- {
- IList attributes = CustomAttributeData.GetCustomAttributes(tempTypeInfo);
- AddNewAttributes(
- attributes,
- shouldGetAllAttributes,
- type!,
- uniqueAttributes,
- nonUniqueAttributes);
- tempTypeInfo = tempTypeInfo!.BaseType?.GetTypeInfo();
- inheritanceLevel++;
- }
- while (tempTypeInfo != null && tempTypeInfo != typeof(object).GetTypeInfo()
- && inheritanceLevel < inheritanceThreshold);
- }
- else if (memberInfo.MemberType == MemberTypes.Method)
- {
- // This code is based on the code for fetching CustomAttributes in System.Reflection.CustomAttribute(RuntimeMethodInfo method, RuntimeType caType, bool inherit).
- var tempMethodInfo = memberInfo as MethodInfo;
-
- do
- {
- IList attributes = CustomAttributeData.GetCustomAttributes(tempMethodInfo);
- AddNewAttributes(
- attributes,
- shouldGetAllAttributes,
- type!,
- uniqueAttributes,
- nonUniqueAttributes);
- MethodInfo? baseDefinition = tempMethodInfo!.GetBaseDefinition();
-
- if (baseDefinition != null
- && string.Equals(
- string.Concat(tempMethodInfo.DeclaringType.FullName, tempMethodInfo.Name),
- string.Concat(baseDefinition.DeclaringType.FullName, baseDefinition.Name), StringComparison.Ordinal))
- {
- break;
- }
-
- tempMethodInfo = baseDefinition;
- inheritanceLevel++;
- }
- while (tempMethodInfo != null && inheritanceLevel < inheritanceThreshold);
- }
- else
- {
- // Ideally we should not be reaching here. We only query for attributes on types/methods currently.
- // Return the attributes that CustomAttributeData returns in this cases not considering inheritance.
- IList firstLevelAttributes =
- CustomAttributeData.GetCustomAttributes(memberInfo);
- AddNewAttributes(firstLevelAttributes, shouldGetAllAttributes, type!, uniqueAttributes, nonUniqueAttributes);
- }
-
- nonUniqueAttributes.AddRange(uniqueAttributes.Values);
- return nonUniqueAttributes;
- }
-#else
- return type == null
- ? memberInfo.GetCustomAttributes(inherit: true)
- : memberInfo.GetCustomAttributes(type, inherit: true);
-#endif
- }
-
-#if NETFRAMEWORK
- internal static List GetCustomAttributes(Assembly assembly, Type type)
- {
- if (!assembly.ReflectionOnly)
- {
- return [.. assembly.GetCustomAttributes(type)];
- }
-
- List customAttributes = [.. CustomAttributeData.GetCustomAttributes(assembly)];
-
- List attributesArray = [];
-
- foreach (CustomAttributeData attribute in customAttributes)
- {
- if (!IsTypeInheriting(attribute.Constructor.DeclaringType, type)
- && !attribute.Constructor.DeclaringType.AssemblyQualifiedName.Equals(
- type.AssemblyQualifiedName, StringComparison.Ordinal))
- {
- continue;
- }
-
- Attribute? attributeInstance = CreateAttributeInstance(attribute);
- if (attributeInstance != null)
- {
- attributesArray.Add(attributeInstance);
- }
- }
-
- return attributesArray;
- }
-
- ///
- /// Create instance of the attribute for reflection only load.
- ///
- /// The attribute data.
- /// An attribute.
- private static Attribute? CreateAttributeInstance(CustomAttributeData attributeData)
- {
- object? attribute = null;
- try
- {
- // Create instance of attribute. For some case, constructor param is returned as ReadOnlyCollection
- // instead of array. So convert it to array else constructor invoke will fail.
- var attributeType = Type.GetType(attributeData.Constructor.DeclaringType.AssemblyQualifiedName);
-
- List constructorParameters = [];
- List constructorArguments = [];
- foreach (CustomAttributeTypedArgument parameter in attributeData.ConstructorArguments)
- {
- var parameterType = Type.GetType(parameter.ArgumentType.AssemblyQualifiedName);
- constructorParameters.Add(parameterType);
- if (!parameterType.IsArray
- || parameter.Value is not IEnumerable enumerable)
- {
- constructorArguments.Add(parameter.Value);
- continue;
- }
-
- ArrayList list = [];
- foreach (object? item in enumerable)
- {
- if (item is CustomAttributeTypedArgument argument)
- {
- list.Add(argument.Value);
- }
- else
- {
- list.Add(item);
- }
- }
-
- constructorArguments.Add(list.ToArray(parameterType.GetElementType()));
- }
-
- ConstructorInfo constructor = attributeType.GetConstructor([.. constructorParameters]);
- attribute = constructor.Invoke([.. constructorArguments]);
-
- foreach (CustomAttributeNamedArgument namedArgument in attributeData.NamedArguments)
- {
- attributeType.GetProperty(namedArgument.MemberInfo.Name).SetValue(attribute, namedArgument.TypedValue.Value, null);
- }
- }
-
- // If not able to create instance of attribute ignore attribute. (May happen for custom user defined attributes).
- catch (BadImageFormatException)
- {
- }
- catch (FileLoadException)
- {
- }
- catch (TypeLoadException)
- {
- }
-
- return attribute as Attribute;
- }
-
- private static void AddNewAttributes(
- IList customAttributes,
- bool shouldGetAllAttributes,
- Type type,
- Dictionary uniqueAttributes,
- List nonUniqueAttributes)
- {
- foreach (CustomAttributeData attribute in customAttributes)
- {
- if (!shouldGetAllAttributes
- && !IsTypeInheriting(attribute.Constructor.DeclaringType, type)
- && !attribute.Constructor.DeclaringType.AssemblyQualifiedName.Equals(
- type.AssemblyQualifiedName, StringComparison.Ordinal))
- {
- continue;
- }
-
- Attribute? attributeInstance = CreateAttributeInstance(attribute);
- if (attributeInstance == null)
- {
- continue;
- }
-
- Type attributeType = attributeInstance.GetType();
- IReadOnlyList attributeUsageAttributes = GetCustomAttributesCore(
- attributeType,
- typeof(AttributeUsageAttribute));
- if (attributeUsageAttributes.Count > 0
- && attributeUsageAttributes[0] is AttributeUsageAttribute { AllowMultiple: false })
- {
- if (!uniqueAttributes.ContainsKey(attributeType.FullName))
- {
- uniqueAttributes.Add(attributeType.FullName, attributeInstance);
- }
- }
- else
- {
- nonUniqueAttributes.Add(attributeInstance);
- }
- }
- }
-
- ///
- /// Check whether the member is loaded in a reflection only context.
- ///
- /// The member Info.
- /// True if the member is loaded in a reflection only context.
- private static bool IsReflectionOnlyLoad(MemberInfo? memberInfo)
- => memberInfo != null && memberInfo.Module.Assembly.ReflectionOnly;
-
- private static bool IsTypeInheriting(Type? type1, Type type2)
- {
- while (type1 != null)
- {
- if (type1.AssemblyQualifiedName.Equals(type2.AssemblyQualifiedName, StringComparison.Ordinal))
- {
- return true;
- }
-
- type1 = type1.BaseType;
- }
-
- return false;
- }
-#endif
-}
-
-#endif
diff --git a/test/IntegrationTests/PlatformServices.Desktop.IntegrationTests/ReflectionUtilityTests.cs b/test/IntegrationTests/PlatformServices.Desktop.IntegrationTests/ReflectionUtilityTests.cs
index 6d65e28527..6713c84c42 100644
--- a/test/IntegrationTests/PlatformServices.Desktop.IntegrationTests/ReflectionUtilityTests.cs
+++ b/test/IntegrationTests/PlatformServices.Desktop.IntegrationTests/ReflectionUtilityTests.cs
@@ -3,7 +3,7 @@
using AwesomeAssertions;
-using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Utilities;
+using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices;
using SampleFrameworkExtensions;
@@ -14,9 +14,11 @@ namespace PlatformServices.Desktop.ComponentTests;
public class ReflectionUtilityTests : TestContainer
{
private readonly Assembly _testAsset;
+ private readonly ReflectionOperations _reflectionOperations;
public ReflectionUtilityTests()
{
+ _reflectionOperations = new ReflectionOperations();
DirectoryInfo currentAssemblyDirectory = new FileInfo(typeof(ReflectionUtilityTests).Assembly.Location).Directory;
string testAssetPath =
Path.Combine(
@@ -39,7 +41,7 @@ public void GetCustomAttributesShouldReturnAllAttributes()
{
MethodInfo methodInfo = _testAsset.GetType("TestProjectForDiscovery.AttributeTestBaseClass").GetMethod("DummyVTestMethod1")!;
- IReadOnlyList attributes = ReflectionUtility.GetCustomAttributes(methodInfo);
+ object[] attributes = _reflectionOperations.GetCustomAttributes(methodInfo);
attributes.Should().NotBeNull();
attributes.Should().HaveCount(2);
@@ -52,7 +54,7 @@ public void GetCustomAttributesShouldReturnAllAttributesWithBaseInheritance()
{
MethodInfo methodInfo = _testAsset.GetType("TestProjectForDiscovery.AttributeTestClass").GetMethod("DummyVTestMethod1")!;
- IReadOnlyList attributes = ReflectionUtility.GetCustomAttributes(methodInfo);
+ object[] attributes = _reflectionOperations.GetCustomAttributes(methodInfo);
attributes.Should().NotBeNull();
attributes.Should().HaveCount(3);
@@ -66,7 +68,7 @@ public void GetCustomAttributesOnTypeShouldReturnAllAttributes()
{
Type type = _testAsset.GetType("TestProjectForDiscovery.AttributeTestBaseClass");
- IReadOnlyList attributes = ReflectionUtility.GetCustomAttributes(type);
+ object[] attributes = _reflectionOperations.GetCustomAttributes(type);
attributes.Should().NotBeNull();
attributes.Should().HaveCount(1);
@@ -79,7 +81,7 @@ public void GetCustomAttributesOnTypeShouldReturnAllAttributesWithBaseInheritanc
{
Type type = _testAsset.GetType("TestProjectForDiscovery.AttributeTestClass");
- IReadOnlyList attributes = ReflectionUtility.GetCustomAttributes(type);
+ object[] attributes = _reflectionOperations.GetCustomAttributes(type);
attributes.Should().NotBeNull();
attributes.Should().HaveCount(2);
@@ -92,7 +94,7 @@ public void GetSpecificCustomAttributesShouldReturnAllAttributes()
{
MethodInfo methodInfo = _testAsset.GetType("TestProjectForDiscovery.AttributeTestBaseClass").GetMethod("DummyVTestMethod1")!;
- IReadOnlyList attributes = ReflectionUtility.GetCustomAttributesCore(methodInfo, typeof(TestCategoryAttribute));
+ object[] attributes = _reflectionOperations.GetCustomAttributes(methodInfo, typeof(TestCategoryAttribute));
attributes.Should().NotBeNull();
attributes.Should().HaveCount(1);
@@ -106,7 +108,7 @@ public void GetSpecificCustomAttributesShouldReturnAllAttributesWithBaseInherita
MethodInfo methodInfo =
_testAsset.GetType("TestProjectForDiscovery.AttributeTestClass").GetMethod("DummyVTestMethod1")!;
- IReadOnlyList attributes = ReflectionUtility.GetCustomAttributesCore(methodInfo, typeof(TestCategoryAttribute));
+ object[] attributes = _reflectionOperations.GetCustomAttributes(methodInfo, typeof(TestCategoryAttribute));
attributes.Should().NotBeNull();
attributes.Should().HaveCount(2);
@@ -119,7 +121,7 @@ public void GetCustomAttributesShouldReturnAllAttributesIncludingUserDefinedAttr
{
MethodInfo methodInfo = _testAsset.GetType("TestProjectForDiscovery.AttributeTestClassWithCustomAttributes").GetMethod("DummyVTestMethod1")!;
- IReadOnlyList attributes = ReflectionUtility.GetCustomAttributesCore(methodInfo, null);
+ object[] attributes = _reflectionOperations.GetCustomAttributes(methodInfo);
attributes.Should().NotBeNull();
attributes.Should().HaveCount(3);
@@ -132,7 +134,7 @@ public void GetSpecificCustomAttributesShouldReturnAllAttributesIncludingUserDef
{
MethodInfo methodInfo = _testAsset.GetType("TestProjectForDiscovery.AttributeTestClassWithCustomAttributes").GetMethod("DummyVTestMethod1")!;
- IReadOnlyList attributes = ReflectionUtility.GetCustomAttributesCore(methodInfo, typeof(TestPropertyAttribute));
+ object[] attributes = _reflectionOperations.GetCustomAttributes(methodInfo, typeof(TestPropertyAttribute));
attributes.Should().NotBeNull();
attributes.Should().HaveCount(2);
@@ -145,7 +147,7 @@ public void GetSpecificCustomAttributesShouldReturnArrayAttributesAsWell()
{
MethodInfo methodInfo = _testAsset.GetType("TestProjectForDiscovery.AttributeTestClassWithCustomAttributes").GetMethod("DummyTestMethod2")!;
- IReadOnlyList attributes = ReflectionUtility.GetCustomAttributesCore(methodInfo, typeof(CategoryArrayAttribute));
+ object[] attributes = _reflectionOperations.GetCustomAttributes(methodInfo, typeof(CategoryArrayAttribute));
attributes.Should().NotBeNull();
attributes.Should().HaveCount(1);
@@ -158,7 +160,7 @@ public void GetSpecificCustomAttributesOnTypeShouldReturnAllAttributes()
{
Type type = _testAsset.GetType("TestProjectForDiscovery.AttributeTestBaseClass");
- IReadOnlyList attributes = ReflectionUtility.GetCustomAttributesCore(type, typeof(TestCategoryAttribute));
+ object[] attributes = _reflectionOperations.GetCustomAttributes(type, typeof(TestCategoryAttribute));
attributes.Should().NotBeNull();
attributes.Should().HaveCount(1);
@@ -171,7 +173,7 @@ public void GetSpecificCustomAttributesOnTypeShouldReturnAllAttributesWithBaseIn
{
Type type = _testAsset.GetType("TestProjectForDiscovery.AttributeTestClass");
- IReadOnlyList attributes = ReflectionUtility.GetCustomAttributesCore(type, typeof(TestCategoryAttribute));
+ object[] attributes = _reflectionOperations.GetCustomAttributes(type, typeof(TestCategoryAttribute));
attributes.Should().NotBeNull();
attributes.Should().HaveCount(2);
@@ -184,7 +186,7 @@ public void GetSpecificCustomAttributesOnAssemblyShouldReturnAllAttributes()
{
Assembly asm = _testAsset.GetType("TestProjectForDiscovery.AttributeTestClass").Assembly;
- List attributes = ReflectionUtility.GetCustomAttributes(asm, typeof(TestCategoryAttribute));
+ object[] attributes = _reflectionOperations.GetCustomAttributes(asm, typeof(TestCategoryAttribute));
attributes.Should().NotBeNull();
attributes.Should().HaveCount(2);
diff --git a/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Services/DesktopTestDeploymentTests.cs b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Services/DesktopTestDeploymentTests.cs
index 41262e4193..f610ee9dc7 100644
--- a/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Services/DesktopTestDeploymentTests.cs
+++ b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Services/DesktopTestDeploymentTests.cs
@@ -2,6 +2,7 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#if NETFRAMEWORK
+using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Helpers;
using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices;
using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Deployment;
using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Utilities;
@@ -21,7 +22,7 @@ public class DesktopTestDeploymentTests : TestContainer
private const string DefaultDeploymentItemPath = @"c:\temp";
private const string DefaultDeploymentItemOutputDirectory = "out";
- private readonly Mock _mockReflectionUtility;
+ private readonly Mock _mockReflectHelper;
private readonly Mock _mockFileUtility;
#pragma warning disable IDE0052 // Remove unread private members
@@ -30,7 +31,7 @@ public class DesktopTestDeploymentTests : TestContainer
public DesktopTestDeploymentTests()
{
- _mockReflectionUtility = new Mock();
+ _mockReflectHelper = new Mock();
_mockFileUtility = new Mock();
_warnings = [];
@@ -126,11 +127,9 @@ private void SetupDeploymentItems(MemberInfo memberInfo, KeyValuePair
- ru.GetCustomAttributes(
- memberInfo,
- typeof(DeploymentItemAttribute))).Returns(deploymentItemAttributes.ToArray());
+ _mockReflectHelper.Setup(
+ rh =>
+ rh.GetAttributes(memberInfo)).Returns(deploymentItemAttributes);
}
private TestCase GetTestCase(string source)
@@ -165,7 +164,7 @@ private TestDeployment CreateAndSetupDeploymentRelatedUtilities(out TestRunDirec
_mockFileUtility.Setup(fu => fu.GetNextIterationDirectoryName(It.IsAny(), It.IsAny()))
.Returns(testRunDirectories.RootDeploymentDirectory);
- var deploymentItemUtility = new DeploymentItemUtility(_mockReflectionUtility.Object);
+ var deploymentItemUtility = new DeploymentItemUtility(_mockReflectHelper.Object);
return new TestDeployment(
deploymentItemUtility,
diff --git a/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Services/TestDeploymentTests.cs b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Services/TestDeploymentTests.cs
index 6619a81bb9..d4136a72cf 100644
--- a/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Services/TestDeploymentTests.cs
+++ b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Services/TestDeploymentTests.cs
@@ -1,6 +1,7 @@
// 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.TestPlatform.MSTest.TestAdapter.Helpers;
using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices;
using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Deployment;
using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Utilities;
@@ -22,7 +23,7 @@ public class TestDeploymentTests : TestContainer
private const string DefaultDeploymentItemPath = @"c:\temp";
private const string DefaultDeploymentItemOutputDirectory = "out";
- private readonly Mock _mockReflectionUtility;
+ private readonly Mock _mockReflectHelper;
private readonly Mock _mockFileUtility;
#pragma warning disable IDE0044 // Add readonly modifier
@@ -31,7 +32,7 @@ public class TestDeploymentTests : TestContainer
public TestDeploymentTests()
{
- _mockReflectionUtility = new Mock();
+ _mockReflectHelper = new Mock();
_mockFileUtility = new Mock();
_warnings = [];
@@ -50,7 +51,7 @@ public void GetDeploymentItemsReturnsNullWhenNoDeploymentItems()
public void GetDeploymentItemsReturnsDeploymentItems()
{
// Arrange.
- var testDeployment = new TestDeployment(new DeploymentItemUtility(_mockReflectionUtility.Object), null!, null!);
+ var testDeployment = new TestDeployment(new DeploymentItemUtility(_mockReflectHelper.Object), null!, null!);
// setup mocks
KeyValuePair[] methodLevelDeploymentItems =
@@ -179,7 +180,7 @@ public void DeployShouldReturnFalseWhenDeploymentEnabledSetToFalseButHasDeployme
testCase.SetPropertyValue(DeploymentItemUtilityTests.DeploymentItemsProperty, kvpArray);
var testDeployment = new TestDeployment(
- new DeploymentItemUtility(_mockReflectionUtility.Object),
+ new DeploymentItemUtility(_mockReflectHelper.Object),
new DeploymentUtility(),
_mockFileUtility.Object);
@@ -202,7 +203,7 @@ public void DeployShouldReturnFalseWhenDeploymentEnabledSetToFalseAndHasNoDeploy
var testCase = new TestCase("A.C.M", new Uri("executor://testExecutor"), "path/to/asm.dll");
testCase.SetPropertyValue(DeploymentItemUtilityTests.DeploymentItemsProperty, null);
var testDeployment = new TestDeployment(
- new DeploymentItemUtility(_mockReflectionUtility.Object),
+ new DeploymentItemUtility(_mockReflectHelper.Object),
new DeploymentUtility(),
_mockFileUtility.Object);
@@ -225,7 +226,7 @@ public void DeployShouldReturnFalseWhenDeploymentEnabledSetToTrueButHasNoDeploym
var testCase = new TestCase("A.C.M", new Uri("executor://testExecutor"), "path/to/asm.dll");
testCase.SetPropertyValue(DeploymentItemUtilityTests.DeploymentItemsProperty, null);
var testDeployment = new TestDeployment(
- new DeploymentItemUtility(_mockReflectionUtility.Object),
+ new DeploymentItemUtility(_mockReflectHelper.Object),
new DeploymentUtility(),
_mockFileUtility.Object);
@@ -255,7 +256,7 @@ internal void DeployShouldReturnTrueWhenDeploymentEnabledSetToTrueAndHasDeployme
];
testCase.SetPropertyValue(DeploymentItemUtilityTests.DeploymentItemsProperty, kvpArray);
var testDeployment = new TestDeployment(
- new DeploymentItemUtility(_mockReflectionUtility.Object),
+ new DeploymentItemUtility(_mockReflectHelper.Object),
new DeploymentUtility(),
_mockFileUtility.Object);
@@ -368,11 +369,9 @@ private void SetupDeploymentItems(MemberInfo memberInfo, KeyValuePair
- ru.GetCustomAttributes(
- memberInfo,
- typeof(DeploymentItemAttribute))).Returns(deploymentItemAttributes.ToArray());
+ _mockReflectHelper.Setup(
+ rh =>
+ rh.GetAttributes(memberInfo)).Returns(deploymentItemAttributes);
}
private static TestCase GetTestCase(string source)
@@ -416,7 +415,7 @@ private TestDeployment CreateAndSetupDeploymentRelatedUtilities(out TestRunDirec
_mockFileUtility.Setup(fu => fu.GetNextIterationDirectoryName(It.IsAny(), It.IsAny()))
.Returns(testRunDirectories.RootDeploymentDirectory);
- var deploymentItemUtility = new DeploymentItemUtility(_mockReflectionUtility.Object);
+ var deploymentItemUtility = new DeploymentItemUtility(_mockReflectHelper.Object);
return new TestDeployment(
deploymentItemUtility,
diff --git a/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Utilities/DeploymentUtilityTests.cs b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Utilities/DeploymentUtilityTests.cs
index 578c096bdd..04762d894b 100644
--- a/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Utilities/DeploymentUtilityTests.cs
+++ b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Utilities/DeploymentUtilityTests.cs
@@ -1,6 +1,7 @@
// 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.TestPlatform.MSTest.TestAdapter.Helpers;
using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Deployment;
using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Resources;
using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Utilities;
@@ -23,7 +24,7 @@ public class DeploymentUtilityTests : TestContainer
private const string DefaultDeploymentItemPath = @"c:\temp";
private const string DefaultDeploymentItemOutputDirectory = "out";
- private readonly Mock _mockReflectionUtility;
+ private readonly Mock _mockReflectHelper;
private readonly Mock _mockFileUtility;
private readonly Mock _mockAssemblyUtility;
private readonly Mock _mockRunContext;
@@ -39,13 +40,13 @@ public class DeploymentUtilityTests : TestContainer
public DeploymentUtilityTests()
{
- _mockReflectionUtility = new Mock();
+ _mockReflectHelper = new Mock();
_mockFileUtility = new Mock();
_mockAssemblyUtility = new Mock();
_warnings = [];
_deploymentUtility = new DeploymentUtility(
- new DeploymentItemUtility(_mockReflectionUtility.Object),
+ new DeploymentItemUtility(_mockReflectHelper.Object),
_mockAssemblyUtility.Object,
_mockFileUtility.Object);
diff --git a/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Utilities/DesktopReflectionUtilityTests.cs b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Utilities/DesktopReflectionUtilityTests.cs
index 0996e422a2..132e16f9fc 100644
--- a/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Utilities/DesktopReflectionUtilityTests.cs
+++ b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Utilities/DesktopReflectionUtilityTests.cs
@@ -2,7 +2,7 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#if NETFRAMEWORK
-using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Utilities;
+using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices;
using TestFramework.ForTestingMSTest;
@@ -12,14 +12,16 @@ namespace MSTestAdapter.PlatformServices.UnitTests.Utilities;
public class ReflectionUtilityTests : TestContainer
#pragma warning restore SA1649 // File name must match first type name
{
+ private readonly ReflectionOperations _reflectionOperations = new();
+
public void GetSpecificCustomAttributesOnAssemblyShouldReturnAllAttributes()
{
Assembly asm = typeof(DummyTestClass).Assembly;
- List attributes = ReflectionUtility.GetCustomAttributes(asm, typeof(DummyAAttribute));
+ object[] attributes = _reflectionOperations.GetCustomAttributes(asm, typeof(DummyAAttribute));
Verify(attributes is not null);
- Verify(attributes.Count == 2);
+ Verify(attributes.Length == 2);
string[] expectedAttributes = ["DummyA : a1", "DummyA : a2"];
Verify(expectedAttributes.SequenceEqual(GetAttributeValuePairs(attributes)));
diff --git a/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Utilities/ns13DeploymentItemUtilityTests.cs b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Utilities/ns13DeploymentItemUtilityTests.cs
index 539c42f503..692bc87cc9 100644
--- a/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Utilities/ns13DeploymentItemUtilityTests.cs
+++ b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Utilities/ns13DeploymentItemUtilityTests.cs
@@ -1,6 +1,7 @@
// 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.TestPlatform.MSTest.TestAdapter.Helpers;
using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Deployment;
using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Resources;
using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Utilities;
@@ -23,7 +24,7 @@ public class DeploymentItemUtilityTests : TestContainer
TestPropertyAttributes.Hidden,
typeof(TestCase));
- private readonly Mock _mockReflectionUtility;
+ private readonly Mock _mockReflectHelper;
private readonly DeploymentItemUtility _deploymentItemUtility;
private readonly ICollection _warnings;
@@ -32,8 +33,8 @@ public class DeploymentItemUtilityTests : TestContainer
public DeploymentItemUtilityTests()
{
- _mockReflectionUtility = new Mock();
- _deploymentItemUtility = new DeploymentItemUtility(_mockReflectionUtility.Object);
+ _mockReflectHelper = new Mock();
+ _deploymentItemUtility = new DeploymentItemUtility(_mockReflectHelper.Object);
_warnings = [];
}
@@ -41,7 +42,7 @@ public DeploymentItemUtilityTests()
public void GetClassLevelDeploymentItemsShouldReturnEmptyListWhenNoDeploymentItems()
{
- _mockReflectionUtility.Setup(x => x.GetCustomAttributes(typeof(DeploymentItemUtilityTests), typeof(DeploymentItemAttribute)))
+ _mockReflectHelper.Setup(x => x.GetAttributes(typeof(DeploymentItemUtilityTests)))
.Returns([]);
IList deploymentItems = _deploymentItemUtility.GetClassLevelDeploymentItems(typeof(DeploymentItemUtilityTests), _warnings);
@@ -162,7 +163,7 @@ public void GetClassLevelDeploymentItemsShouldReportWarningsForInvalidDeployment
public void GetDeploymentItemsShouldReturnNullOnNoDeploymentItems()
{
MethodInfo method = typeof(DeploymentItemUtilityTests).GetMethod("GetDeploymentItemsShouldReturnNullOnNoDeploymentItems")!;
- _mockReflectionUtility.Setup(x => x.GetCustomAttributes(method, typeof(DeploymentItemAttribute)))
+ _mockReflectHelper.Setup(x => x.GetAttributes(method))
.Returns([]);
Verify(_deploymentItemUtility.GetDeploymentItems(method, null!, _warnings) is null);
@@ -207,7 +208,7 @@ public void GetDeploymentItemsShouldReturnClassLevelDeploymentItemsOnly()
};
MethodInfo method = typeof(DeploymentItemUtilityTests).GetMethod("GetDeploymentItemsShouldReturnNullOnNoDeploymentItems")!;
- _mockReflectionUtility.Setup(x => x.GetCustomAttributes(method, typeof(DeploymentItemAttribute)))
+ _mockReflectHelper.Setup(x => x.GetAttributes(method))
.Returns([]);
// Act.
@@ -426,11 +427,9 @@ private void SetupDeploymentItems(MemberInfo memberInfo, KeyValuePair
- ru.GetCustomAttributes(
- memberInfo,
- typeof(DeploymentItemAttribute))).Returns(deploymentItemAttributes.ToArray());
+ _mockReflectHelper.Setup(
+ rh =>
+ rh.GetAttributes(memberInfo)).Returns(deploymentItemAttributes);
}
#endregion
diff --git a/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Utilities/ns13ReflectionUtilityTests.cs b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Utilities/ns13ReflectionUtilityTests.cs
index c22a003840..5bedb358cb 100644
--- a/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Utilities/ns13ReflectionUtilityTests.cs
+++ b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Utilities/ns13ReflectionUtilityTests.cs
@@ -1,7 +1,7 @@
// 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.TestPlatform.MSTestAdapter.PlatformServices.Utilities;
+using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices;
using TestFramework.ForTestingMSTest;
@@ -11,14 +11,16 @@ namespace MSTestAdapter.PlatformServices.Tests.Utilities;
public class ReflectionUtilityTests : TestContainer
#pragma warning restore SA1649 // File name must match first type name
{
+ private readonly ReflectionOperations _reflectionOperations = new();
+
public void GetCustomAttributesShouldReturnAllAttributes()
{
MethodInfo methodInfo = typeof(DummyBaseTestClass).GetMethod("DummyVTestMethod1")!;
- IReadOnlyList attributes = ReflectionUtility.GetCustomAttributes(methodInfo);
+ object[] attributes = _reflectionOperations.GetCustomAttributes(methodInfo);
Verify(attributes is not null);
- Verify(attributes.Count == 2);
+ Verify(attributes.Length == 2);
string[] expectedAttributes = ["DummyA : base", "DummySingleA : base"];
Verify(expectedAttributes.SequenceEqual(GetAttributeValuePairs(attributes)));
@@ -28,10 +30,10 @@ public void GetCustomAttributesShouldReturnAllAttributesWithBaseInheritance()
{
MethodInfo methodInfo = typeof(DummyTestClass).GetMethod("DummyVTestMethod1")!;
- IReadOnlyList attributes = ReflectionUtility.GetCustomAttributes(methodInfo);
+ object[] attributes = _reflectionOperations.GetCustomAttributes(methodInfo);
Verify(attributes is not null);
- Verify(attributes.Count == 3);
+ Verify(attributes.Length == 3);
// Notice that the DummySingleA on the base method does not show up since it can only be defined once.
string[] expectedAttributes = ["DummyA : derived", "DummySingleA : derived", "DummyA : base"];
@@ -42,10 +44,10 @@ public void GetCustomAttributesOnTypeShouldReturnAllAttributes()
{
Type type = typeof(DummyBaseTestClass);
- IReadOnlyList attributes = ReflectionUtility.GetCustomAttributes(type);
+ object[] attributes = _reflectionOperations.GetCustomAttributes(type);
Verify(attributes is not null);
- Verify(attributes.Count == 1);
+ Verify(attributes.Length == 1);
string[] expectedAttributes = ["DummyA : ba"];
Verify(expectedAttributes.SequenceEqual(GetAttributeValuePairs(attributes)));
@@ -55,10 +57,10 @@ public void GetCustomAttributesOnTypeShouldReturnAllAttributesWithBaseInheritanc
{
Type type = typeof(DummyTestClass);
- IReadOnlyList attributes = ReflectionUtility.GetCustomAttributes(type);
+ object[] attributes = _reflectionOperations.GetCustomAttributes(type);
Verify(attributes is not null);
- Verify(attributes.Count == 2);
+ Verify(attributes.Length == 2);
string[] expectedAttributes = ["DummyA : a", "DummyA : ba"];
Verify(expectedAttributes.SequenceEqual(GetAttributeValuePairs(attributes)));
@@ -68,10 +70,10 @@ public void GetSpecificCustomAttributesShouldReturnAllAttributes()
{
MethodInfo methodInfo = typeof(DummyBaseTestClass).GetMethod("DummyVTestMethod1")!;
- IReadOnlyList attributes = ReflectionUtility.GetCustomAttributesCore(methodInfo, typeof(DummyAAttribute));
+ object[] attributes = _reflectionOperations.GetCustomAttributes(methodInfo, typeof(DummyAAttribute));
Verify(attributes is not null);
- Verify(attributes.Count == 1);
+ Verify(attributes.Length == 1);
string[] expectedAttributes = ["DummyA : base"];
Verify(expectedAttributes.SequenceEqual(GetAttributeValuePairs(attributes)));
@@ -81,10 +83,10 @@ public void GetSpecificCustomAttributesShouldReturnAllAttributesWithBaseInherita
{
MethodInfo methodInfo = typeof(DummyTestClass).GetMethod("DummyVTestMethod1")!;
- IReadOnlyList attributes = ReflectionUtility.GetCustomAttributesCore(methodInfo, typeof(DummyAAttribute));
+ object[] attributes = _reflectionOperations.GetCustomAttributes(methodInfo, typeof(DummyAAttribute));
Verify(attributes is not null);
- Verify(attributes.Count == 2);
+ Verify(attributes.Length == 2);
string[] expectedAttributes = ["DummyA : derived", "DummyA : base"];
Verify(expectedAttributes.SequenceEqual(GetAttributeValuePairs(attributes)));
@@ -94,23 +96,23 @@ public void GetSpecificCustomAttributesOnTypeShouldReturnAllAttributes()
{
Type type = typeof(DummyBaseTestClass);
- IReadOnlyList attributes = ReflectionUtility.GetCustomAttributesCore(type, typeof(DummyAAttribute));
+ object[] attributes = _reflectionOperations.GetCustomAttributes(type, typeof(DummyAAttribute));
Verify(attributes is not null);
- Verify(attributes.Count == 1);
+ Verify(attributes.Length == 1);
string[] expectedAttributes = ["DummyA : ba"];
Verify(expectedAttributes.SequenceEqual(GetAttributeValuePairs(attributes)));
}
- public void GetSpecificCustomAttributesOnTypeShouldReturnAllAttributesWithBaseInheritance()
+ public void GetSpecificCustomAttributesOnTypeShouldReturnAllAttributesIgnoringBaseInheritance()
{
Type type = typeof(DummyTestClass);
- IReadOnlyList attributes = ReflectionUtility.GetCustomAttributesCore(type, typeof(DummyAAttribute));
+ object[] attributes = _reflectionOperations.GetCustomAttributes(type, typeof(DummyAAttribute));
Verify(attributes is not null);
- Verify(attributes.Count == 2);
+ Verify(attributes.Length == 2);
string[] expectedAttributes = ["DummyA : a", "DummyA : ba"];
Verify(expectedAttributes.SequenceEqual(GetAttributeValuePairs(attributes)));