Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve display name for DynamicDataAttribute #3293

Merged
merged 6 commits into from
Jul 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -88,9 +88,10 @@ internal ICollection<UnitTestElement> EnumerateAssembly(string assemblyFileName,
TestIdGenerationStrategy testIdGenerationStrategy = assembly.GetCustomAttribute<TestIdGenerationStrategyAttribute>()?.Strategy
?? TestIdGenerationStrategy.FullyQualified;

// Set the test ID generation strategy for the data row attribute so we can improve display name without causing
// a breaking change.
// Set the test ID generation strategy for DataRowAttribute and DynamicDataAttribute so we can improve display name without
// causing a breaking change.
DataRowAttribute.TestIdGenerationStrategy = testIdGenerationStrategy;
DynamicDataAttribute.TestIdGenerationStrategy = testIdGenerationStrategy;

TestDataSourceDiscoveryOption testDataSourceDiscovery = assembly.GetCustomAttribute<TestDataSourceDiscoveryAttribute>()?.DiscoveryOption
#pragma warning disable CS0618 // Type or member is obsolete
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
// 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.Collections;
using System.Globalization;
using System.Reflection;

using Microsoft.VisualStudio.TestTools.UnitTesting.Internal;

namespace Microsoft.VisualStudio.TestTools.UnitTesting;

/// <summary>
Expand Down Expand Up @@ -87,37 +88,6 @@ public DataRowAttribute(params object?[]? data)
: data.AsEnumerable();

return string.Format(CultureInfo.CurrentCulture, FrameworkMessages.DataDrivenResultDisplayName, methodInfo.Name,
string.Join(",", displayData.Select(GetObjectString)));
}

/// <summary>
/// Recursively resolve collections of objects to a proper string representation.
/// </summary>
private static string? GetObjectString(object? obj)
{
if (TestIdGenerationStrategy != TestIdGenerationStrategy.FullyQualified)
{
return obj?.ToString();
}

if (obj == null)
{
return "null";
}

if (!obj.GetType().IsArray)
{
return obj switch
{
string s => $"\"{s}\"",
char c => $"'{c}'",
_ => obj.ToString(),
};
}

// We need to box the object here so that we can support value types
IEnumerable<object> boxedObjectEnumerable = ((IEnumerable)obj).Cast<object>();
IEnumerable<string?> elementStrings = boxedObjectEnumerable.Select(GetObjectString);
return $"[{string.Join(",", elementStrings)}]";
string.Join(",", displayData.Select(x => TestDataSourceUtilities.GetHumanizedArguments(x, TestIdGenerationStrategy))));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
using System.Globalization;
using System.Reflection;

using Microsoft.VisualStudio.TestTools.UnitTesting.Internal;

namespace Microsoft.VisualStudio.TestTools.UnitTesting;

/// <summary>
Expand Down Expand Up @@ -73,6 +75,8 @@ public DynamicDataAttribute(string dynamicDataSourceName, Type dynamicDataDeclar
_dynamicDataDeclaringType = dynamicDataDeclaringType;
}

internal static TestIdGenerationStrategy TestIdGenerationStrategy { get; set; }

/// <summary>
/// Gets or sets the name of method used to customize the display name in test results.
/// </summary>
Expand Down Expand Up @@ -194,7 +198,7 @@ public IEnumerable<object[]> GetData(MethodInfo methodInfo)
// so that null do appear as "null". If you remove the call, and do string.Join(",", new object[] { null, "a" }),
// you will get empty string while with the call you will get "null,a".
return string.Format(CultureInfo.CurrentCulture, FrameworkMessages.DataDrivenResultDisplayName, methodInfo.Name,
string.Join(",", data.AsEnumerable()));
string.Join(",", data.AsEnumerable().Select(x => TestDataSourceUtilities.GetHumanizedArguments(x, TestIdGenerationStrategy))));
}

return null;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// 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.Collections;

namespace Microsoft.VisualStudio.TestTools.UnitTesting.Internal;

internal static class TestDataSourceUtilities
{
/// <summary>
/// Recursively resolve collections of objects to a proper string representation.
/// </summary>
/// <param name="data">The method arguments.</param>
/// <param name="testIdGenerationStrategy">The strategy for creating the test ID.</param>
/// <returns>The humanized representation of the data.</returns>
public static string? GetHumanizedArguments(object? data, TestIdGenerationStrategy testIdGenerationStrategy)
{
// To avoid breaking changes, we will return the string representation of the arguments if the testIdGenerationStrategy
// is not set to FullyQualified. This is the logic that was present in the previous implementation.
if (testIdGenerationStrategy != TestIdGenerationStrategy.FullyQualified)
{
return data?.ToString();
}

if (data is null)
{
return "null";
}

if (!data.GetType().IsArray)
{
return data switch
{
string s => $"\"{s}\"",
char c => $"'{c}'",
_ => data.ToString(),
};
}

// We need to box the object here so that we can support value types
IEnumerable<object> boxedObjectEnumerable = ((IEnumerable)data).Cast<object>();
IEnumerable<string?> elementStrings = boxedObjectEnumerable.Select(x => GetHumanizedArguments(x, testIdGenerationStrategy));
return $"[{string.Join(",", elementStrings)}]";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,37 +21,37 @@ public void ExecuteDynamicDataTests()
// Assert
VerifyE2E.TestsPassed(
testResults,
"DynamicDataTest_SourceMethod (John;Doe,LibProjectReferencedByDataSourceTest.User)",
"DynamicDataTest_SourceMethod (Jane;Doe,LibProjectReferencedByDataSourceTest.User)",
"DynamicDataTest_SourceProperty (John;Doe,LibProjectReferencedByDataSourceTest.User)",
"DynamicDataTest_SourceProperty (Jane;Doe,LibProjectReferencedByDataSourceTest.User)",
"Custom DynamicDataTestMethod DynamicDataTest_SourceMethod_CustomDisplayName with 2 parameters",
"DynamicDataTest_SourceProperty (\"John;Doe\",LibProjectReferencedByDataSourceTest.User)",
"Custom DynamicDataTestMethod DynamicDataTest_SourcePropertyOtherType_CustomDisplayName with 2 parameters",
"Custom DynamicDataTestMethod DynamicDataTest_SourceMethodOtherType_CustomDisplayName with 2 parameters",
"UserDynamicDataTestMethod DynamicDataTest_SourcePropertyOtherType_CustomDisplayNameOtherType with 2 parameters",
"Custom DynamicDataTestMethod DynamicDataTest_SourceMethod_CustomDisplayName with 2 parameters",
"Custom DynamicDataTestMethod DynamicDataTest_SourceProperty_CustomDisplayName with 2 parameters",
"UserDynamicDataTestMethod DynamicDataTest_SourceMethodOtherType_CustomDisplayNameOtherType with 2 parameters",
"DynamicDataTest_SourceMethod (\"Jane;Doe\",LibProjectReferencedByDataSourceTest.User)",
"UserDynamicDataTestMethod DynamicDataTest_SourcePropertyOtherType_CustomDisplayNameOtherType with 2 parameters",
"StackOverflowException_Example (DataSourceTestProject.DynamicDataTests+ExampleTestCase)",
"Custom DynamicDataTestMethod DynamicDataTest_SourceProperty_CustomDisplayName with 2 parameters",
"UserDynamicDataTestMethod DynamicDataTest_SourceMethod_CustomDisplayNameOtherType with 2 parameters",
"DynamicDataTest_SourceMethodOtherType (\"John;Doe\",LibProjectReferencedByDataSourceTest.User)",
"DynamicDataTest_SourceMethodOtherType (\"Jane;Doe\",LibProjectReferencedByDataSourceTest.User)",
"Custom DynamicDataTestMethod DynamicDataTest_SourceProperty_CustomDisplayName with 2 parameters",
"UserDynamicDataTestMethod DynamicDataTest_SourceMethod_CustomDisplayNameOtherType with 2 parameters",
"Custom DynamicDataTestMethod DynamicDataTest_SourceMethodOtherType_CustomDisplayName with 2 parameters",
"DynamicDataTest_SourcePropertyOtherType (\"John;Doe\",LibProjectReferencedByDataSourceTest.User)",
"DynamicDataTestWithTestCategory (\"Jane;Doe\",LibProjectReferencedByDataSourceTest.User)",
"DynamicDataTestWithTestCategory (\"John;Doe\",LibProjectReferencedByDataSourceTest.User)",
"UserDynamicDataTestMethod DynamicDataTest_SourceProperty_CustomDisplayNameOtherType with 2 parameters",
"UserDynamicDataTestMethod DynamicDataTest_SourceProperty_CustomDisplayNameOtherType with 2 parameters",
"DynamicDataTest_SourceMethodOtherType (John;Doe,LibProjectReferencedByDataSourceTest.User)",
"DynamicDataTest_SourceMethodOtherType (Jane;Doe,LibProjectReferencedByDataSourceTest.User)",
"DynamicDataTest_SourcePropertyOtherType (John;Doe,LibProjectReferencedByDataSourceTest.User)",
"DynamicDataTest_SourcePropertyOtherType (Jane;Doe,LibProjectReferencedByDataSourceTest.User)",
"Custom DynamicDataTestMethod DynamicDataTest_SourceMethodOtherType_CustomDisplayName with 2 parameters",
"Custom DynamicDataTestMethod DynamicDataTest_SourceMethodOtherType_CustomDisplayName with 2 parameters",
"UserDynamicDataTestMethod DynamicDataTest_SourceMethodOtherType_CustomDisplayNameOtherType with 2 parameters",
"UserDynamicDataTestMethod DynamicDataTest_SourceMethodOtherType_CustomDisplayNameOtherType with 2 parameters",
"Custom DynamicDataTestMethod DynamicDataTest_SourcePropertyOtherType_CustomDisplayName with 2 parameters",
"DynamicDataTest_SourceMethod (\"John;Doe\",LibProjectReferencedByDataSourceTest.User)",
"Custom DynamicDataTestMethod DynamicDataTest_SourcePropertyOtherType_CustomDisplayName with 2 parameters",
"UserDynamicDataTestMethod DynamicDataTest_SourcePropertyOtherType_CustomDisplayNameOtherType with 2 parameters",
"UserDynamicDataTestMethod DynamicDataTest_SourcePropertyOtherType_CustomDisplayNameOtherType with 2 parameters",
"DynamicDataTestWithTestCategory (John;Doe,LibProjectReferencedByDataSourceTest.User)",
"DynamicDataTestWithTestCategory (Jane;Doe,LibProjectReferencedByDataSourceTest.User)",
"StackOverflowException_Example (DataSourceTestProject.DynamicDataTests+ExampleTestCase)",
"MethodWithOverload (1,1)",
"MethodWithOverload (2,1)",
"MethodWithOverload (1,0)",
"MethodWithOverload (2,2)");
"UserDynamicDataTestMethod DynamicDataTest_SourceMethodOtherType_CustomDisplayNameOtherType with 2 parameters",
"DynamicDataTest_SourceProperty (\"Jane;Doe\",LibProjectReferencedByDataSourceTest.User)",
"DynamicDataTest_SourcePropertyOtherType (\"Jane;Doe\",LibProjectReferencedByDataSourceTest.User)",
"Custom DynamicDataTestMethod DynamicDataTest_SourceMethod_CustomDisplayName with 2 parameters",
"MethodWithOverload (\"1\",1)",
"MethodWithOverload (\"2\",1)",
"MethodWithOverload (1,\"0\")",
"MethodWithOverload (2,\"2\")");

VerifyE2E.FailedTestCount(testResults, 0);
}
Expand All @@ -68,8 +68,8 @@ public void ExecuteDynamicDataTestsWithCategoryFilter()
// Assert
VerifyE2E.ContainsTestsPassed(
testResults,
"DynamicDataTestWithTestCategory (John;Doe,LibProjectReferencedByDataSourceTest.User)",
"DynamicDataTestWithTestCategory (Jane;Doe,LibProjectReferencedByDataSourceTest.User)");
"DynamicDataTestWithTestCategory (\"John;Doe\",LibProjectReferencedByDataSourceTest.User)",
"DynamicDataTestWithTestCategory (\"Jane;Doe\",LibProjectReferencedByDataSourceTest.User)");

VerifyE2E.FailedTestCount(testResults, 0);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,9 @@ public void TestIdUniqueness_DynamicDataArrays_DefaultStrategy()
VerifyE2E.FailedTestCount(testResults, 0);
VerifyE2E.TestsPassed(
testResults,
"DynamicDataArraysTests (0,System.Int32[])",
"DynamicDataArraysTests (0,System.Int32[])",
"DynamicDataArraysTests (0,System.Int32[])");
"DynamicDataArraysTests (0,[])",
"DynamicDataArraysTests (0,[0])",
"DynamicDataArraysTests (0,[0,0,0])");

// We cannot assert the expected ID as it is path dependent
testResults.Select(x => x.TestCase.Id.ToString()).Should().OnlyHaveUniqueItems();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,9 @@ public void TestIdUniqueness_DynamicDataArrays_FullyQualifiedStrategy()
VerifyE2E.FailedTestCount(testResults, 0);
VerifyE2E.TestsPassed(
testResults,
"DynamicDataArraysTests (0,System.Int32[])",
"DynamicDataArraysTests (0,System.Int32[])",
"DynamicDataArraysTests (0,System.Int32[])");
"DynamicDataArraysTests (0,[])",
"DynamicDataArraysTests (0,[0])",
"DynamicDataArraysTests (0,[0,0,0])");

// We cannot assert the expected ID as it is path dependent
testResults.Select(x => x.TestCase.Id.ToString()).Should().OnlyHaveUniqueItems();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,16 @@ public void ExecuteDynamicDataExtensibilityTests()
{
InvokeVsTestForExecution([TestAssetName]);
ValidatePassedTestsContain(
"DynamicDataTestMethod1 (string,2,True)",
"DynamicDataTestMethod2 (string,4,True)",
"DynamicDataTestMethod3 (string,2,True)",
"DynamicDataTestMethod3 (string,4,True)");
"DynamicDataTestMethod1 (\"string\",2,True)",
"DynamicDataTestMethod2 (\"string\",4,True)",
"DynamicDataTestMethod3 (\"string\",2,True)",
"DynamicDataTestMethod3 (\"string\",4,True)");

ValidatePassedTestsContain(
"DynamicDataTestMethod4 (string,2,True)",
"DynamicDataTestMethod5 (string,4,True)",
"DynamicDataTestMethod6 (string,2,True)",
"DynamicDataTestMethod6 (string,4,True)");
"DynamicDataTestMethod4 (\"string\",2,True)",
"DynamicDataTestMethod5 (\"string\",4,True)",
"DynamicDataTestMethod6 (\"string\",2,True)",
"DynamicDataTestMethod6 (\"string\",4,True)");

ValidateFailedTestsContain(
false,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@ public void ExecuteDynamicDataTests()

// Assert
ValidatePassedTests(
"DynamicDataTest_SourceMethod (John;Doe,LibProjectReferencedByDataSourceTest.User)",
"DynamicDataTest_SourceMethod (Jane;Doe,LibProjectReferencedByDataSourceTest.User)",
"DynamicDataTest_SourceProperty (John;Doe,LibProjectReferencedByDataSourceTest.User)",
"DynamicDataTest_SourceProperty (Jane;Doe,LibProjectReferencedByDataSourceTest.User)",
"DynamicDataTest_SourceMethod (\"John;Doe\",LibProjectReferencedByDataSourceTest.User)",
"DynamicDataTest_SourceMethod (\"Jane;Doe\",LibProjectReferencedByDataSourceTest.User)",
"DynamicDataTest_SourceProperty (\"John;Doe\",LibProjectReferencedByDataSourceTest.User)",
"DynamicDataTest_SourceProperty (\"Jane;Doe\",LibProjectReferencedByDataSourceTest.User)",
"Custom DynamicDataTestMethod DynamicDataTest_SourceMethod_CustomDisplayName with 2 parameters",
"Custom DynamicDataTestMethod DynamicDataTest_SourceMethod_CustomDisplayName with 2 parameters",
"Custom DynamicDataTestMethod DynamicDataTest_SourceProperty_CustomDisplayName with 2 parameters",
Expand All @@ -30,25 +30,25 @@ public void ExecuteDynamicDataTests()
"UserDynamicDataTestMethod DynamicDataTest_SourceMethod_CustomDisplayNameOtherType with 2 parameters",
"UserDynamicDataTestMethod DynamicDataTest_SourceProperty_CustomDisplayNameOtherType with 2 parameters",
"UserDynamicDataTestMethod DynamicDataTest_SourceProperty_CustomDisplayNameOtherType with 2 parameters",
"DynamicDataTest_SourceMethodOtherType (John;Doe,LibProjectReferencedByDataSourceTest.User)",
"DynamicDataTest_SourceMethodOtherType (Jane;Doe,LibProjectReferencedByDataSourceTest.User)",
"DynamicDataTest_SourcePropertyOtherType (John;Doe,LibProjectReferencedByDataSourceTest.User)",
"DynamicDataTest_SourcePropertyOtherType (Jane;Doe,LibProjectReferencedByDataSourceTest.User)",
"DynamicDataTest_SourceMethodOtherType (\"John;Doe\",LibProjectReferencedByDataSourceTest.User)",
"DynamicDataTest_SourceMethodOtherType (\"Jane;Doe\",LibProjectReferencedByDataSourceTest.User)",
"DynamicDataTest_SourcePropertyOtherType (\"John;Doe\",LibProjectReferencedByDataSourceTest.User)",
"DynamicDataTest_SourcePropertyOtherType (\"Jane;Doe\",LibProjectReferencedByDataSourceTest.User)",
"Custom DynamicDataTestMethod DynamicDataTest_SourceMethodOtherType_CustomDisplayName with 2 parameters",
"Custom DynamicDataTestMethod DynamicDataTest_SourceMethodOtherType_CustomDisplayName with 2 parameters",
"UserDynamicDataTestMethod DynamicDataTest_SourceMethodOtherType_CustomDisplayNameOtherType with 2 parameters",
"UserDynamicDataTestMethod DynamicDataTest_SourceMethodOtherType_CustomDisplayNameOtherType with 2 parameters",
"Custom DynamicDataTestMethod DynamicDataTest_SourcePropertyOtherType_CustomDisplayName with 2 parameters",
"Custom DynamicDataTestMethod DynamicDataTest_SourcePropertyOtherType_CustomDisplayName with 2 parameters",
"UserDynamicDataTestMethod DynamicDataTest_SourceMethodOtherType_CustomDisplayNameOtherType with 2 parameters",
"UserDynamicDataTestMethod DynamicDataTest_SourceMethodOtherType_CustomDisplayNameOtherType with 2 parameters",
"UserDynamicDataTestMethod DynamicDataTest_SourcePropertyOtherType_CustomDisplayNameOtherType with 2 parameters",
"UserDynamicDataTestMethod DynamicDataTest_SourcePropertyOtherType_CustomDisplayNameOtherType with 2 parameters",
"DynamicDataTestWithTestCategory (John;Doe,LibProjectReferencedByDataSourceTest.User)",
"DynamicDataTestWithTestCategory (Jane;Doe,LibProjectReferencedByDataSourceTest.User)",
"DynamicDataTestWithTestCategory (\"John;Doe\",LibProjectReferencedByDataSourceTest.User)",
"DynamicDataTestWithTestCategory (\"Jane;Doe\",LibProjectReferencedByDataSourceTest.User)",
"StackOverflowException_Example (DataSourceTestProject.DynamicDataTests+ExampleTestCase)",
"MethodWithOverload (1,1)",
"MethodWithOverload (2,1)",
"MethodWithOverload (1,0)",
"MethodWithOverload (2,2)");
"MethodWithOverload (\"1\",1)",
"MethodWithOverload (\"2\",1)",
"MethodWithOverload (1,\"0\")",
"MethodWithOverload (2,\"2\")");

ValidateFailedTestsCount(0);
}
Expand Down
Loading