diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index d5a3444991..531fb9e908 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -21,9 +21,9 @@ https://github.com/microsoft/testanywhere d8fa8c790db1eb9f5eee1d4d8be1c8c21c3c3ef9 - + https://github.com/microsoft/testanywhere - aa2fcc8616d988b234bc1d218465b20c56d0b82f + 3c99c34d0f99de8dacfe909073722bd8ba45f2d8 diff --git a/eng/Versions.props b/eng/Versions.props index f8823dae76..ee38ee7822 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -3,7 +3,7 @@ 3.7.0 - 1.5.0 + 1.6.0 preview @@ -11,6 +11,6 @@ 17.13.0-preview.24562.1 1.5.0-preview.24569.1 - 1.0.0-alpha.24473.2 + 1.0.0-alpha.24555.1 diff --git a/samples/Playground/DebuggerUtility.cs b/samples/Playground/DebuggerUtility.cs index 6b58a2a58d..71e474bd6a 100644 --- a/samples/Playground/DebuggerUtility.cs +++ b/samples/Playground/DebuggerUtility.cs @@ -121,9 +121,7 @@ private static bool AttachVs(Process vs, int pid, bool enableLog = false) IEnumMoniker? enumMoniker = null; try { -#pragma warning disable IL2050 int r = CreateBindCtx(0, out bindCtx); -#pragma warning restore IL2050 Marshal.ThrowExceptionForHR(r); if (bindCtx == null) { diff --git a/samples/Playground/Program.cs b/samples/Playground/Program.cs index c285308345..f5d0adb2b2 100644 --- a/samples/Playground/Program.cs +++ b/samples/Playground/Program.cs @@ -27,7 +27,7 @@ public static async Task Main(string[] args) if (Environment.GetEnvironmentVariable("TESTSERVERMODE") != "1") { // To attach to the children - Microsoft.Testing.TestInfrastructure.DebuggerUtility.AttachCurrentProcessToParentVSProcess(); + // Microsoft.Testing.TestInfrastructure.DebuggerUtility.AttachCurrentProcessToParentVSProcess(); ITestApplicationBuilder testApplicationBuilder = await TestApplication.CreateBuilderAsync(args); // Test MSTest diff --git a/src/Adapter/MSTest.TestAdapter/Discovery/AssemblyEnumerator.cs b/src/Adapter/MSTest.TestAdapter/Discovery/AssemblyEnumerator.cs index 711bda3b0e..b5baad9649 100644 --- a/src/Adapter/MSTest.TestAdapter/Discovery/AssemblyEnumerator.cs +++ b/src/Adapter/MSTest.TestAdapter/Discovery/AssemblyEnumerator.cs @@ -11,6 +11,9 @@ using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution; using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Helpers; using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel; +#if NET8_0_OR_GREATER +using Microsoft.VisualStudio.TestPlatform.MSTestAdapter; +#endif using Microsoft.VisualStudio.TestPlatform.ObjectModel; using Microsoft.VisualStudio.TestTools.UnitTesting; using Microsoft.VisualStudio.TestTools.UnitTesting.Internal; @@ -305,8 +308,13 @@ private static bool DynamicDataAttached(UnitTestElement test, Lazy tests, HashSet fixtureTests) { +#if NET8_0_OR_GREATER + ApplicationStateGuard.Ensure(System.Runtime.CompilerServices.RuntimeFeature.IsDynamicCodeSupported, "Fixture tests are not supported in NativeAOT mode."); +#endif string assemblyName = testMethodInfo.Parent.Parent.Assembly.GetName().Name!; string assemblyLocation = testMethodInfo.Parent.Parent.Assembly.Location; string className = testMethodInfo.Parent.ClassType.Name; diff --git a/src/Adapter/MSTest.TestAdapter/Execution/TypeCache.cs b/src/Adapter/MSTest.TestAdapter/Execution/TypeCache.cs index eb6124cf9d..f4b42cdd0d 100644 --- a/src/Adapter/MSTest.TestAdapter/Execution/TypeCache.cs +++ b/src/Adapter/MSTest.TestAdapter/Execution/TypeCache.cs @@ -257,6 +257,7 @@ private static bool TryGetUnescapedManagedTypeName(TestMethod testMethod, [NotNu /// The class Type. /// The test Method. /// The . + [UnconditionalSuppressMessage("Aot", "IL2070:DoNotUseGetConstructor", Justification = "We access all the types we need in metadata, so this is preserved and works.")] private TestClassInfo CreateClassInfo(Type classType, TestMethod testMethod) { IEnumerable constructors = PlatformServiceProvider.Instance.ReflectionOperations.GetDeclaredConstructors(classType); @@ -832,6 +833,7 @@ private MethodInfo GetMethodInfoForTestMethod(TestMethod testMethod, TestClassIn return testMethodInfo; } + [UnconditionalSuppressMessage("Aot", "IL2026:DoNotUseGetConstructor", Justification = "We access all the types we need in metadata, so this is preserved and works.")] private static MethodInfo? GetMethodInfoUsingManagedNameHelper(TestMethod testMethod, TestClassInfo testClassInfo, bool discoverInternals) { MethodBase? methodBase = null; diff --git a/src/Adapter/MSTest.TestAdapter/Helpers/DataSerializationHelper.cs b/src/Adapter/MSTest.TestAdapter/Helpers/DataSerializationHelper.cs index 0b9e1bc782..8485b1a943 100644 --- a/src/Adapter/MSTest.TestAdapter/Helpers/DataSerializationHelper.cs +++ b/src/Adapter/MSTest.TestAdapter/Helpers/DataSerializationHelper.cs @@ -2,6 +2,7 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System.Collections.Concurrent; +using System.Diagnostics.CodeAnalysis; using System.Runtime.Serialization.Json; using System.Text; @@ -23,6 +24,14 @@ internal static class DataSerializationHelper /// /// Data array to serialize. /// Serialized array. + [UnconditionalSuppressMessage( + "Trimming", + "IL2026:Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code", + Justification = "This should be safe as long as our generator mentions getting fields / properties of the target type. https://github.com/dotnet/runtime/issues/71350#issuecomment-1168140551. Not the best solution, maybe we can replace this with System.Text.Json, but the we need one generator calling the other.")] + [UnconditionalSuppressMessage( + "AOT", + "IL3050:Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling.", + Justification = "This should be safe as long as our generator mentions getting fields / properties of the target type. https://github.com/dotnet/runtime/issues/71350#issuecomment-1168140551. Not the best solution, maybe we can replace this with System.Text.Json, but the we need one generator calling the other.")] public static string?[]? Serialize(object?[]? data) { if (data == null) @@ -51,14 +60,7 @@ internal static class DataSerializationHelper DataContractJsonSerializer serializer = GetSerializer(type); using var memoryStream = new MemoryStream(); - // This should be safe as long as our generator mentions - // getting fields / properties of the target type. https://github.com/dotnet/runtime/issues/71350#issuecomment-1168140551 - // Not the best solution, maybe we can replace this with System.Text.Json, but the we need one generator calling the other. -#pragma warning disable IL3050 // IL3050: Avoid calling members annotated with 'RequiresDynamicCodeAttribute' when publishing as Native AOT -#pragma warning disable IL2026 // IL2026: Members attributed with RequiresUnreferencedCode may break when trimming serializer.WriteObject(memoryStream, data[i]); -#pragma warning restore IL3050 // IL3050: Avoid calling members annotated with 'RequiresDynamicCodeAttribute' when publishing as Native AOT -#pragma warning restore IL2026 // IL2026: Members attributed with RequiresUnreferencedCode may break when trimming byte[] serializerData = memoryStream.ToArray(); serializedData[dataIndex] = Encoding.UTF8.GetString(serializerData, 0, serializerData.Length); @@ -72,6 +74,14 @@ internal static class DataSerializationHelper /// /// Serialized data array to deserialize. /// Deserialized array. + [UnconditionalSuppressMessage( + "Trimming", + "IL2026:Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code", + Justification = "This should be safe as long as our generator mentions getting fields / properties of the target type. https://github.com/dotnet/runtime/issues/71350#issuecomment-1168140551. Not the best solution, maybe we can replace this with System.Text.Json, but the we need one generator calling the other.")] + [UnconditionalSuppressMessage( + "AOT", + "IL3050:Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling.", + Justification = "This should be safe as long as our generator mentions getting fields / properties of the target type. https://github.com/dotnet/runtime/issues/71350#issuecomment-1168140551. Not the best solution, maybe we can replace this with System.Text.Json, but the we need one generator calling the other.")] public static object?[]? Deserialize(string?[]? serializedData) { if (serializedData == null || serializedData.Length % 2 != 0) @@ -98,40 +108,36 @@ internal static class DataSerializationHelper byte[] serializedDataBytes = Encoding.UTF8.GetBytes(serializedValue); using var memoryStream = new MemoryStream(serializedDataBytes); - // This should be safe as long as our generator mentions - // getting fields / properties of the target type. https://github.com/dotnet/runtime/issues/71350#issuecomment-1168140551 - // Not the best solution, maybe we can replace this with System.Text.Json, but the we need one generator calling the other. -#pragma warning disable IL3050 // IL3050: Avoid calling members annotated with 'RequiresDynamicCodeAttribute' when publishing as Native AOT -#pragma warning disable IL2026 // IL2026: Members attributed with RequiresUnreferencedCode may break when trimming data[i] = serializer.ReadObject(memoryStream); -#pragma warning restore IL3050 // IL3050: Avoid calling members annotated with 'RequiresDynamicCodeAttribute' when publishing as Native AOT -#pragma warning restore IL2026 // IL2026: Members attributed with RequiresUnreferencedCode may break when trimming } return data; } + [UnconditionalSuppressMessage( + "Trimming", + "IL2026:Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code", + Justification = "This should be safe as long as our generator mentions getting fields / properties of the target type. https://github.com/dotnet/runtime/issues/71350#issuecomment-1168140551. Not the best solution, maybe we can replace this with System.Text.Json, but the we need one generator calling the other.")] + [UnconditionalSuppressMessage( + "AOT", + "IL3050:Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling.", + Justification = "This should be safe as long as our generator mentions getting fields / properties of the target type. https://github.com/dotnet/runtime/issues/71350#issuecomment-1168140551. Not the best solution, maybe we can replace this with System.Text.Json, but the we need one generator calling the other.")] + private static DataContractJsonSerializer GetSerializer(string assemblyQualifiedName) => SerializerCache.GetOrAdd( assemblyQualifiedName, - // This should be safe as long as our generator mentions - // getting fields / properties of the target type. https://github.com/dotnet/runtime/issues/71350#issuecomment-1168140551 - // Not the best solution, maybe we can replace this with System.Text.Json, but the we need one generator calling the other. -#pragma warning disable IL3050 // IL3050: Avoid calling members annotated with 'RequiresDynamicCodeAttribute' when publishing as Native AOT -#pragma warning disable IL2026 // IL2026: Members attributed with RequiresUnreferencedCode may break when trimming _ => new DataContractJsonSerializer(PlatformServiceProvider.Instance.ReflectionOperations.GetType(assemblyQualifiedName) ?? typeof(object), SerializerSettings)); -#pragma warning restore IL3050 // IL3050: Avoid calling members annotated with 'RequiresDynamicCodeAttribute' when publishing as Native AOT -#pragma warning restore IL2026 // IL2026: Members attributed with RequiresUnreferencedCode may break when trimming + [UnconditionalSuppressMessage( + "Trimming", + "IL2026:Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code", + Justification = "This should be safe as long as our generator mentions getting fields / properties of the target type. https://github.com/dotnet/runtime/issues/71350#issuecomment-1168140551. Not the best solution, maybe we can replace this with System.Text.Json, but the we need one generator calling the other.")] + [UnconditionalSuppressMessage( + "AOT", + "IL3050:Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling.", + Justification = "This should be safe as long as our generator mentions getting fields / properties of the target type. https://github.com/dotnet/runtime/issues/71350#issuecomment-1168140551. Not the best solution, maybe we can replace this with System.Text.Json, but the we need one generator calling the other.")] private static DataContractJsonSerializer GetSerializer(Type type) => SerializerCache.GetOrAdd( type.AssemblyQualifiedName!, - // This should be safe as long as our generator mentions - // getting fields / properties of the target type. https://github.com/dotnet/runtime/issues/71350#issuecomment-1168140551 - // Not the best solution, maybe we can replace this with System.Text.Json, but the we need one generator calling the other. -#pragma warning disable IL3050 // IL3050: Avoid calling members annotated with 'RequiresDynamicCodeAttribute' when publishing as Native AOT -#pragma warning disable IL2026 // IL2026: Members attributed with RequiresUnreferencedCode may break when trimming _ => new DataContractJsonSerializer(type, SerializerSettings)); -#pragma warning restore IL3050 // IL3050: Avoid calling members annotated with 'RequiresDynamicCodeAttribute' when publishing as Native AOT -#pragma warning restore IL2026 // IL2026: Members attributed with RequiresUnreferencedCode may break when trimming } diff --git a/src/Adapter/MSTest.TestAdapter/MSTest.TestAdapter.csproj b/src/Adapter/MSTest.TestAdapter/MSTest.TestAdapter.csproj index fb25147250..3fcfe3fb6b 100644 --- a/src/Adapter/MSTest.TestAdapter/MSTest.TestAdapter.csproj +++ b/src/Adapter/MSTest.TestAdapter/MSTest.TestAdapter.csproj @@ -12,7 +12,7 @@ - $(EnableIotAnalyzers) + true diff --git a/src/Adapter/MSTest.TestAdapter/TestMethodFilter.cs b/src/Adapter/MSTest.TestAdapter/TestMethodFilter.cs index 1076988370..4297ee00be 100644 --- a/src/Adapter/MSTest.TestAdapter/TestMethodFilter.cs +++ b/src/Adapter/MSTest.TestAdapter/TestMethodFilter.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 System.Diagnostics.CodeAnalysis; using System.Reflection; using Microsoft.VisualStudio.TestPlatform.ObjectModel; @@ -118,6 +119,7 @@ internal TestProperty PropertyProvider(string propertyName) /// Discovery context. /// The logger to log exception messages too. /// Filter expression. + [UnconditionalSuppressMessage("Aot", "IL2072:DoNotUseDynamicMembers", Justification = "Tested it, it works.")] private ITestCaseFilterExpression? GetTestCaseFilterFromDiscoveryContext(IDiscoveryContext context, IMessageLogger logger) { try diff --git a/src/Adapter/MSTest.TestAdapter/TestingPlatformAdapter/TestingPlatformBuilderHook.cs b/src/Adapter/MSTest.TestAdapter/TestingPlatformAdapter/TestingPlatformBuilderHook.cs index befda48370..7379df8e12 100644 --- a/src/Adapter/MSTest.TestAdapter/TestingPlatformAdapter/TestingPlatformBuilderHook.cs +++ b/src/Adapter/MSTest.TestAdapter/TestingPlatformAdapter/TestingPlatformBuilderHook.cs @@ -11,6 +11,17 @@ namespace Microsoft.VisualStudio.TestTools.UnitTesting; public static class TestingPlatformBuilderHook { #pragma warning disable IDE0060 // Remove unused parameter - public static void AddExtensions(ITestApplicationBuilder testApplicationBuilder, string[] arguments) => testApplicationBuilder.AddMSTest(() => [Assembly.GetEntryAssembly()!]); + public static void AddExtensions(ITestApplicationBuilder testApplicationBuilder, string[] arguments) + { +#if NET8_0_OR_GREATER + if (!System.Runtime.CompilerServices.RuntimeFeature.IsDynamicCodeSupported) + { + // We don't have a reliable way to get reference to the entry dll when compiled as NativeAOT. So instead we do the same registration + // in source generator. + return; + } +#endif + testApplicationBuilder.AddMSTest(() => [Assembly.GetEntryAssembly()!]); + } } #endif diff --git a/src/Adapter/MSTestAdapter.PlatformServices/AssemblyResolver.cs b/src/Adapter/MSTestAdapter.PlatformServices/AssemblyResolver.cs index 59ae87d210..913d3784f9 100644 --- a/src/Adapter/MSTestAdapter.PlatformServices/AssemblyResolver.cs +++ b/src/Adapter/MSTestAdapter.PlatformServices/AssemblyResolver.cs @@ -3,6 +3,7 @@ #if NETFRAMEWORK || NET using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Reflection; #if NETFRAMEWORK using System.Runtime.InteropServices.WindowsRuntime; @@ -291,16 +292,14 @@ private static #endif bool DoesFileExist(string filePath) => File.Exists(filePath); + [UnconditionalSuppressMessage("Aot", "IL2026:DoNotUseGetDefinedTypes", Justification = "The whole class is not used in source generator mode.")] + #if NETFRAMEWORK protected virtual #else private static #endif - - // This whole class is not used in source generator mode. -#pragma warning disable IL2026 // Members attributed with RequiresUnreferencedCode may break when trimming Assembly LoadAssemblyFrom(string path) => Assembly.LoadFrom(path); -#pragma warning restore IL2026 // Members attributed with RequiresUnreferencedCode may break when trimming #if NETFRAMEWORK protected virtual Assembly ReflectionOnlyLoadAssemblyFrom(string path) => Assembly.ReflectionOnlyLoadFrom(path); diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Services/DiaSessionOperations.cs b/src/Adapter/MSTestAdapter.PlatformServices/Services/DiaSessionOperations.cs index dd44632e3a..0e008cca6e 100644 --- a/src/Adapter/MSTestAdapter.PlatformServices/Services/DiaSessionOperations.cs +++ b/src/Adapter/MSTestAdapter.PlatformServices/Services/DiaSessionOperations.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 System.Diagnostics.CodeAnalysis; using System.Reflection; namespace Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices; @@ -33,15 +34,17 @@ static DiaSessionOperations() /// /// The source file. /// A Navigation session instance for the current platform. + [UnconditionalSuppressMessage( + "ReflectionAnalysis", + "IL2077", + Justification = "")] internal static object? CreateNavigationSession(string source) { // Create instance only when DiaSession is found in Object Model. if (s_typeDiaSession != null && s_typeDiaNavigationData != null) { string messageFormatOnException = string.Join("MSTestDiscoverer:DiaSession: Could not create diaSession for source:", source, ". Reason:{0}"); -#pragma warning disable IL2077 // 'target parameter' argument does not satisfy 'DynamicallyAccessedMembersAttribute' in call to 'target method'. return SafeInvoke(() => Activator.CreateInstance(s_typeDiaSession, source)); -#pragma warning restore IL2077 // 'target parameter' argument does not satisfy 'DynamicallyAccessedMembersAttribute' in call to 'target method'. } return null; @@ -90,23 +93,27 @@ internal static void DisposeNavigationSession(object? navigationSession) /// /// Type name of DiaSession class. /// Type name of DiaNavigationData class. + [UnconditionalSuppressMessage( + "ReflectionAnalysis", + "IL2057", + Justification = "")] + [UnconditionalSuppressMessage( + "ReflectionAnalysis", + "IL2077", + Justification = "")] internal static void Initialize(string diaSession, string diaNavigationData) { // We won't reach this code, in we will generate this info in source generator, // and we won't use navigation session to get method locations from PDBs. -#pragma warning disable IL2057 // Unrecognized value passed to the typeName parameter of 'System.Type.GetType(String)' s_typeDiaSession = Type.GetType(diaSession, false); s_typeDiaNavigationData = Type.GetType(diaNavigationData, false); -#pragma warning restore IL2057 // Unrecognized value passed to the typeName parameter of 'System.Type.GetType(String)' -#pragma warning disable IL2077 // 'target parameter' argument does not satisfy 'DynamicallyAccessedMembersAttribute' in call to 'target method'. if (s_typeDiaSession != null && s_typeDiaNavigationData != null) { s_methodGetNavigationData = s_typeDiaSession.GetRuntimeMethod("GetNavigationData", [typeof(string), typeof(string)]); s_propertyFileName = s_typeDiaNavigationData.GetRuntimeProperty("FileName"); s_propertyMinLineNumber = s_typeDiaNavigationData.GetRuntimeProperty("MinLineNumber"); } -#pragma warning restore IL2077 // 'target parameter' argument does not satisfy 'DynamicallyAccessedMembersAttribute' in call to 'target method'. } private static object? SafeInvoke(Func action) diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Services/FileOperations.cs b/src/Adapter/MSTestAdapter.PlatformServices/Services/FileOperations.cs index 82064d7c5b..d857acf508 100644 --- a/src/Adapter/MSTestAdapter.PlatformServices/Services/FileOperations.cs +++ b/src/Adapter/MSTestAdapter.PlatformServices/Services/FileOperations.cs @@ -2,6 +2,7 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System.Collections.Concurrent; +using System.Diagnostics.CodeAnalysis; using System.Reflection; #if WIN_UI @@ -81,12 +82,10 @@ public Assembly LoadAssembly(string assemblyName, bool isReflectionOnly) /// /// The assembly. /// Path to the .DLL of the assembly. + [UnconditionalSuppressMessage("Aot", "IL3000:DoNotUseLocation", Justification = "This method will never be called in source generator mode, we are providing a different provider for file operations.")] public string? GetAssemblyPath(Assembly assembly) #if NETSTANDARD || NETCOREAPP || NETFRAMEWORK - // This method will never be called in source generator mode, we are providing a different provider for file operations. -#pragma warning disable IL3000 // Avoid accessing Assembly file path when publishing as a single file => assembly.Location; -#pragma warning disable IL3000 // Avoid accessing Assembly file path when publishing as a single file #elif WINDOWS_UWP => null; // TODO: what are the options here? #endif diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Services/ReflectionOperations2.cs b/src/Adapter/MSTestAdapter.PlatformServices/Services/ReflectionOperations2.cs index 8f74a3e352..7d4275663b 100644 --- a/src/Adapter/MSTestAdapter.PlatformServices/Services/ReflectionOperations2.cs +++ b/src/Adapter/MSTestAdapter.PlatformServices/Services/ReflectionOperations2.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 System.Diagnostics.CodeAnalysis; using System.Reflection; using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Interface; @@ -19,47 +20,83 @@ public ReflectionOperations2() #endif } -#pragma warning disable IL2070 // this' argument does not satisfy 'DynamicallyAccessedMembersAttribute' in call to 'target method'. -#pragma warning disable IL2026 // Members attributed with RequiresUnreferencedCode may break when trimming -#pragma warning disable IL2067 // 'target parameter' argument does not satisfy 'DynamicallyAccessedMembersAttribute' in call to 'target method'. -#pragma warning disable IL2057 // Unrecognized value passed to the typeName parameter of 'System.Type.GetType(String)' + [UnconditionalSuppressMessage( + "ReflectionAnalysis", + "IL2070", + Justification = "")] public IEnumerable GetDeclaredConstructors(Type classType) => classType.GetTypeInfo().DeclaredConstructors; + [UnconditionalSuppressMessage( + "ReflectionAnalysis", + "IL2070", + Justification = "")] public MethodInfo? GetDeclaredMethod(Type type, string methodName) => type.GetTypeInfo().GetDeclaredMethod(methodName); + [UnconditionalSuppressMessage( + "ReflectionAnalysis", + "IL2070", + Justification = "")] public IEnumerable GetDeclaredMethods(Type classType) => classType.GetTypeInfo().DeclaredMethods; + [UnconditionalSuppressMessage( + "ReflectionAnalysis", + "IL2070", + Justification = "")] public IEnumerable GetDeclaredProperties(Type type) => type.GetTypeInfo().DeclaredProperties; + [UnconditionalSuppressMessage( + "ReflectionAnalysis", + "IL2070", + Justification = "")] public PropertyInfo? GetDeclaredProperty(Type type, string propertyName) => type.GetTypeInfo().GetDeclaredProperty(propertyName); + [UnconditionalSuppressMessage("Aot", "IL2026:DoNotUseGetDefinedTypes", Justification = "We access all the types we need in metadata, so this is preserved and works.")] + public Type[] GetDefinedTypes(Assembly assembly) => assembly.DefinedTypes.ToArray(); + [UnconditionalSuppressMessage( + "Trimming", + "IL2067", + Justification = "")] public IEnumerable GetRuntimeMethods(Type type) => type.GetRuntimeMethods(); + [UnconditionalSuppressMessage( + "ReflectionAnalysis", + "IL2067", + Justification = "")] public MethodInfo? GetRuntimeMethod(Type declaringType, string methodName, Type[] parameters) => declaringType.GetRuntimeMethod(methodName, parameters); + [UnconditionalSuppressMessage( + "ReflectionAnalysis", + "IL2070", + Justification = "")] public PropertyInfo? GetRuntimeProperty(Type classType, string testContextPropertyName) => classType.GetProperty(testContextPropertyName); + [UnconditionalSuppressMessage("Aot", "IL2026:DoNotUseGetDefinedTypes", Justification = "We access all the types we need in metadata, so this is preserved and works.")] + [UnconditionalSuppressMessage( + "ReflectionAnalysis", + "IL2057", + Justification = "")] public Type? GetType(string typeName) => Type.GetType(typeName); + [UnconditionalSuppressMessage("Aot", "IL2026:DoNotUseGetDefinedTypes", Justification = "We access all the types we need in metadata, so this is preserved and works.")] public Type? GetType(Assembly assembly, string typeName) => assembly.GetType(typeName); + [UnconditionalSuppressMessage( + "ReflectionAnalysis", + "IL2067", + Justification = "")] public object? CreateInstance(Type type, object?[] parameters) => Activator.CreateInstance(type, parameters); -#pragma warning restore IL2070 // this' argument does not satisfy 'DynamicallyAccessedMembersAttribute' in call to 'target method'. -#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)' } diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Services/TestSourceHost.cs b/src/Adapter/MSTestAdapter.PlatformServices/Services/TestSourceHost.cs index 482c4f9b94..4cb8e3641f 100644 --- a/src/Adapter/MSTestAdapter.PlatformServices/Services/TestSourceHost.cs +++ b/src/Adapter/MSTestAdapter.PlatformServices/Services/TestSourceHost.cs @@ -360,6 +360,7 @@ internal virtual string GetTargetFrameworkVersionString(string sourceFileName) /// /// A list of path. /// + [UnconditionalSuppressMessage("Aot", "IL3000:DoNotUseLocation", Justification = " We check for the empty path, and in single file mode, or on source gen mode we allow loading dependencies only from the current folder, which is what the default loader handles by itself.")] internal virtual List GetResolutionPaths(string sourceFileName, bool isPortableMode) { List resolutionPaths = @@ -388,9 +389,6 @@ internal virtual List GetResolutionPaths(string sourceFileName, bool isP #endif } - // We check for the empty path, and in single file mode, or on source gen mode we don't allow - // loading dependencies than from the current folder, which is what the default loader handles by itself. -#pragma warning disable IL3000 // Avoid accessing Assembly file path when publishing as a single file if (!string.IsNullOrEmpty(typeof(TestSourceHost).Assembly.Location)) { // Adding adapter folder to resolution paths @@ -408,7 +406,6 @@ internal virtual List GetResolutionPaths(string sourceFileName, bool isP resolutionPaths.Add(Path.GetDirectoryName(typeof(AssemblyHelper).Assembly.Location)!); } } -#pragma warning restore IL3000 // Avoid accessing Assembly file path when publishing as a single file return resolutionPaths; } diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Utilities/DeploymentUtilityBase.cs b/src/Adapter/MSTestAdapter.PlatformServices/Utilities/DeploymentUtilityBase.cs index 0fbcabc78e..659955756b 100644 --- a/src/Adapter/MSTestAdapter.PlatformServices/Utilities/DeploymentUtilityBase.cs +++ b/src/Adapter/MSTestAdapter.PlatformServices/Utilities/DeploymentUtilityBase.cs @@ -126,6 +126,7 @@ public static string GetTestResultsDirectory(IRunContext? runContext) => !String /// The deployment directory. /// Root results directory. /// Returns a list of deployment warnings. + [UnconditionalSuppressMessage("Aot", "IL3000:DoNotUseLocation", Justification = "Deployment feature is not available in native.")] protected IEnumerable Deploy(IList deploymentItems, string testSource, string deploymentDirectory, string resultsDirectory) { Guard.NotNullOrWhiteSpace(deploymentDirectory); @@ -186,10 +187,7 @@ protected IEnumerable Deploy(IList deploymentItems, stri // Ignore the test platform files. string tempFile = Path.GetFileName(fileToDeploy); - // We throw when we run in source gen mode. -#pragma warning disable IL3000 // Avoid accessing Assembly file path when publishing as a single file string assemblyName = Path.GetFileName(GetType().Assembly.Location); -#pragma warning restore IL3000 // Avoid accessing Assembly file path when publishing as a single file if (tempFile.Equals(assemblyName, StringComparison.OrdinalIgnoreCase)) { continue; diff --git a/src/Package/MSTest.Sdk/MSTest.Sdk.csproj b/src/Package/MSTest.Sdk/MSTest.Sdk.csproj index 9df47c1e9a..aca0d75d36 100644 --- a/src/Package/MSTest.Sdk/MSTest.Sdk.csproj +++ b/src/Package/MSTest.Sdk/MSTest.Sdk.csproj @@ -35,7 +35,7 @@ - <_TemplateProperties>MSTestEngineVersion=$(MSTestEngineVersion);MSTestVersion=$(Version);MicrosoftTestingPlatformVersion=$(Version.Replace('$(VersionPrefix)', '$(TestingPlatformVersionPrefix)'));MicrosoftTestingEntrepriseExtensionsVersion=$(MicrosoftTestingInternalFrameworkVersion);MicrosoftNETTestSdkVersion=$(MicrosoftNETTestSdkVersion);MicrosoftTestingExtensionsCodeCoverageVersion=$(MicrosoftTestingExtensionsCodeCoverageVersion);MicrosoftPlaywrightVersion=$(MicrosoftPlaywrightVersion);AspireHostingTestingVersion=$(AspireHostingTestingVersion) + <_TemplateProperties>MSTestSourceGenerationVersion=$(MSTestSourceGenerationVersion);MSTestVersion=$(Version);MicrosoftTestingPlatformVersion=$(Version.Replace('$(VersionPrefix)', '$(TestingPlatformVersionPrefix)'));MicrosoftTestingEntrepriseExtensionsVersion=$(MicrosoftTestingInternalFrameworkVersion);MicrosoftNETTestSdkVersion=$(MicrosoftNETTestSdkVersion);MicrosoftTestingExtensionsCodeCoverageVersion=$(MicrosoftTestingExtensionsCodeCoverageVersion);MicrosoftPlaywrightVersion=$(MicrosoftPlaywrightVersion);AspireHostingTestingVersion=$(AspireHostingTestingVersion) - - + + Version="$(MSTestSourceGenerationVersion)" VersionOverride="$(MSTestSourceGenerationVersion)" /> - $(EnableIotAnalyzers) + true diff --git a/test/IntegrationTests/MSTest.Acceptance.IntegrationTests/MSTest.Acceptance.IntegrationTests.csproj b/test/IntegrationTests/MSTest.Acceptance.IntegrationTests/MSTest.Acceptance.IntegrationTests.csproj index 06e198a550..862499bcf9 100644 --- a/test/IntegrationTests/MSTest.Acceptance.IntegrationTests/MSTest.Acceptance.IntegrationTests.csproj +++ b/test/IntegrationTests/MSTest.Acceptance.IntegrationTests/MSTest.Acceptance.IntegrationTests.csproj @@ -22,8 +22,7 @@ - - + @@ -34,8 +33,7 @@ - - + diff --git a/test/IntegrationTests/MSTest.Acceptance.IntegrationTests/NativeAotTests.cs b/test/IntegrationTests/MSTest.Acceptance.IntegrationTests/NativeAotTests.cs index c0efb2bae8..aebfe91310 100644 --- a/test/IntegrationTests/MSTest.Acceptance.IntegrationTests/NativeAotTests.cs +++ b/test/IntegrationTests/MSTest.Acceptance.IntegrationTests/NativeAotTests.cs @@ -1,93 +1,457 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. +using System.Text.RegularExpressions; + using Microsoft.Testing.Platform.Acceptance.IntegrationTests; using Microsoft.Testing.Platform.Acceptance.IntegrationTests.Helpers; +using Microsoft.Testing.Platform.Helpers; namespace MSTest.Acceptance.IntegrationTests; [TestGroup] public class NativeAotTests : AcceptanceTestBase { - private const string SourceCode = """ -#file NativeAotTests.csproj - - - $TargetFramework$ - enable - enable - Exe - true - preview - true - - - - - - - - - -#file Program.cs -using System.Diagnostics; -using System.Reflection; -using System.Runtime.InteropServices; - -using Microsoft.Testing.Framework; -using Microsoft.Testing.Internal.Framework; -using Microsoft.Testing.Platform.Builder; -using Microsoft.Testing.Platform.Capabilities; -using Microsoft.Testing.Platform.Capabilities.TestFramework; -using Microsoft.Testing.Platform.Extensions.Messages; -using Microsoft.Testing.Platform.Extensions.TestFramework; - -using NativeAotTests; - -ITestApplicationBuilder builder = await TestApplication.CreateBuilderAsync(args); -builder.AddTestFramework(new SourceGeneratedTestNodesBuilder()); -using ITestApplication app = await builder.BuildAsync(); -return await app.RunAsync(); - -#file TestClass1.cs -using Microsoft.VisualStudio.TestTools.UnitTesting; - -namespace MyTests; - -[TestClass] -public class UnitTest1 -{ - [TestMethod] - public void TestMethod1() + private const string SourceCodeCsproj = """ + #file NativeAotTests.csproj + + + $TargetFramework$ + enable + enable + Exe + true + preview + true + + true + + + + + + + + + + + + + + """; + + private const string SourceCodeSimple = $$""" + {{SourceCodeCsproj}} + + #file TestClass1.cs + using Microsoft.VisualStudio.TestTools.UnitTesting; + + namespace MyTests; + + [TestClass] + public class UnitTest1 + { + [ClassInitialize] + public static void ClassInit(TestContext testContext) + { + } + + [ClassCleanup] + public static void ClassClean() + { + } + + [TestInitialize] + public void TestInit() + { + } + + [TestCleanup] + public void TestClean() + { + } + + [AssemblyInitialize] + public static void AssemblyInit(TestContext testContext) + { + } + + [AssemblyCleanup] + public static void AssemblyClean() + { + } + + [TestMethod] + public void TestMethod1() + { + } + + [TestMethod] + [DataRow(0, 1)] + public void TestMethod2(int a, int b) + { + } + + [TestMethod] + [DynamicData(nameof(Data))] + public void TestMethod3(int a, int b) + { + } + + public static IEnumerable Data { get; } + = new[] + { + new object[] { 1, 2 } + }; + } + """; + + private const string SourceCodeWithFailingAssert = $$""" + {{SourceCodeCsproj}} + + #file TestClass1.cs + using Microsoft.VisualStudio.TestTools.UnitTesting; + + namespace MyTests; + + [TestClass] + public class UnitTest1 + { + [ClassInitialize] + public static void ClassInit(TestContext testContext) + { + } + + [ClassCleanup] + public static void ClassClean() + { + } + + [TestInitialize] + public void TestInit() + { + } + + [TestCleanup] + public void TestClean() + { + } + + [AssemblyInitialize] + public static void AssemblyInit(TestContext testContext) + { + } + + [AssemblyCleanup] + public static void AssemblyClean() + { + } + + [TestMethod] + public void TestMethod1() + { + Assert.Fail("Failing TestMethod1"); + } + + [TestMethod] + [DataRow(0, 1)] + [DataRow(2, 3)] + public void TestMethod2(int a, int b) + { + if (a == 2) Assert.Fail("Failing a specific case of TestMethod2"); + } + + [TestMethod] + [DynamicData(nameof(Data))] + public void TestMethod3(int a, int b) + { + if (a == 2) Assert.Fail("Failing a specific case of TestMethod3"); + } + + public static IEnumerable Data { get; } + = new[] + { + new object[] { 1, 2 }, + new object[] { 2, 3 }, + }; + } + """; + + private const string SourceCodeWithDerivedTestClass = $$""" + {{SourceCodeCsproj}} + + #file TestClass1.cs + using Microsoft.VisualStudio.TestTools.UnitTesting; + + namespace MyTests; + + public class MyTestClassAttribute : TestClassAttribute { } + + [MyTestClass] + public class UnitTest1 + { + [TestMethod] + public void TestMethod1() + { + Assert.Fail("Failing TestMethod1"); + } + } + """; + + private const string SourceCodeWithFailingAssertClassIgnored = $$""" + {{SourceCodeCsproj}} + + #file TestClass1.cs + using Microsoft.VisualStudio.TestTools.UnitTesting; + + namespace MyTests; + + [TestClass] + [Ignore] + public class UnitTest1 + { + [TestMethod] + public void TestMethod1() + { + Assert.Fail("Failing TestMethod1"); + } + } + """; + + private const string SourceCodeWithFailingAssertMethodIgnored = $$""" + {{SourceCodeCsproj}} + + #file TestClass1.cs + using Microsoft.VisualStudio.TestTools.UnitTesting; + + namespace MyTests; + + [TestClass] + public class UnitTest1 + { + [TestMethod] + [Ignore] + public void TestMethod1() + { + Assert.Fail("Failing TestMethod1"); + } + } + """; + + private const string SourceCodeWithTestContext = $$""" + {{SourceCodeCsproj}} + + #file TestClass1.cs + using Microsoft.VisualStudio.TestTools.UnitTesting; + + namespace MyTests; + + [TestClass] + public class UnitTest1 + { + public TestContext TestContext { get; set; } = default!; + + [TestMethod] + public void TestMethod1() + { + TestContext.WriteLine("Writing to TestContext"); + TestContext.AddResultFile("C:\\file.txt"); + } + } + """; + + private const string SourceCodeWithIncompatibleLibrary = $$""" + #file TestProject/NativeAotTests.csproj + + + $TargetFramework$ + enable + enable + Exe + true + preview + true + $(NoWarn);IL2104;IL2026;IL3053 + + true + + + + + + + + + + + #file TestProject/TestClass1.cs + using Microsoft.VisualStudio.TestTools.UnitTesting; + + namespace MyTests; + + [TestClass] + public class UnitTest1 + { + [TestMethod] + public void TestMethod1() + { + Assert.IsTrue(TestBadLibrary.ClassToBeTested.M()); + } + } + + #file TestBadLibrary/TestBadLibrary.csproj + + + $TargetFramework$ + enable + enable + Library + preview + + + + #file TestBadLibrary/ClassToBeTested.cs + + using System; + using System.Diagnostics.CodeAnalysis; + using System.Reflection; + + namespace TestBadLibrary; + + public static class ClassToBeTested + { + [UnconditionalSuppressMessage("Trimming", "IL2075", Justification = "Intentionally not trimmer friendly. That is what we are testing ;)")] + public static bool M() + { + var asm = Assembly.GetExecutingAssembly(); + var type = asm.GetType("TestBadLibrary.ClassToBeTested"); + var m = type!.GetMethod("CalledByReflection"); + return (bool)m!.Invoke(null, null)!; + } + + private static bool CalledByReflection() + { + return true; + } + } + + """; + + private readonly AcceptanceFixture _acceptanceFixture; + + public NativeAotTests(ITestExecutionContext testExecutionContext, AcceptanceFixture acceptanceFixture) + : base(testExecutionContext) => _acceptanceFixture = acceptanceFixture; + + public async Task NativeAotTests_WillRunWithExitCodeZero() + { + TestHostResult result = await GetTestResultForCode(SourceCodeSimple); + result.AssertExitCodeIs(ExitCodes.Success); + } + + public async Task NativeAotTests_WillFailAsserts() + { + TestHostResult result = await GetTestResultForCode(SourceCodeWithFailingAssert); + result.AssertExitCodeIs(ExitCodes.AtLeastOneTestFailed); + + result.AssertOutputContains("failed TestMethod1"); + result.AssertOutputContains("Assert.Fail failed. Failing TestMethod1"); + + result.AssertOutputContains("failed TestMethod2 (2,3)"); + result.AssertOutputContains("Assert.Fail failed. Failing a specific case of TestMethod2"); + + result.AssertOutputContains("failed TestMethod3 (2,3)"); + result.AssertOutputContains("Assert.Fail failed. Failing a specific case of TestMethod3"); + + result.AssertOutputContainsSummary(failed: 3, passed: 2, skipped: 0); + } + + public async Task NativeAotTests_WillRespectIgnoreInClass() { + TestHostResult result = await GetTestResultForCode(SourceCodeWithFailingAssertClassIgnored); + result.AssertExitCodeIs(ExitCodes.ZeroTests); + result.AssertOutputContainsSummary(failed: 0, passed: 0, skipped: 1); } - [TestMethod] - [DataRow(0, 1)] - public void TestMethod2(int a, int b) + public async Task NativeAotTests_WillRespectIgnoreInMethod() { + TestHostResult result = await GetTestResultForCode(SourceCodeWithFailingAssertMethodIgnored); + result.AssertExitCodeIs(ExitCodes.ZeroTests); + result.AssertOutputContainsSummary(failed: 0, passed: 0, skipped: 1); } - [TestMethod] - [DynamicData(nameof(Data))] - public void TestMethod3(int a, int b) + public async Task NativeAotTests_DerivedTestClassAttribute_NotCurrentlySupported() { + TestHostResult result = await GetTestResultForCode(SourceCodeWithDerivedTestClass); + // TODO: Add 'wrong' asserts to document the current behavior. } - public static IEnumerable Data { get; } - = new[] + public async Task NativeAotTests_TestContext() + { + TestHostResult result = await GetTestResultForCode(SourceCodeWithTestContext, executeBeforeDisposingTestAsset: result => { - new object[] { 1, 2 } - }; -} -"""; + string trxPath = Regex.Match(result.StandardOutput, "- (.+?).trx").Value.Substring("- ".Length); + string trxContent = File.ReadAllText(trxPath); + Assert.Contains("Writing to TestContext", trxContent); + Assert.Contains(@"", trxContent); + }); - private readonly AcceptanceFixture _acceptanceFixture; + result.AssertExitCodeIs(ExitCodes.Success); + } - public NativeAotTests(ITestExecutionContext testExecutionContext, AcceptanceFixture acceptanceFixture) - : base(testExecutionContext) => _acceptanceFixture = acceptanceFixture; + public async Task NativeAotTests_WillFailBecauseTestedLibraryIsNotCompatible() + { + TestHostResult result = await GetTestResultForCode(SourceCodeWithIncompatibleLibrary, "TestProject"); + result.AssertExitCodeIs(ExitCodes.AtLeastOneTestFailed); - public async Task NativeAotTests_WillRunWithExitCodeZero() + result.AssertOutputContains("System.NullReferenceException: Object reference not set to an instance of an object."); + result.AssertOutputContains("TestBadLibrary.ClassToBeTested.M()"); + + result.AssertOutputContainsSummary(failed: 1, passed: 0, skipped: 0); + } + + public async Task NativeAotTests_WillFailInTestInitialize() + { + string code = ConstructFailingFixture("TestInitialize", isStatic: false, usesTestContext: false); + await NativeAotTests_WillFailInTestFixtureCommon(code); + } + + public async Task NativeAotTests_WillFailInTestCleanup() + { + string code = ConstructFailingFixture("TestCleanup", isStatic: false, usesTestContext: false); + await NativeAotTests_WillFailInTestFixtureCommon(code); + } + + public async Task NativeAotTests_WillFailInClassInitialize() + { + string code = ConstructFailingFixture("ClassInitialize", isStatic: true, usesTestContext: true); + await NativeAotTests_WillFailInTestFixtureCommon(code); + } + + public async Task NativeAotTests_WillFailInClassCleanup() + { + string code = ConstructFailingFixture("ClassCleanup", isStatic: true, usesTestContext: false); + await NativeAotTests_WillFailInTestFixtureCommon(code); + } + + public async Task NativeAotTests_WillFailInAssemblyInitialize() + { + string code = ConstructFailingFixture("AssemblyInitialize", isStatic: true, usesTestContext: true); + await NativeAotTests_WillFailInTestFixtureCommon(code); + } + + public async Task NativeAotTests_WillFailInAssemblyCleanup() + { + string code = ConstructFailingFixture("AssemblyCleanup", isStatic: true, usesTestContext: false); + await NativeAotTests_WillFailInTestFixtureCommon(code); + } + + private async Task GetTestResultForCode(string code, string? projectDir = null, Action? executeBeforeDisposingTestAsset = null) // The native AOT publication is pretty flaky and is often failing on CI with "fatal error LNK1136: invalid or corrupt file", // or sometimes doesn't fail but the native code generation is not done. // Retrying the restore/publish on fresh asset seems to be more effective than retrying on the same asset. @@ -96,27 +460,64 @@ public async Task NativeAotTests_WillRunWithExitCodeZero() { using TestAsset generator = await TestAsset.GenerateAssetAsync( "NativeAotTests", - SourceCode + code .PatchCodeWithReplace("$MicrosoftTestingPlatformVersion$", MicrosoftTestingPlatformVersion) .PatchCodeWithReplace("$MicrosoftTestingEnterpriseExtensionsVersion$", MicrosoftTestingEnterpriseExtensionsVersion) - .PatchCodeWithReplace("$TargetFramework$", TargetFrameworks.NetCurrent.Arguments) + // temporarily set test to be on net9.0 as it's fixing one error that started to happen: error IL3000: System.Net.Quic.MsQuicApi..cctor + // see https://github.com/dotnet/sdk/issues/44880. + .PatchCodeWithReplace("$TargetFramework$", "net9.0"/*TODO: TargetFrameworks.NetCurrent.Arguments*/) .PatchCodeWithReplace("$MSTestVersion$", MSTestVersion) - .PatchCodeWithReplace("$MSTestEngineVersion$", MSTestEngineVersion), + .PatchCodeWithReplace("$MSTestSourceGenerationVersion$", MSTestSourceGenerationVersion), addPublicFeeds: true); + string targetAssetPath = projectDir is null ? generator.TargetAssetPath : Path.Combine(generator.TargetAssetPath, projectDir); + await DotnetCli.RunAsync( - $"restore -m:1 -nodeReuse:false {generator.TargetAssetPath} -r {RID}", + $"restore -m:1 -nodeReuse:false {targetAssetPath} -r {RID}", _acceptanceFixture.NuGetGlobalPackagesFolder.Path, retryCount: 0); DotnetMuxerResult compilationResult = await DotnetCli.RunAsync( - $"publish -m:1 -nodeReuse:false {generator.TargetAssetPath} -r {RID}", + $"publish -m:1 -nodeReuse:false {targetAssetPath} -r {RID}", _acceptanceFixture.NuGetGlobalPackagesFolder.Path, + timeoutInSeconds: 100, retryCount: 0); compilationResult.AssertOutputContains("Generating native code"); - var testHost = TestHost.LocateFrom(generator.TargetAssetPath, "NativeAotTests", TargetFrameworks.NetCurrent.Arguments, RID, Verb.publish); + var testHost = TestHost.LocateFrom(targetAssetPath, "NativeAotTests", "net9.0"/*TODO: TargetFrameworks.NetCurrent.Arguments*/, RID, Verb.publish); - TestHostResult result = await testHost.ExecuteAsync(); - result.AssertExitCodeIs(0); + TestHostResult result = await testHost.ExecuteAsync("--report-trx"); + executeBeforeDisposingTestAsset?.Invoke(result); + return result; }, times: 15, every: TimeSpan.FromSeconds(5)); + + private async Task NativeAotTests_WillFailInTestFixtureCommon(string code) + { + TestHostResult result = await GetTestResultForCode(code); + result.AssertExitCodeIs(ExitCodes.AtLeastOneTestFailed); + result.AssertOutputContains("Assert.Fail failed. Fails in fixture"); + } + + private static string ConstructFailingFixture(string attributeName, bool isStatic, bool usesTestContext) => $$""" + {{SourceCodeCsproj}} + + #file TestClass1.cs + using Microsoft.VisualStudio.TestTools.UnitTesting; + + namespace MyTests; + + [TestClass] + public class UnitTest1 + { + [{{attributeName}}] + public{{(isStatic ? " static" : string.Empty)}} void FixtureMethod({{(usesTestContext ? "TestContext testContext" : string.Empty)}}) + { + Assert.Fail("Fails in fixture"); + } + + [TestMethod] + public void TestMethod1() + { + } + } + """; } diff --git a/test/IntegrationTests/Microsoft.Testing.Platform.Acceptance.IntegrationTests/Helpers/AcceptanceTestBase.cs b/test/IntegrationTests/Microsoft.Testing.Platform.Acceptance.IntegrationTests/Helpers/AcceptanceTestBase.cs index ddaf3bc633..78dbcef845 100644 --- a/test/IntegrationTests/Microsoft.Testing.Platform.Acceptance.IntegrationTests/Helpers/AcceptanceTestBase.cs +++ b/test/IntegrationTests/Microsoft.Testing.Platform.Acceptance.IntegrationTests/Helpers/AcceptanceTestBase.cs @@ -62,12 +62,12 @@ static AcceptanceTestBase() MSTestVersion = ExtractVersionFromVersionPropsFile(versionsPropFileDoc, "MSTestVersion"); MicrosoftTestingPlatformVersion = ExtractVersionFromVersionPropsFile(versionsPropFileDoc, "MSTestVersion"); MicrosoftTestingEnterpriseExtensionsVersion = ExtractVersionFromPackage(Constants.ArtifactsPackagesShipping, "Microsoft.Testing.Extensions."); - MSTestEngineVersion = ExtractVersionFromPackage(Constants.ArtifactsPackagesShipping, "MSTest.Engine"); + MSTestSourceGenerationVersion = ExtractVersionFromPackage(Constants.ArtifactsPackagesShipping, "MSTest.SourceGeneration"); #else MSTestVersion = ExtractVersionFromPackage(Constants.ArtifactsPackagesShipping, "MSTest.TestFramework."); MicrosoftTestingPlatformVersion = ExtractVersionFromPackage(Constants.ArtifactsPackagesShipping, "Microsoft.Testing.Platform."); MicrosoftTestingEnterpriseExtensionsVersion = ExtractVersionFromVersionPropsFile(versionsPropFileDoc, "MicrosoftTestingInternalFrameworkVersion"); - MSTestEngineVersion = ExtractVersionFromVersionPropsFile(versionsPropFileDoc, "MSTestEngineVersion"); + MSTestSourceGenerationVersion = ExtractVersionFromVersionPropsFile(versionsPropFileDoc, "MSTestSourceGenerationVersion"); #endif } @@ -80,7 +80,7 @@ protected AcceptanceTestBase(ITestExecutionContext testExecutionContext) public static string MSTestVersion { get; private set; } - public static string MSTestEngineVersion { get; private set; } + public static string MSTestSourceGenerationVersion { get; private set; } public static string MicrosoftNETTestSdkVersion { get; private set; } diff --git a/test/Utilities/Microsoft.Testing.TestInfrastructure/DebuggerUtility.cs b/test/Utilities/Microsoft.Testing.TestInfrastructure/DebuggerUtility.cs index ddb5ed161b..67aa959e55 100644 --- a/test/Utilities/Microsoft.Testing.TestInfrastructure/DebuggerUtility.cs +++ b/test/Utilities/Microsoft.Testing.TestInfrastructure/DebuggerUtility.cs @@ -98,9 +98,7 @@ private static bool AttachVs(Process vs, int pid, bool enableLog = false) IEnumMoniker? enumMoniker = null; try { -#pragma warning disable IL2050 int r = CreateBindCtx(0, out bindCtx); -#pragma warning restore IL2050 Marshal.ThrowExceptionForHR(r); if (bindCtx == null) {