Skip to content

Commit

Permalink
Add support for ValueTuple for all target frameworks (microsoft#4360)
Browse files Browse the repository at this point in the history
  • Loading branch information
Evangelink committed Dec 16, 2024
1 parent d614132 commit 1866115
Show file tree
Hide file tree
Showing 9 changed files with 99 additions and 52 deletions.
3 changes: 2 additions & 1 deletion Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
<SystemNetWebSocketsClientVersion>4.3.1</SystemNetWebSocketsClientVersion>
<SystemTextRegularExpressionsVersion>4.3.1</SystemTextRegularExpressionsVersion>
<SystemThreadingTasksExtensionsVersion>4.5.4</SystemThreadingTasksExtensionsVersion>
<SystemValueTupleVersion>4.5.0</SystemValueTupleVersion>
</PropertyGroup>
<PropertyGroup Label="Test dependencies">
<MicrosoftCodeAnalysisAnalyzerTestingVersion>1.1.3-beta1.24423.1</MicrosoftCodeAnalysisAnalyzerTestingVersion>
Expand Down Expand Up @@ -53,7 +54,7 @@
<PackageVersion Include="System.Diagnostics.TextWriterTraceListener" Version="4.3.0" />
<!-- CVE-2019-0981, CVE-2019-0980, CVE-2019-0657 -->
<PackageVersion Include="System.Private.Uri" Version="4.3.2" />
<PackageVersion Include="System.ValueTuple" Version="4.5.0" />
<PackageVersion Include="System.ValueTuple" Version="$(SystemValueTupleVersion)" />
</ItemGroup>
<ItemGroup Label="Test dependencies">
<PackageVersion Include="Codecov" Version="1.12.3" />
Expand Down
3 changes: 3 additions & 0 deletions samples/Playground/DebuggerUtility.cs
Original file line number Diff line number Diff line change
@@ -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.

#if NETCOREAPP
#pragma warning disable CA1837 // Use 'Environment.ProcessId'
#pragma warning disable CA1416 // Validate platform compatibility

Expand Down Expand Up @@ -356,3 +357,5 @@ private static extern int NtQueryInformationProcess(
[DllImport("ole32.dll")]
private static extern int CreateBindCtx(uint reserved, out IBindCtx ppbc);
}

#endif
4 changes: 4 additions & 0 deletions samples/Playground/Playground.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@
<NoWarn>$(NoWarn);NETSDK1023</NoWarn>
</PropertyGroup>

<ItemGroup Condition=" '$(TargetFramework)' == 'net462' ">
<Compile Remove="ServerMode/**/*.cs" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="$(RepoRoot)src\Platform\Microsoft.Testing.Platform\Microsoft.Testing.Platform.csproj" />
<ProjectReference Include="$(RepoRoot)src\Adapter\MSTest.TestAdapter\MSTest.TestAdapter.csproj" />
Expand Down
11 changes: 9 additions & 2 deletions samples/Playground/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -25,8 +26,10 @@ public static async Task<int> Main(string[] args)

if (Environment.GetEnvironmentVariable("TESTSERVERMODE") != "1")
{
#if NETCOREAPP
// To attach to the children
Microsoft.Testing.TestInfrastructure.DebuggerUtility.AttachCurrentProcessToParentVSProcess();
#endif

ITestApplicationBuilder testApplicationBuilder = await TestApplication.CreateBuilderAsync(args);

Expand All @@ -49,6 +52,9 @@ public static async Task<int> 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!);

Expand All @@ -67,6 +73,7 @@ public static async Task<int> Main(string[] args)
await client.ExitAsync();

return 0;
#endif
}
}
}
Expand Down
15 changes: 9 additions & 6 deletions samples/Playground/Tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,16 @@ public class TestClass
public TestContext TestContext { get; set; }

[TestMethod]
public void Test() => TestContext.AddResultFile(@"c:\hello2");
[DynamicData(nameof(Data))]
public void Test3(int a, int b)
=> Assert.AreNotEqual(a, b);

[TestMethod]
public void Test2() => Assert.AreEqual(1, 0, "few");

[TestMethod]
public void Test3()
public static IEnumerable<(int A, int B)> Data
{
get
{
yield return (1, 2);
yield return (3, 4);
}
}
}
71 changes: 64 additions & 7 deletions src/Adapter/MSTest.TestAdapter/DynamicDataOperations.cs
Original file line number Diff line number Diff line change
@@ -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;

Expand Down Expand Up @@ -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<object[]> 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))
{
Expand All @@ -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
}
8 changes: 5 additions & 3 deletions src/Adapter/MSTest.TestAdapter/MSTest.TestAdapter.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,8 @@

<ItemGroup>
<PackageReference Include="Microsoft.TestPlatform.AdapterUtilities" />
<PackageReference Include="System.Threading.Tasks.Extensions" Condition="'$(TargetFramework)'=='netstandard2.0' OR '$(TargetFramework)' == '$(NetFrameworkMinimum)' OR '$(TargetFramework)'=='$(UwpMinimum)'" />
<PackageReference Include="System.Threading.Tasks.Extensions" Condition=" '$(TargetFramework)' == 'netstandard2.0' OR '$(TargetFramework)' == '$(NetFrameworkMinimum)' OR '$(TargetFramework)' == '$(UwpMinimum)' " />
<PackageReference Include="System.ValueTuple" Condition=" '$(TargetFramework)' == 'netstandard2.0' OR '$(TargetFramework)' == '$(NetFrameworkMinimum)' OR '$(TargetFramework)' == '$(UwpMinimum)' " />
</ItemGroup>

<ItemGroup>
Expand All @@ -81,11 +82,12 @@
</ItemGroup>

<ItemGroup Label="NuGet">
<NuspecProperty Include="RepoRoot=$(RepoRoot)" />
<NuspecProperty Include="ArtifactsBinDir=$(ArtifactsBinDir)" />
<NuspecProperty Include="Configuration=$(Configuration)" />
<NuspecProperty Include="TestingPlatformVersion=$(Version.Replace('$(VersionPrefix)', '$(TestingPlatformVersionPrefix)'))" />
<NuspecProperty Include="RepoRoot=$(RepoRoot)" />
<NuspecProperty Include="SystemThreadingTasksExtensionsVersion=$(SystemThreadingTasksExtensionsVersion)" />
<NuspecProperty Include="SystemValueTupleVersion=$(SystemValueTupleVersion)" />
<NuspecProperty Include="TestingPlatformVersion=$(Version.Replace('$(VersionPrefix)', '$(TestingPlatformVersionPrefix)'))" />
</ItemGroup>

<ItemGroup>
Expand Down
3 changes: 3 additions & 0 deletions src/Adapter/MSTest.TestAdapter/MSTest.TestAdapter.nuspec
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,17 @@
<dependency id="Microsoft.Testing.Extensions.VSTestBridge" version="$TestingPlatformVersion$" />
<dependency id="Microsoft.Testing.Platform.MSBuild" version="$TestingPlatformVersion$" />
<dependency id="System.Threading.Tasks.Extensions" version="$SystemThreadingTasksExtensionsVersion$" />
<dependency id="System.ValueTuple" version="$SystemValueTupleVersion$" />
</group>
<group targetFramework="net462">
<dependency id="Microsoft.Testing.Extensions.VSTestBridge" version="$TestingPlatformVersion$" />
<dependency id="Microsoft.Testing.Platform.MSBuild" version="$TestingPlatformVersion$" />
<dependency id="System.Threading.Tasks.Extensions" version="$SystemThreadingTasksExtensionsVersion$" />
<dependency id="System.ValueTuple" version="$SystemValueTupleVersion$" />
</group>
<group targetFramework="uap10.0">
<dependency id="System.Threading.Tasks.Extensions" version="$SystemThreadingTasksExtensionsVersion$" />
<dependency id="System.ValueTuple" version="$SystemValueTupleVersion$" />
</group>
<group targetFramework="netcoreapp3.1">
<dependency id="Microsoft.Testing.Extensions.VSTestBridge" version="$TestingPlatformVersion$" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand Down Expand Up @@ -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<ArgumentNullException>(() => dynamicDataAttribute.GetData(testMethodInfo));

dynamicDataAttribute = new DynamicDataAttribute(nameof(TestClassTupleData.GetDataWithTuple), typeof(TestClassTupleData), DynamicDataSourceType.Method);
VerifyThrows<ArgumentNullException>(() => 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<ArgumentNullException>(() => dynamicDataAttribute.GetData(testMethodInfo));

dynamicDataAttribute = new DynamicDataAttribute(nameof(TestClassTupleData.GetDataWithValueTuple), typeof(TestClassTupleData), DynamicDataSourceType.Method);
VerifyThrows<ArgumentNullException>(() => 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<ArgumentNullException>(() => dynamicDataAttribute.GetData(testMethodInfo));

dynamicDataAttribute = new DynamicDataAttribute(nameof(TestClassTupleData.GetDataWithValueTupleWithTupleSyntax), typeof(TestClassTupleData), DynamicDataSourceType.Method);
VerifyThrows<ArgumentNullException>(() => dynamicDataAttribute.GetData(testMethodInfo));
}
#endif
}

/// <summary>
Expand Down

0 comments on commit 1866115

Please sign in to comment.