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)));