From 7c8a82da751c9e1bdd5a69c05dd715dd4dacd657 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Amaury=20Lev=C3=A9?= Date: Mon, 16 Dec 2024 13:59:36 +0100 Subject: [PATCH 1/3] Add support for ValueTuple for all target frameworks --- Directory.Packages.props | 3 +- samples/Playground/DebuggerUtility.cs | 5 +- samples/Playground/Playground.csproj | 4 ++ samples/Playground/Program.cs | 13 +++- samples/Playground/Tests.cs | 16 +++-- .../DynamicDataOperations.cs | 71 +++++++++++++++++-- .../MSTest.TestAdapter.csproj | 8 ++- .../MSTest.TestAdapter.nuspec | 3 + 8 files changed, 102 insertions(+), 21 deletions(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index 2be713e468..6bd3d0c5d4 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -22,6 +22,7 @@ 4.3.1 4.3.1 4.5.4 + 4.5.0 1.1.3-beta1.24423.1 @@ -53,7 +54,7 @@ - + diff --git a/samples/Playground/DebuggerUtility.cs b/samples/Playground/DebuggerUtility.cs index 6b58a2a58d..b31de7b1ad 100644 --- a/samples/Playground/DebuggerUtility.cs +++ b/samples/Playground/DebuggerUtility.cs @@ -1,4 +1,5 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +#if NETCOREAPP +// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. #pragma warning disable CA1837 // Use 'Environment.ProcessId' @@ -356,3 +357,5 @@ private static extern int NtQueryInformationProcess( [DllImport("ole32.dll")] private static extern int CreateBindCtx(uint reserved, out IBindCtx ppbc); } + +#endif diff --git a/samples/Playground/Playground.csproj b/samples/Playground/Playground.csproj index f60b5e923c..f83ced76c8 100644 --- a/samples/Playground/Playground.csproj +++ b/samples/Playground/Playground.csproj @@ -8,6 +8,10 @@ $(NoWarn);NETSDK1023 + + + + diff --git a/samples/Playground/Program.cs b/samples/Playground/Program.cs index dfa263bd6e..cfd0054792 100644 --- a/samples/Playground/Program.cs +++ b/samples/Playground/Program.cs @@ -8,12 +8,13 @@ using Microsoft.Testing.Platform.Extensions.TestFramework; using Microsoft.Testing.Platform.Extensions.TestHostControllers; using Microsoft.Testing.Platform.Messages; +#if NETCOREAPP using Microsoft.Testing.Platform.ServerMode.IntegrationTests.Messages.V100; +using MSTest.Acceptance.IntegrationTests.Messages.V100; +#endif using Microsoft.Testing.Platform.TestHost; using Microsoft.VisualStudio.TestTools.UnitTesting; -using MSTest.Acceptance.IntegrationTests.Messages.V100; - namespace Playground; public class Program @@ -25,8 +26,10 @@ public static async Task Main(string[] args) if (Environment.GetEnvironmentVariable("TESTSERVERMODE") != "1") { +#if NETCOREAPP // To attach to the children - Microsoft.Testing.TestInfrastructure.DebuggerUtility.AttachCurrentProcessToParentVSProcess(); + Microsoft.Testing.TestInfrastructure.DebuggerUtility.AttachCurrentProcessToParentVSProcess(); +#endif ITestApplicationBuilder testApplicationBuilder = await TestApplication.CreateBuilderAsync(args); @@ -49,6 +52,9 @@ public static async Task Main(string[] args) } else { +#if NETFRAMEWORK + throw new NotSupportedException("Server mode is not supported on .NET Framework"); +#else Environment.SetEnvironmentVariable("TESTSERVERMODE", "0"); using TestingPlatformClient client = await TestingPlatformClientFactory.StartAsServerAndConnectToTheClientAsync(Environment.ProcessPath!); @@ -67,6 +73,7 @@ public static async Task Main(string[] args) await client.ExitAsync(); return 0; +#endif } } } diff --git a/samples/Playground/Tests.cs b/samples/Playground/Tests.cs index eb480d750f..0b080496da 100644 --- a/samples/Playground/Tests.cs +++ b/samples/Playground/Tests.cs @@ -15,13 +15,17 @@ public class TestClass public TestContext TestContext { get; set; } [TestMethod] - public void Test() => TestContext.AddResultFile(@"c:\hello2"); - - [TestMethod] - public void Test2() => Assert.AreEqual(1, 0, "few"); + [DynamicData(nameof(Data))] + public void Test3(int a, int b) + { + } - [TestMethod] - public void Test3() + public static IEnumerable<(int, int)> Data { + get + { + yield return (1, 2); + yield return (3, 4); + } } } diff --git a/src/Adapter/MSTest.TestAdapter/DynamicDataOperations.cs b/src/Adapter/MSTest.TestAdapter/DynamicDataOperations.cs index a666067292..10485ab7c3 100644 --- a/src/Adapter/MSTest.TestAdapter/DynamicDataOperations.cs +++ b/src/Adapter/MSTest.TestAdapter/DynamicDataOperations.cs @@ -1,15 +1,15 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. -using Microsoft.VisualStudio.TestTools.UnitTesting; - -#if NET471_OR_GREATER || NETCOREAPP using System.Collections; -using System.Runtime.CompilerServices; -#endif using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Reflection; +#if NET471_OR_GREATER || NETCOREAPP +using System.Runtime.CompilerServices; +#endif + +using Microsoft.VisualStudio.TestTools.UnitTesting; namespace Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter; @@ -129,12 +129,12 @@ private static bool TryGetData(object dataSource, [NotNullWhen(true)] out IEnume return true; } -#if NETCOREAPP || NET471_OR_GREATER if (dataSource is IEnumerable enumerable) { List objects = new(); foreach (object? entry in enumerable) { +#if NET471_OR_GREATER || NETCOREAPP if (entry is not ITuple tuple || (objects.Count > 0 && objects[^1].Length != tuple.Length)) { @@ -149,14 +149,71 @@ private static bool TryGetData(object dataSource, [NotNullWhen(true)] out IEnume } objects.Add(array); +#else + Type type = entry.GetType(); + if (!IsTupleOrValueTuple(entry.GetType(), out int tupleSize) + || (objects.Count > 0 && objects[objects.Count - 1].Length != tupleSize)) + { + data = null; + return false; + } + + object[] array = new object[tupleSize]; + for (int i = 0; i < tupleSize; i++) + { + array[i] = type.GetField($"Item{i + 1}")?.GetValue(entry)!; + } + + objects.Add(array); +#endif } data = objects; return true; } -#endif data = null; return false; } + +#if !NET471_OR_GREATER && !NETCOREAPP + private static bool IsTupleOrValueTuple(Type type, out int tupleSize) + { + tupleSize = 0; + if (!type.IsGenericType) + { + return false; + } + + Type genericTypeDefinition = type.GetGenericTypeDefinition(); + + if (genericTypeDefinition == typeof(Tuple<>) || + genericTypeDefinition == typeof(Tuple<,>) || + genericTypeDefinition == typeof(Tuple<,,>) || + genericTypeDefinition == typeof(Tuple<,,,>) || + genericTypeDefinition == typeof(Tuple<,,,,>) || + genericTypeDefinition == typeof(Tuple<,,,,,>) || + genericTypeDefinition == typeof(Tuple<,,,,,,>) || + genericTypeDefinition == typeof(Tuple<,,,,,,,>)) + { + tupleSize = type.GetGenericArguments().Length; + return true; + } + + if (genericTypeDefinition == typeof(ValueTuple<>) || + genericTypeDefinition == typeof(ValueTuple<,>) || + genericTypeDefinition == typeof(ValueTuple<,,>) || + genericTypeDefinition == typeof(ValueTuple<,,,>) || + genericTypeDefinition == typeof(ValueTuple<,,,,>) || + genericTypeDefinition == typeof(ValueTuple<,,,,,>) || + genericTypeDefinition == typeof(ValueTuple<,,,,,,>) || + genericTypeDefinition == typeof(ValueTuple<,,,,,,,>)) + { + tupleSize = type.GetGenericArguments().Length; + return true; + } + + return false; + } +#endif } diff --git a/src/Adapter/MSTest.TestAdapter/MSTest.TestAdapter.csproj b/src/Adapter/MSTest.TestAdapter/MSTest.TestAdapter.csproj index 61b5a1173c..0174d645d9 100644 --- a/src/Adapter/MSTest.TestAdapter/MSTest.TestAdapter.csproj +++ b/src/Adapter/MSTest.TestAdapter/MSTest.TestAdapter.csproj @@ -57,7 +57,8 @@ - + + @@ -81,11 +82,12 @@ - - + + + diff --git a/src/Adapter/MSTest.TestAdapter/MSTest.TestAdapter.nuspec b/src/Adapter/MSTest.TestAdapter/MSTest.TestAdapter.nuspec index fab41babbc..549cd6e8c8 100644 --- a/src/Adapter/MSTest.TestAdapter/MSTest.TestAdapter.nuspec +++ b/src/Adapter/MSTest.TestAdapter/MSTest.TestAdapter.nuspec @@ -7,14 +7,17 @@ + + + From 73cb18a26a51c2981bff49f33c99bcade7e3a0ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Amaury=20Lev=C3=A9?= Date: Mon, 16 Dec 2024 15:25:09 +0100 Subject: [PATCH 2/3] Fix playground --- samples/Playground/DebuggerUtility.cs | 4 ++-- samples/Playground/Program.cs | 2 +- samples/Playground/Tests.cs | 5 ++--- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/samples/Playground/DebuggerUtility.cs b/samples/Playground/DebuggerUtility.cs index b31de7b1ad..55fb8c75eb 100644 --- a/samples/Playground/DebuggerUtility.cs +++ b/samples/Playground/DebuggerUtility.cs @@ -1,7 +1,7 @@ -#if NETCOREAPP -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. +#if NETCOREAPP #pragma warning disable CA1837 // Use 'Environment.ProcessId' #pragma warning disable CA1416 // Validate platform compatibility diff --git a/samples/Playground/Program.cs b/samples/Playground/Program.cs index cfd0054792..82315191c2 100644 --- a/samples/Playground/Program.cs +++ b/samples/Playground/Program.cs @@ -28,7 +28,7 @@ public static async Task Main(string[] args) { #if NETCOREAPP // To attach to the children - Microsoft.Testing.TestInfrastructure.DebuggerUtility.AttachCurrentProcessToParentVSProcess(); + Microsoft.Testing.TestInfrastructure.DebuggerUtility.AttachCurrentProcessToParentVSProcess(); #endif ITestApplicationBuilder testApplicationBuilder = await TestApplication.CreateBuilderAsync(args); diff --git a/samples/Playground/Tests.cs b/samples/Playground/Tests.cs index 0b080496da..ffd007f386 100644 --- a/samples/Playground/Tests.cs +++ b/samples/Playground/Tests.cs @@ -17,10 +17,9 @@ public class TestClass [TestMethod] [DynamicData(nameof(Data))] public void Test3(int a, int b) - { - } + => Assert.AreNotEqual(a, b); - public static IEnumerable<(int, int)> Data + public static IEnumerable<(int A, int B)> Data { get { From efcec49286230dc1fbd4a4839ce4b0ba31f95758 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Amaury=20Lev=C3=A9?= Date: Mon, 16 Dec 2024 15:56:27 +0100 Subject: [PATCH 3/3] Fix UTs --- .../DynamicDataAttributeTests.cs | 33 ------------------- 1 file changed, 33 deletions(-) diff --git a/test/UnitTests/MSTestAdapter.UnitTests/DynamicDataAttributeTests.cs b/test/UnitTests/MSTestAdapter.UnitTests/DynamicDataAttributeTests.cs index cad1caf3e4..866b30d657 100644 --- a/test/UnitTests/MSTestAdapter.UnitTests/DynamicDataAttributeTests.cs +++ b/test/UnitTests/MSTestAdapter.UnitTests/DynamicDataAttributeTests.cs @@ -240,7 +240,6 @@ public void GetDisplayNameForMultipleArraysOfArraysOfMultipleItems() Verify(displayName == "TestMethod1 ([[\"a\",\"b\",\"c\"],[\"d\",\"e\",\"f\"],[\"gh\",\"ij\",\"kl\"]],['m','n','o'],[[\"1\",\"2\",\"3\"],[\"4\",\"5\",\"6\"],[\"7\",\"8\",\"9\"]])"); } -#if NETCOREAPP public void DynamicDataSource_WithTuple_Works() { MethodInfo testMethodInfo = new TestClassTupleData().GetType().GetTypeInfo().GetDeclaredMethod(nameof(TestClassTupleData.DynamicDataTestWithTuple)); @@ -270,38 +269,6 @@ public void DynamicDataSource_WithValueTupleWithTupleSyntax_Works() dynamicDataAttribute = new DynamicDataAttribute(nameof(TestClassTupleData.GetDataWithValueTupleWithTupleSyntax), typeof(TestClassTupleData), DynamicDataSourceType.Method); dynamicDataAttribute.GetData(testMethodInfo); } -#else - public void DynamicDataSource_WithTuple_Throws() - { - MethodInfo testMethodInfo = new TestClassTupleData().GetType().GetTypeInfo().GetDeclaredMethod(nameof(TestClassTupleData.DynamicDataTestWithTuple)); - var dynamicDataAttribute = new DynamicDataAttribute(nameof(TestClassTupleData.DataWithTuple), typeof(TestClassTupleData), DynamicDataSourceType.Property); - - VerifyThrows(() => dynamicDataAttribute.GetData(testMethodInfo)); - - dynamicDataAttribute = new DynamicDataAttribute(nameof(TestClassTupleData.GetDataWithTuple), typeof(TestClassTupleData), DynamicDataSourceType.Method); - VerifyThrows(() => dynamicDataAttribute.GetData(testMethodInfo)); - } - - public void DynamicDataSource_WithValueTuple_Throws() - { - MethodInfo testMethodInfo = new TestClassTupleData().GetType().GetTypeInfo().GetDeclaredMethod(nameof(TestClassTupleData.DynamicDataTestWithTuple)); - var dynamicDataAttribute = new DynamicDataAttribute(nameof(TestClassTupleData.DataWithValueTuple), typeof(TestClassTupleData), DynamicDataSourceType.Property); - VerifyThrows(() => dynamicDataAttribute.GetData(testMethodInfo)); - - dynamicDataAttribute = new DynamicDataAttribute(nameof(TestClassTupleData.GetDataWithValueTuple), typeof(TestClassTupleData), DynamicDataSourceType.Method); - VerifyThrows(() => dynamicDataAttribute.GetData(testMethodInfo)); - } - - public void DynamicDataSource_WithValueTupleWithTupleSyntax_Throws() - { - MethodInfo testMethodInfo = new TestClassTupleData().GetType().GetTypeInfo().GetDeclaredMethod(nameof(TestClassTupleData.DynamicDataTestWithTuple)); - var dynamicDataAttribute = new DynamicDataAttribute(nameof(TestClassTupleData.DataWithValueTupleWithTupleSyntax), typeof(TestClassTupleData), DynamicDataSourceType.Property); - VerifyThrows(() => dynamicDataAttribute.GetData(testMethodInfo)); - - dynamicDataAttribute = new DynamicDataAttribute(nameof(TestClassTupleData.GetDataWithValueTupleWithTupleSyntax), typeof(TestClassTupleData), DynamicDataSourceType.Method); - VerifyThrows(() => dynamicDataAttribute.GetData(testMethodInfo)); - } -#endif } ///