diff --git a/src/Adapter/MSTest.TestAdapter/TestingPlatformAdapter/TestApplicationBuilderExtensions.cs b/src/Adapter/MSTest.TestAdapter/TestingPlatformAdapter/TestApplicationBuilderExtensions.cs
index 436ce80215..326c85f88f 100644
--- a/src/Adapter/MSTest.TestAdapter/TestingPlatformAdapter/TestApplicationBuilderExtensions.cs
+++ b/src/Adapter/MSTest.TestAdapter/TestingPlatformAdapter/TestApplicationBuilderExtensions.cs
@@ -2,7 +2,7 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#if !WINDOWS_UWP
-using Microsoft.Testing.Extensions.VSTestBridge.Capabilities;
+using Microsoft.Testing.Extensions.TrxReport.Abstractions;
using Microsoft.Testing.Extensions.VSTestBridge.Helpers;
using Microsoft.Testing.Platform.Builder;
using Microsoft.Testing.Platform.Capabilities.TestFramework;
@@ -17,6 +17,17 @@ namespace Microsoft.VisualStudio.TestTools.UnitTesting;
[SuppressMessage("ApiDesign", "RS0030:Do not use banned APIs", Justification = "We can use MTP from this folder")]
public static class TestApplicationBuilderExtensions
{
+ // NOTE: We intentionally use this class and not VSTestBridgeExtensionBaseCapabilities because
+ // we don't want MSTest to use vstestProvider capability
+ private sealed class MSTestCapabilities : ITrxReportCapability
+ {
+ bool ITrxReportCapability.IsSupported { get; } = true;
+
+ void ITrxReportCapability.Enable()
+ {
+ }
+ }
+
///
/// Register MSTest as the test framework and register the necessary services.
///
@@ -34,7 +45,7 @@ public static void AddMSTest(this ITestApplicationBuilder testApplicationBuilder
testApplicationBuilder.AddRunSettingsEnvironmentVariableProvider(extension);
testApplicationBuilder.RegisterTestFramework(
serviceProvider => new TestFrameworkCapabilities(
- new VSTestBridgeExtensionBaseCapabilities(),
+ new MSTestCapabilities(),
#pragma warning disable TPEXP // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
new MSTestBannerCapability(serviceProvider.GetRequiredService()),
MSTestGracefulStopTestExecutionCapability.Instance),
diff --git a/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Capabilities/VSTestBridgeExtensionBaseCapabilities.cs b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Capabilities/VSTestBridgeExtensionBaseCapabilities.cs
index b9cb3dcdb4..5b2b690303 100644
--- a/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Capabilities/VSTestBridgeExtensionBaseCapabilities.cs
+++ b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Capabilities/VSTestBridgeExtensionBaseCapabilities.cs
@@ -9,6 +9,10 @@ namespace Microsoft.Testing.Extensions.VSTestBridge.Capabilities;
///
/// The VSTest bridged test framework capabilities.
///
+// NOTE: MSTest no longer uses this, as we don't want to use the vstestProvider.
+// Only NUnit and Expecto use this.
+// https://github.com/nunit/nunit3-vs-adapter/blob/3d0f824243aaaeb85621d3c7dddc92e7a7c45097/src/NUnitTestAdapter/TestingPlatformAdapter/TestApplicationBuilderExtensions.cs#L20
+// https://github.com/YoloDev/YoloDev.Expecto.TestSdk/blob/0d1a3eadd65b605f61bb01d302f28382be76b8ac/src/YoloDev.Expecto.TestSdk/TestApplicationHelpers.fs#L16
public sealed class VSTestBridgeExtensionBaseCapabilities : ITrxReportCapability, IVSTestFlattenedTestNodesReportCapability, INamedFeatureCapability
{
private const string VSTestProviderSupport = "vstestProvider";
diff --git a/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Microsoft.Testing.Extensions.VSTestBridge.csproj b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Microsoft.Testing.Extensions.VSTestBridge.csproj
index a3d08254e9..fd51a85275 100644
--- a/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Microsoft.Testing.Extensions.VSTestBridge.csproj
+++ b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Microsoft.Testing.Extensions.VSTestBridge.csproj
@@ -12,6 +12,7 @@
+
diff --git a/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/ObjectModel/FrameworkHandlerAdapter.cs b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/ObjectModel/FrameworkHandlerAdapter.cs
index 2d992b1e77..f28f435f65 100644
--- a/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/ObjectModel/FrameworkHandlerAdapter.cs
+++ b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/ObjectModel/FrameworkHandlerAdapter.cs
@@ -4,6 +4,8 @@
#pragma warning disable TPEXP // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
using Microsoft.Testing.Extensions.VSTestBridge.Helpers;
+using Microsoft.Testing.Platform.Capabilities.TestFramework;
+using Microsoft.Testing.Platform.CommandLine;
using Microsoft.Testing.Platform.Extensions.Messages;
using Microsoft.Testing.Platform.Logging;
using Microsoft.Testing.Platform.Messages;
@@ -30,15 +32,26 @@ internal sealed class FrameworkHandlerAdapter : IFrameworkHandle
private readonly IMessageBus _messageBus;
private readonly VSTestBridgedTestFrameworkBase _adapterExtensionBase;
private readonly TestSessionContext _session;
- private readonly IClientInfo _clientInfo;
private readonly CancellationToken _cancellationToken;
private readonly bool _isTrxEnabled;
private readonly MessageLoggerAdapter _comboMessageLogger;
private readonly string _testAssemblyPath;
-
- public FrameworkHandlerAdapter(VSTestBridgedTestFrameworkBase adapterExtensionBase, TestSessionContext session, IClientInfo clientInfo, string[] testAssemblyPaths,
- ITestApplicationModuleInfo testApplicationModuleInfo, ILoggerFactory loggerFactory, IMessageBus messageBus, IOutputDevice outputDevice,
- bool isTrxEnabled, CancellationToken cancellationToken, IFrameworkHandle? frameworkHandle = null)
+ private readonly INamedFeatureCapability? _namedFeatureCapability;
+ private readonly ICommandLineOptions _commandLineOptions;
+
+ public FrameworkHandlerAdapter(
+ VSTestBridgedTestFrameworkBase adapterExtensionBase,
+ TestSessionContext session,
+ string[] testAssemblyPaths,
+ ITestApplicationModuleInfo testApplicationModuleInfo,
+ INamedFeatureCapability? namedFeatureCapability,
+ ICommandLineOptions commandLineOptions,
+ IMessageBus messageBus,
+ IOutputDevice outputDevice,
+ ILoggerFactory loggerFactory,
+ bool isTrxEnabled,
+ CancellationToken cancellationToken,
+ IFrameworkHandle? frameworkHandle = null)
{
if (testAssemblyPaths.Length == 0)
{
@@ -58,12 +71,13 @@ public FrameworkHandlerAdapter(VSTestBridgedTestFrameworkBase adapterExtensionBa
_testAssemblyPath = testAssemblyPaths[0];
}
+ _namedFeatureCapability = namedFeatureCapability;
+ _commandLineOptions = commandLineOptions;
_frameworkHandle = frameworkHandle;
_logger = loggerFactory.CreateLogger();
_messageBus = messageBus;
_adapterExtensionBase = adapterExtensionBase;
_session = session;
- _clientInfo = clientInfo;
_cancellationToken = cancellationToken;
_isTrxEnabled = isTrxEnabled;
_comboMessageLogger = new MessageLoggerAdapter(loggerFactory, outputDevice, adapterExtensionBase, frameworkHandle);
@@ -126,7 +140,7 @@ public void RecordResult(TestResult testResult)
_frameworkHandle?.RecordResult(testResult);
// Publish node state change to Microsoft Testing Platform
- var testNode = testResult.ToTestNode(_isTrxEnabled, _clientInfo);
+ var testNode = testResult.ToTestNode(_isTrxEnabled, _namedFeatureCapability, _commandLineOptions);
var testNodeChange = new TestNodeUpdateMessage(_session.SessionUid, testNode);
_messageBus.PublishAsync(_adapterExtensionBase, testNodeChange).Await();
@@ -145,7 +159,7 @@ public void RecordStart(TestCase testCase)
_frameworkHandle?.RecordStart(testCase);
// Publish node state change to Microsoft Testing Platform
- var testNode = testCase.ToTestNode(_isTrxEnabled, _clientInfo);
+ var testNode = testCase.ToTestNode(_isTrxEnabled, _namedFeatureCapability, _commandLineOptions);
testNode.Properties.Add(InProgressTestNodeStateProperty.CachedInstance);
var testNodeChange = new TestNodeUpdateMessage(_session.SessionUid, testNode);
diff --git a/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/ObjectModel/ObjectModelConverters.cs b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/ObjectModel/ObjectModelConverters.cs
index 46343a7174..046d03c7b9 100644
--- a/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/ObjectModel/ObjectModelConverters.cs
+++ b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/ObjectModel/ObjectModelConverters.cs
@@ -5,9 +5,12 @@
using Microsoft.Testing.Extensions.TrxReport.Abstractions;
using Microsoft.Testing.Platform;
+using Microsoft.Testing.Platform.Capabilities.TestFramework;
+using Microsoft.Testing.Platform.CommandLine;
using Microsoft.Testing.Platform.Extensions.Messages;
-using Microsoft.Testing.Platform.Services;
-using Microsoft.Testing.Platform.TestHost;
+using Microsoft.Testing.Platform.ServerMode;
+using Microsoft.TestPlatform.AdapterUtilities;
+using Microsoft.TestPlatform.AdapterUtilities.ManagedNameUtilities;
using Microsoft.VisualStudio.TestPlatform.ObjectModel;
namespace Microsoft.Testing.Extensions.VSTestBridge.ObjectModel;
@@ -21,10 +24,34 @@ internal static class ObjectModelConverters
VSTestTestNodeProperties.OriginalExecutorUriPropertyName, VSTestTestNodeProperties.OriginalExecutorUriPropertyName,
typeof(Uri), typeof(TestNode));
+ private static readonly TestProperty ManagedTypeProperty = TestProperty.Register(
+ id: "TestCase.ManagedType",
+ label: "TestCase.ManagedType",
+ valueType: typeof(string),
+ owner: typeof(TestCase));
+
+ private static readonly TestProperty ManagedMethodProperty = TestProperty.Register(
+ id: "TestCase.ManagedMethod",
+ label: "TestCase.ManagedMethod",
+ valueType: typeof(string),
+ owner: typeof(TestCase));
+
+ private static readonly TestProperty TestCategoryProperty = TestProperty.Register(
+ id: "MSTestDiscoverer.TestCategory",
+ label: "TestCategory",
+ valueType: typeof(string[]),
+ owner: typeof(TestCase));
+
+ private static readonly TestProperty TraitsProperty = TestProperty.Register(
+ id: "TestObject.Traits",
+ label: "Traits",
+ valueType: typeof(KeyValuePair[]),
+ owner: typeof(TestObject));
+
///
/// Converts a VSTest to a Microsoft Testing Platform .
///
- public static TestNode ToTestNode(this TestCase testCase, bool isTrxEnabled, IClientInfo client, string? displayNameFromTestResult = null)
+ public static TestNode ToTestNode(this TestCase testCase, bool isTrxEnabled, INamedFeatureCapability? namedFeatureCapability, ICommandLineOptions commandLineOptions, string? displayNameFromTestResult = null)
{
string testNodeUid = testCase.Id.ToString();
@@ -34,7 +61,19 @@ public static TestNode ToTestNode(this TestCase testCase, bool isTrxEnabled, ICl
DisplayName = displayNameFromTestResult ?? testCase.DisplayName ?? testCase.FullyQualifiedName,
};
- CopyVSTestProperties(testCase.Properties, testNode, testCase, testCase.GetPropertyValue, isTrxEnabled, client);
+ // This will be false for Expecto and NUnit currently, as they don't provide ManagedType/ManagedMethod.
+ if (TryGetMethodIdentifierProperty(testCase, out TestMethodIdentifierProperty? methodIdentifierProperty))
+ {
+ testNode.Properties.Add(methodIdentifierProperty);
+ }
+
+ CopyCategoryAndTraits(testCase, testNode, isTrxEnabled);
+
+ if (ShouldAddVSTestProviderProperties(namedFeatureCapability, commandLineOptions))
+ {
+ CopyVSTestProviderProperties(testCase.Properties, testNode, testCase.GetPropertyValue);
+ }
+
if (testCase.CodeFilePath is not null)
{
testNode.Properties.Add(new TestFileLocationProperty(testCase.CodeFilePath, new(new(testCase.LineNumber, -1), new(testCase.LineNumber, -1))));
@@ -43,73 +82,60 @@ public static TestNode ToTestNode(this TestCase testCase, bool isTrxEnabled, ICl
return testNode;
}
- private static void CopyVSTestProperties(IEnumerable testProperties, TestNode testNode, TestCase testCase, Func getPropertyValue,
- bool isTrxEnabled, IClientInfo client)
+ private static void CopyCategoryAndTraits(TestObject testCaseOrResult, TestNode testNode, bool isTrxEnabled)
{
- foreach (TestProperty property in testProperties)
+ // TPv2 is doing some special handling for MSTest... we should probably do the same.
+ // See https://github.com/microsoft/vstest/blob/main/src/Microsoft.TestPlatform.Extensions.TrxLogger/Utility/Converter.cs#L66-L70
+ if (testCaseOrResult.GetPropertyValue(TestCategoryProperty, defaultValue: null) is string[] mstestCategories)
{
- testNode.Properties.Add(new VSTestProperty(property, testCase));
-
if (isTrxEnabled)
{
- // TPv2 is doing some special handling for MSTest... we should probably do the same.
- // See https://github.com/microsoft/vstest/blob/main/src/Microsoft.TestPlatform.Extensions.TrxLogger/Utility/Converter.cs#L66-L70
- if (property.Id == "MSTestDiscoverer.TestCategory"
- && getPropertyValue(property) is string[] mstestCategories)
- {
- testNode.Properties.Add(new TrxCategoriesProperty(mstestCategories));
- }
+ testNode.Properties.Add(new TrxCategoriesProperty(mstestCategories));
}
- // Implement handling of specific vstest properties for VS/VS Code Test Explorer,
- // see https://github.com/microsoft/testanywhere/blob/main/docs/design/proposed/IDE_Protocol_IDE_Integration.md#vstest-test-node
- if (client.Id == WellKnownClients.VisualStudio)
+ foreach (string category in mstestCategories)
{
- if (property.Id == TestCaseProperties.Id.Id
- && getPropertyValue(property) is Guid testCaseId)
- {
- testNode.Properties.Add(new SerializableKeyValuePairStringProperty("vstest.TestCase.Id", testCaseId.ToString()));
- }
- else if (property.Id == TestCaseProperties.FullyQualifiedName.Id
- && getPropertyValue(property) is string testCaseFqn)
- {
- testNode.Properties.Add(new SerializableKeyValuePairStringProperty("vstest.TestCase.FullyQualifiedName", testCaseFqn));
- }
- else if (property.Id == OriginalExecutorUriProperty.Id
- && getPropertyValue(property) is Uri originalExecutorUri)
- {
- testNode.Properties.Add(new SerializableKeyValuePairStringProperty("vstest.original-executor-uri", originalExecutorUri.AbsoluteUri));
- }
-
- // The TP object holding the hierarchy property is defined on adapter utilities and we don't want to enforce that dependency
- // so instead I use the string ID copied from TP.
- else if (property.Id == "TestCase.Hierarchy"
- && getPropertyValue(property) is string[] testCaseHierarchy
- && testCaseHierarchy.Length == 4)
- {
- testNode.Properties.Add(new SerializableNamedArrayStringProperty("vstest.TestCase.Hierarchy", testCaseHierarchy));
- }
+ testNode.Properties.Add(new TestMetadataProperty(category, string.Empty));
}
+ }
- // ID is defined on TraitCollection but is internal so again we copy the string here.
- if (property.Id == "TestObject.Traits"
- && getPropertyValue(property) is KeyValuePair[] traits && traits.Length > 0)
+ if (testCaseOrResult.GetPropertyValue[]>(TraitsProperty, defaultValue: null) is KeyValuePair[] traits &&
+ traits.Length > 0)
+ {
+ foreach (KeyValuePair trait in traits)
{
- foreach (KeyValuePair trait in traits)
- {
- testNode.Properties.Add(new TestMetadataProperty(trait.Key, trait.Value));
- }
+ testNode.Properties.Add(new TestMetadataProperty(trait.Key, trait.Value));
}
+ }
+ }
- // TPv2 is doing some special handling for MSTest... we should probably do the same.
- // See https://github.com/microsoft/vstest/blob/main/src/Microsoft.TestPlatform.Extensions.TrxLogger/Utility/Converter.cs#L66-L70
- else if (property.Id == "MSTestDiscoverer.TestCategory"
- && getPropertyValue(property) is string[] mstestCategories && mstestCategories.Length > 0)
+ private static void CopyVSTestProviderProperties(IEnumerable testProperties, TestNode testNode, Func getPropertyValue)
+ {
+ foreach (TestProperty property in testProperties)
+ {
+ // If vstestProvider is enabled (only known to be true for NUnit and Expecto so far), and we are running server mode in IDE (not dotnet test),
+ // we add these stuff.
+ // Once NUnit and Expecto allow us to move forward and remove vstestProvider, we can remove this logic and get rid of the whole vstestProvider capability.
+ if (property.Id == TestCaseProperties.Id.Id
+ && getPropertyValue(property) is Guid testCaseId)
{
- foreach (string category in mstestCategories)
- {
- testNode.Properties.Add(new TestMetadataProperty(category, string.Empty));
- }
+ testNode.Properties.Add(new SerializableKeyValuePairStringProperty("vstest.TestCase.Id", testCaseId.ToString()));
+ }
+ else if (property.Id == TestCaseProperties.FullyQualifiedName.Id
+ && getPropertyValue(property) is string testCaseFqn)
+ {
+ testNode.Properties.Add(new SerializableKeyValuePairStringProperty("vstest.TestCase.FullyQualifiedName", testCaseFqn));
+ }
+ else if (property.Id == OriginalExecutorUriProperty.Id
+ && getPropertyValue(property) is Uri originalExecutorUri)
+ {
+ testNode.Properties.Add(new SerializableKeyValuePairStringProperty("vstest.original-executor-uri", originalExecutorUri.AbsoluteUri));
+ }
+ else if (property.Id == HierarchyConstants.HierarchyPropertyId
+ && getPropertyValue(property) is string[] testCaseHierarchy
+ && testCaseHierarchy.Length == 4)
+ {
+ testNode.Properties.Add(new SerializableNamedArrayStringProperty("vstest.TestCase.Hierarchy", testCaseHierarchy));
}
}
}
@@ -117,10 +143,21 @@ private static void CopyVSTestProperties(IEnumerable testPropertie
///
/// Converts a VSTest to a Microsoft Testing Platform .
///
- public static TestNode ToTestNode(this TestResult testResult, bool isTrxEnabled, IClientInfo client)
+ public static TestNode ToTestNode(this TestResult testResult, bool isTrxEnabled, INamedFeatureCapability? namedFeatureCapability, ICommandLineOptions commandLineOptions)
{
- var testNode = testResult.TestCase.ToTestNode(isTrxEnabled, client, testResult.DisplayName);
- CopyVSTestProperties(testResult.Properties, testNode, testResult.TestCase, testResult.GetPropertyValue, isTrxEnabled, client);
+ var testNode = testResult.TestCase.ToTestNode(isTrxEnabled, namedFeatureCapability, commandLineOptions, testResult.DisplayName);
+
+ CopyCategoryAndTraits(testResult, testNode, isTrxEnabled);
+
+ bool addVSTestProviderProperties = ShouldAddVSTestProviderProperties(namedFeatureCapability, commandLineOptions);
+ if (addVSTestProviderProperties)
+ {
+ // TODO: This call might be unnecessary.
+ // All the relevant properties should be on TestCase, not TestResult.
+ // And properties on TestCase were already copied as part of ToTestNode call above.
+ CopyVSTestProviderProperties(testResult.Properties, testNode, testResult.GetPropertyValue);
+ }
+
testNode.AddOutcome(testResult);
if (isTrxEnabled)
@@ -157,14 +194,22 @@ public static TestNode ToTestNode(this TestResult testResult, bool isTrxEnabled,
if (testResultMessage.Category == TestResultMessage.StandardErrorCategory)
{
string message = testResultMessage.Text ?? string.Empty;
- testNode.Properties.Add(new SerializableKeyValuePairStringProperty("vstest.TestCase.StandardError", message));
+ if (addVSTestProviderProperties)
+ {
+ testNode.Properties.Add(new SerializableKeyValuePairStringProperty("vstest.TestCase.StandardError", message));
+ }
+
standardErrorMessages.Add(message);
}
if (testResultMessage.Category == TestResultMessage.StandardOutCategory)
{
string message = testResultMessage.Text ?? string.Empty;
- testNode.Properties.Add(new SerializableKeyValuePairStringProperty("vstest.TestCase.StandardOutput", message));
+ if (addVSTestProviderProperties)
+ {
+ testNode.Properties.Add(new SerializableKeyValuePairStringProperty("vstest.TestCase.StandardOutput", message));
+ }
+
standardOutputMessages.Add(message);
}
}
@@ -238,6 +283,45 @@ internal static void FixUpTestCase(this TestCase testCase, string? testAssemblyP
testCase.ExecutorUri = new(Constants.ExecutorUri);
}
+ private static bool TryGetMethodIdentifierProperty(TestCase testCase, [NotNullWhen(true)] out TestMethodIdentifierProperty? methodIdentifierProperty)
+ {
+ string? managedType = testCase.GetPropertyValue(ManagedTypeProperty, defaultValue: null);
+ string? managedMethod = testCase.GetPropertyValue(ManagedMethodProperty, defaultValue: null);
+ // NOTE: ManagedMethod, in case of MSTest, will have the parameter types.
+ // So, we prefer using it to display the parameter types in Test Explorer.
+ if (RoslynString.IsNullOrEmpty(managedType) || RoslynString.IsNullOrEmpty(managedMethod))
+ {
+ methodIdentifierProperty = null;
+ return false;
+ }
+
+ methodIdentifierProperty = GetMethodIdentifierPropertyFromManagedTypeAndManagedMethod(managedType, managedMethod);
+ return true;
+ }
+
+ private static TestMethodIdentifierProperty GetMethodIdentifierPropertyFromManagedTypeAndManagedMethod(
+ string managedType,
+ string managedMethod)
+ {
+ ManagedNameParser.ParseManagedMethodName(managedMethod, out string methodName, out int arity, out string[]? parameterTypes);
+ if (arity != 0)
+ {
+ methodName = $"{methodName}`{arity.ToString(CultureInfo.InvariantCulture)}";
+ }
+
+ parameterTypes ??= [];
+
+ ManagedNameParser.ParseManagedTypeName(managedType, out string @namespace, out string typeName);
+
+ // In the context of the VSTestBridge where we only have access to VSTest object model, we cannot determine ReturnTypeFullName.
+ // For now, we lose this bit of information.
+ // If really needed in the future, we can introduce a VSTest property to hold this info.
+ // But the eventual goal should be to stop using the VSTestBridge altogether.
+ // TODO: For AssemblyFullName, can we use Assembly.GetEntryAssembly().FullName?
+ // Or alternatively, does VSTest object model expose the assembly full name somewhere?
+ return new TestMethodIdentifierProperty(AssemblyFullName: string.Empty, @namespace, typeName, methodName, parameterTypes, ReturnTypeFullName: string.Empty);
+ }
+
private static bool TryParseFullyQualifiedType(string fullyQualifiedName, [NotNullWhen(true)] out string? fullyQualifiedType)
{
fullyQualifiedType = null;
@@ -256,4 +340,9 @@ private static bool TryParseFullyQualifiedType(string fullyQualifiedName, [NotNu
fullyQualifiedType = fullyQualifiedName[..lastDotIndexBeforeOpenBracket];
return true;
}
+
+ private static bool ShouldAddVSTestProviderProperties(INamedFeatureCapability? namedFeatureCapability, ICommandLineOptions commandLineOptions)
+ => namedFeatureCapability?.IsSupported(JsonRpcStrings.VSTestProviderSupport) == true &&
+ commandLineOptions.IsOptionSet(PlatformCommandLineProvider.ServerOptionKey) &&
+ !commandLineOptions.IsOptionSet(PlatformCommandLineProvider.DotNetTestPipeOptionKey);
}
diff --git a/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/ObjectModel/TestCaseDiscoverySinkAdapter.cs b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/ObjectModel/TestCaseDiscoverySinkAdapter.cs
index cd720b8074..1abd875609 100644
--- a/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/ObjectModel/TestCaseDiscoverySinkAdapter.cs
+++ b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/ObjectModel/TestCaseDiscoverySinkAdapter.cs
@@ -4,6 +4,8 @@
#pragma warning disable TPEXP // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
using Microsoft.Testing.Extensions.VSTestBridge.Helpers;
+using Microsoft.Testing.Platform.Capabilities.TestFramework;
+using Microsoft.Testing.Platform.CommandLine;
using Microsoft.Testing.Platform.Extensions.Messages;
using Microsoft.Testing.Platform.Logging;
using Microsoft.Testing.Platform.Messages;
@@ -25,19 +27,25 @@ internal sealed class TestCaseDiscoverySinkAdapter : ITestCaseDiscoverySink
///
private readonly ITestCaseDiscoverySink? _testCaseDiscoverySink;
private readonly ILogger _logger;
+ private readonly INamedFeatureCapability? _namedFeatureCapability;
+ private readonly ICommandLineOptions _commandLineOptions;
private readonly IMessageBus _messageBus;
private readonly bool _isTrxEnabled;
- private readonly IClientInfo _clientInfo;
private readonly VSTestBridgedTestFrameworkBase _adapterExtension;
private readonly TestSessionContext _session;
private readonly CancellationToken _cancellationToken;
private readonly string? _testAssemblyPath;
- public TestCaseDiscoverySinkAdapter(VSTestBridgedTestFrameworkBase adapterExtension, TestSessionContext session, string[] testAssemblyPaths,
+ public TestCaseDiscoverySinkAdapter(
+ VSTestBridgedTestFrameworkBase adapterExtension,
+ TestSessionContext session,
+ string[] testAssemblyPaths,
ITestApplicationModuleInfo testApplicationModuleInfo,
+ INamedFeatureCapability? namedFeatureCapability,
+ ICommandLineOptions commandLineOptions,
+ IMessageBus messageBus,
ILoggerFactory loggerFactory,
- IMessageBus messageBus, bool isTrxEnabled,
- IClientInfo clientInfo,
+ bool isTrxEnabled,
CancellationToken cancellationToken,
ITestCaseDiscoverySink? testCaseDiscoverySink = null)
{
@@ -61,9 +69,10 @@ public TestCaseDiscoverySinkAdapter(VSTestBridgedTestFrameworkBase adapterExtens
_testCaseDiscoverySink = testCaseDiscoverySink;
_logger = loggerFactory.CreateLogger();
+ _namedFeatureCapability = namedFeatureCapability;
+ _commandLineOptions = commandLineOptions;
_messageBus = messageBus;
_isTrxEnabled = isTrxEnabled;
- _clientInfo = clientInfo;
_adapterExtension = adapterExtension;
_session = session;
_cancellationToken = cancellationToken;
@@ -82,7 +91,7 @@ public void SendTestCase(TestCase discoveredTest)
_testCaseDiscoverySink?.SendTestCase(discoveredTest);
// Publish node state change to Microsoft Testing Platform
- var testNode = discoveredTest.ToTestNode(_isTrxEnabled, _clientInfo);
+ var testNode = discoveredTest.ToTestNode(_isTrxEnabled, _namedFeatureCapability, _commandLineOptions);
testNode.Properties.Add(DiscoveredTestNodeStateProperty.CachedInstance);
var testNodeChange = new TestNodeUpdateMessage(_session.SessionUid, testNode);
diff --git a/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/ObjectModel/VSTestProperty.cs b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/ObjectModel/VSTestProperty.cs
deleted file mode 100644
index 5ee2545535..0000000000
--- a/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/ObjectModel/VSTestProperty.cs
+++ /dev/null
@@ -1,22 +0,0 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
-// Licensed under the MIT license. See LICENSE file in the project root for full license information.
-
-using Microsoft.Testing.Platform.Extensions.Messages;
-using Microsoft.VisualStudio.TestPlatform.ObjectModel;
-
-namespace Microsoft.Testing.Extensions.VSTestBridge.ObjectModel;
-
-internal sealed class VSTestProperty(TestProperty property, TestCase testCase) : IProperty
-{
- public TestProperty Property { get; } = property;
-
- public TestCase TestCase { get; } = testCase;
-
- // We don't want to pay the allocation if we're not printing it for instance inside the logs.
- // So we go to get the property and ToString() it only if needed.
- public override string ToString()
- {
- object? value = TestCase.GetPropertyValue(Property);
- return $"VSTestProperty [Id: {Property.Id}] [Description: {Property.Description}] [ValueType: {Property.ValueType}] [Value: {value ?? "null"}]";
- }
-}
diff --git a/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Requests/VSTestDiscoverTestExecutionRequestFactory.cs b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Requests/VSTestDiscoverTestExecutionRequestFactory.cs
index b3076a43ae..ec247ba950 100644
--- a/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Requests/VSTestDiscoverTestExecutionRequestFactory.cs
+++ b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Requests/VSTestDiscoverTestExecutionRequestFactory.cs
@@ -2,11 +2,11 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using Microsoft.Testing.Extensions.VSTestBridge.ObjectModel;
+using Microsoft.Testing.Platform.Capabilities.TestFramework;
using Microsoft.Testing.Platform.CommandLine;
using Microsoft.Testing.Platform.Configurations;
using Microsoft.Testing.Platform.Helpers;
using Microsoft.Testing.Platform.Logging;
-using Microsoft.Testing.Platform.Messages;
using Microsoft.Testing.Platform.OutputDevice;
using Microsoft.Testing.Platform.Requests;
using Microsoft.Testing.Platform.Services;
@@ -60,9 +60,17 @@ public static VSTestDiscoverTestExecutionRequest CreateRequest(
RunSettingsAdapter runSettings = new(commandLineOptions, fileSystem, configuration, clientInfo, loggerFactory, messageLogger);
DiscoveryContextAdapter discoveryContext = new(commandLineOptions, runSettings, discoverTestExecutionRequest.Filter);
- ITestApplicationModuleInfo testApplicationModuleInfo = serviceProvider.GetTestApplicationModuleInfo();
- IMessageBus messageBus = serviceProvider.GetRequiredService();
- TestCaseDiscoverySinkAdapter discoverySink = new(adapterExtension, discoverTestExecutionRequest.Session, testAssemblyPaths, testApplicationModuleInfo, loggerFactory, messageBus, adapterExtension.IsTrxEnabled, clientInfo, cancellationToken);
+ TestCaseDiscoverySinkAdapter discoverySink = new(
+ adapterExtension,
+ discoverTestExecutionRequest.Session,
+ testAssemblyPaths,
+ serviceProvider.GetTestApplicationModuleInfo(),
+ serviceProvider.GetTestFrameworkCapabilities().GetCapability(),
+ serviceProvider.GetCommandLineOptions(),
+ serviceProvider.GetMessageBus(),
+ loggerFactory,
+ adapterExtension.IsTrxEnabled,
+ cancellationToken);
return new(discoverTestExecutionRequest.Session, discoverTestExecutionRequest.Filter, testAssemblyPaths, discoveryContext, messageLogger, discoverySink);
}
diff --git a/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Requests/VSTestRunTestExecutionRequestFactory.cs b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Requests/VSTestRunTestExecutionRequestFactory.cs
index 67ef610b2a..71f00dca62 100644
--- a/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Requests/VSTestRunTestExecutionRequestFactory.cs
+++ b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Requests/VSTestRunTestExecutionRequestFactory.cs
@@ -2,12 +2,11 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using Microsoft.Testing.Extensions.VSTestBridge.ObjectModel;
+using Microsoft.Testing.Platform.Capabilities.TestFramework;
using Microsoft.Testing.Platform.CommandLine;
using Microsoft.Testing.Platform.Configurations;
using Microsoft.Testing.Platform.Helpers;
using Microsoft.Testing.Platform.Logging;
-using Microsoft.Testing.Platform.Messages;
-using Microsoft.Testing.Platform.OutputDevice;
using Microsoft.Testing.Platform.Requests;
using Microsoft.Testing.Platform.Services;
@@ -55,11 +54,18 @@ public static VSTestRunTestExecutionRequest CreateRequest(
IFileSystem fileSystem = serviceProvider.GetFileSystem();
IClientInfo clientInfo = serviceProvider.GetClientInfo();
- ITestApplicationModuleInfo testApplicationModuleInfo = serviceProvider.GetTestApplicationModuleInfo();
- IMessageBus messageBus = serviceProvider.GetRequiredService();
- IOutputDevice outputDevice = serviceProvider.GetOutputDevice();
- FrameworkHandlerAdapter frameworkHandlerAdapter = new(adapterExtension, runTestExecutionRequest.Session, clientInfo, testAssemblyPaths,
- testApplicationModuleInfo, loggerFactory, messageBus, outputDevice, adapterExtension.IsTrxEnabled, cancellationToken);
+ FrameworkHandlerAdapter frameworkHandlerAdapter = new(
+ adapterExtension,
+ runTestExecutionRequest.Session,
+ testAssemblyPaths,
+ serviceProvider.GetTestApplicationModuleInfo(),
+ serviceProvider.GetTestFrameworkCapabilities().GetCapability(),
+ serviceProvider.GetCommandLineOptions(),
+ serviceProvider.GetMessageBus(),
+ serviceProvider.GetOutputDevice(),
+ loggerFactory,
+ adapterExtension.IsTrxEnabled,
+ cancellationToken);
RunSettingsAdapter runSettings = new(commandLineOptions, fileSystem, configuration, clientInfo, loggerFactory, frameworkHandlerAdapter);
RunContextAdapter runContext = new(commandLineOptions, runSettings, runTestExecutionRequest.Filter);
diff --git a/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/VSTestBridgedTestFrameworkBase.cs b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/VSTestBridgedTestFrameworkBase.cs
index 827cd6ad8a..4fe9357fec 100644
--- a/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/VSTestBridgedTestFrameworkBase.cs
+++ b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/VSTestBridgedTestFrameworkBase.cs
@@ -12,7 +12,6 @@
using Microsoft.Testing.Platform.Extensions.TestFramework;
using Microsoft.Testing.Platform.Logging;
using Microsoft.Testing.Platform.Messages;
-using Microsoft.Testing.Platform.OutputDevice;
using Microsoft.Testing.Platform.Requests;
using Microsoft.Testing.Platform.Services;
@@ -131,30 +130,49 @@ protected abstract Task RunTestsAsync(VSTestRunTestExecutionRequest request, IMe
private VSTestDiscoverTestExecutionRequest UpdateDiscoverRequest(
VSTestDiscoverTestExecutionRequest discoverRequest,
- IMessageBus messageBus, CancellationToken cancellationToken)
+ IMessageBus messageBus,
+ CancellationToken cancellationToken)
{
// Before passing down the request, we need to replace the discovery sink with a custom implementation calling
// both the original (VSTest) sink and our own.
- ITestApplicationModuleInfo testApplicationModuleInfo = ServiceProvider.GetTestApplicationModuleInfo();
ILoggerFactory loggerFactory = ServiceProvider.GetRequiredService();
- IClientInfo clientInfo = ServiceProvider.GetRequiredService();
- TestCaseDiscoverySinkAdapter testCaseDiscoverySinkAdapter = new(this, discoverRequest.Session, discoverRequest.AssemblyPaths, testApplicationModuleInfo, loggerFactory, messageBus, IsTrxEnabled, clientInfo, cancellationToken, discoverRequest.DiscoverySink);
+ TestCaseDiscoverySinkAdapter testCaseDiscoverySinkAdapter = new(
+ this,
+ discoverRequest.Session,
+ discoverRequest.AssemblyPaths,
+ ServiceProvider.GetTestApplicationModuleInfo(),
+ ServiceProvider.GetTestFrameworkCapabilities().GetCapability(),
+ ServiceProvider.GetCommandLineOptions(),
+ messageBus,
+ loggerFactory,
+ IsTrxEnabled,
+ cancellationToken,
+ discoverRequest.DiscoverySink);
return new(discoverRequest.Session, discoverRequest.Filter, discoverRequest.AssemblyPaths, discoverRequest.DiscoveryContext,
discoverRequest.MessageLogger, testCaseDiscoverySinkAdapter);
}
- private VSTestRunTestExecutionRequest UpdateRunRequest(VSTestRunTestExecutionRequest runRequest, IMessageBus messageBus,
+ private VSTestRunTestExecutionRequest UpdateRunRequest(
+ VSTestRunTestExecutionRequest runRequest,
+ IMessageBus messageBus,
CancellationToken cancellationToken)
{
// Before passing down the request, we need to replace the framework handle with a custom implementation calling
// both the original (VSTest) framework handle and our own.
- ITestApplicationModuleInfo testApplicationModuleInfo = ServiceProvider.GetTestApplicationModuleInfo();
ILoggerFactory loggerFactory = ServiceProvider.GetRequiredService();
- IOutputDevice outputDevice = ServiceProvider.GetOutputDevice();
- IClientInfo clientInfo = ServiceProvider.GetClientInfo();
- FrameworkHandlerAdapter frameworkHandlerAdapter = new(this, runRequest.Session, clientInfo, runRequest.AssemblyPaths, testApplicationModuleInfo,
- loggerFactory, messageBus, outputDevice, IsTrxEnabled, cancellationToken, runRequest.FrameworkHandle);
+ FrameworkHandlerAdapter frameworkHandlerAdapter = new(
+ this,
+ runRequest.Session,
+ runRequest.AssemblyPaths,
+ ServiceProvider.GetTestApplicationModuleInfo(),
+ ServiceProvider.GetTestFrameworkCapabilities().GetCapability(),
+ ServiceProvider.GetCommandLineOptions(),
+ messageBus,
+ ServiceProvider.GetOutputDevice(),
+ loggerFactory,
+ IsTrxEnabled,
+ cancellationToken, runRequest.FrameworkHandle);
return new(runRequest.Session, runRequest.Filter, runRequest.AssemblyPaths, runRequest.RunContext,
frameworkHandlerAdapter);
diff --git a/src/Platform/Microsoft.Testing.Platform/Messages/TestNodeProperties.cs b/src/Platform/Microsoft.Testing.Platform/Messages/TestNodeProperties.cs
index 93a1c5177e..d89f32c8fa 100644
--- a/src/Platform/Microsoft.Testing.Platform/Messages/TestNodeProperties.cs
+++ b/src/Platform/Microsoft.Testing.Platform/Messages/TestNodeProperties.cs
@@ -314,7 +314,7 @@ public sealed record TestFileLocationProperty(string FilePath, LinePositionSpan
///
/// Assembly full name.
/// Namespace.
-/// Type name.
+/// Type name in metadata format, not including the namespace. Generics are represented by backtick followed by arity. Nested types are represented by +.
/// Method name.
/// Parameter type full name.
/// Return type full name.
diff --git a/src/Platform/Microsoft.Testing.Platform/ServerMode/JsonRpc/Json/Json.cs b/src/Platform/Microsoft.Testing.Platform/ServerMode/JsonRpc/Json/Json.cs
index adaad5806e..33fe75a9a8 100644
--- a/src/Platform/Microsoft.Testing.Platform/ServerMode/JsonRpc/Json/Json.cs
+++ b/src/Platform/Microsoft.Testing.Platform/ServerMode/JsonRpc/Json/Json.cs
@@ -163,8 +163,10 @@ public Json(Dictionary? serializers = null, Dictionary 0
? $"{testMethodIdentifierProperty.MethodName}({string.Join(",", testMethodIdentifierProperty.ParameterTypeFullNames)})"
: testMethodIdentifierProperty.MethodName));
diff --git a/src/Platform/Microsoft.Testing.Platform/ServerMode/JsonRpc/SerializerUtilities.cs b/src/Platform/Microsoft.Testing.Platform/ServerMode/JsonRpc/SerializerUtilities.cs
index e67983a7bd..36023ccfab 100644
--- a/src/Platform/Microsoft.Testing.Platform/ServerMode/JsonRpc/SerializerUtilities.cs
+++ b/src/Platform/Microsoft.Testing.Platform/ServerMode/JsonRpc/SerializerUtilities.cs
@@ -225,8 +225,10 @@ static SerializerUtilities()
if (property is TestMethodIdentifierProperty testMethodIdentifierProperty)
{
- properties["location.namespace"] = testMethodIdentifierProperty.Namespace;
- properties["location.type"] = testMethodIdentifierProperty.TypeName;
+ properties["location.type"] = RoslynString.IsNullOrEmpty(testMethodIdentifierProperty.Namespace)
+ ? testMethodIdentifierProperty.TypeName
+ : $"{testMethodIdentifierProperty.Namespace}.{testMethodIdentifierProperty.TypeName}";
+
properties["location.method"] = testMethodIdentifierProperty.ParameterTypeFullNames.Length > 0
? $"{testMethodIdentifierProperty.MethodName}({string.Join(",", testMethodIdentifierProperty.ParameterTypeFullNames)})"
: testMethodIdentifierProperty.MethodName;
diff --git a/test/IntegrationTests/MSTest.Acceptance.IntegrationTests/ServerModeTests.cs b/test/IntegrationTests/MSTest.Acceptance.IntegrationTests/ServerModeTests.cs
index 154dceb6df..b79c30d152 100644
--- a/test/IntegrationTests/MSTest.Acceptance.IntegrationTests/ServerModeTests.cs
+++ b/test/IntegrationTests/MSTest.Acceptance.IntegrationTests/ServerModeTests.cs
@@ -23,7 +23,7 @@ public async Task DiscoverAndRun(string tfm)
InitializeResponse initializeResponseArgs = await jsonClient.Initialize();
- Assert.IsTrue(initializeResponseArgs.Capabilities.Testing.VSTestProvider);
+ Assert.IsFalse(initializeResponseArgs.Capabilities.Testing.VSTestProvider);
Assert.IsFalse(initializeResponseArgs.Capabilities.Testing.MultiRequestSupport);
Assert.IsTrue(initializeResponseArgs.Capabilities.Testing.SupportsDiscovery);
diff --git a/test/UnitTests/Microsoft.Testing.Extensions.VSTestBridge.UnitTests/ObjectModel/ObjectModelConvertersTests.cs b/test/UnitTests/Microsoft.Testing.Extensions.VSTestBridge.UnitTests/ObjectModel/ObjectModelConvertersTests.cs
index f2ae46978b..43ca08888b 100644
--- a/test/UnitTests/Microsoft.Testing.Extensions.VSTestBridge.UnitTests/ObjectModel/ObjectModelConvertersTests.cs
+++ b/test/UnitTests/Microsoft.Testing.Extensions.VSTestBridge.UnitTests/ObjectModel/ObjectModelConvertersTests.cs
@@ -5,9 +5,10 @@
using Microsoft.Testing.Extensions.TrxReport.Abstractions;
using Microsoft.Testing.Extensions.VSTestBridge.ObjectModel;
+using Microsoft.Testing.Platform.Capabilities.TestFramework;
+using Microsoft.Testing.Platform.CommandLine;
using Microsoft.Testing.Platform.Extensions.Messages;
-using Microsoft.Testing.Platform.Services;
-using Microsoft.Testing.Platform.TestHost;
+using Microsoft.Testing.Platform.ServerMode;
using Microsoft.VisualStudio.TestPlatform.ObjectModel;
using TestResult = Microsoft.VisualStudio.TestPlatform.ObjectModel.TestResult;
@@ -17,9 +18,6 @@ namespace Microsoft.Testing.Extensions.VSTestBridge.UnitTests.ObjectModel;
[TestClass]
public sealed class ObjectModelConvertersTests
{
- private static readonly IClientInfo TestClient = new ClientInfoService("UnitTest", string.Empty);
- private static readonly IClientInfo VSTestClient = new ClientInfoService(WellKnownClients.VisualStudio, string.Empty);
-
[TestMethod]
public void ToTestNode_WhenTestCaseHasDisplayName_TestNodeDisplayNameUsesIt()
{
@@ -27,7 +25,7 @@ public void ToTestNode_WhenTestCaseHasDisplayName_TestNodeDisplayNameUsesIt()
{
DisplayName = "MyDisplayName",
};
- var testNode = testCase.ToTestNode(false, TestClient);
+ var testNode = testCase.ToTestNode(false, null, new ConsoleCommandLineOptions());
Assert.AreEqual("MyDisplayName", testNode.DisplayName);
}
@@ -36,7 +34,7 @@ public void ToTestNode_WhenTestCaseHasDisplayName_TestNodeDisplayNameUsesIt()
public void ToTestNode_WhenTestCaseHasNoDisplayName_TestNodeDisplayNameUsesIt()
{
TestCase testCase = new("SomeFqn", new("executor://uri", UriKind.Absolute), "source.cs");
- var testNode = testCase.ToTestNode(false, TestClient);
+ var testNode = testCase.ToTestNode(false, null, new ConsoleCommandLineOptions());
Assert.AreEqual("SomeFqn", testNode.DisplayName);
}
@@ -48,7 +46,7 @@ public void ToTestNode_WhenTestResultHasCodeFilePath_SetsTestFileLocationPropert
{
CodeFilePath = "FilePath",
});
- var testNode = testResult.ToTestNode(false, TestClient);
+ var testNode = testResult.ToTestNode(false, null, new ConsoleCommandLineOptions());
Assert.AreEqual("FilePath", testNode.Properties.Single().FilePath);
}
@@ -61,7 +59,7 @@ public void ToTestNode_WhenTestResultOutcomeIsFailed_TestNodePropertiesContainFa
ErrorMessage = "SomeErrorMessage",
ErrorStackTrace = "SomeStackTrace",
};
- var testNode = testResult.ToTestNode(false, TestClient);
+ var testNode = testResult.ToTestNode(false, null, new ConsoleCommandLineOptions());
FailedTestNodeStateProperty[] failedTestNodeStateProperties = testNode.Properties.OfType().ToArray();
Assert.AreEqual(1, failedTestNodeStateProperties.Length);
@@ -77,7 +75,7 @@ public void ToTestNode_WhenTestResultHasMSTestDiscovererTestCategoryTestProperty
var testCategoryProperty = TestProperty.Register("MSTestDiscoverer.TestCategory", "Label", typeof(string[]), TestPropertyAttributes.None, typeof(TestCase));
testResult.SetPropertyValue(testCategoryProperty, ["category1"]);
- var testNode = testResult.ToTestNode(false, VSTestClient);
+ var testNode = testResult.ToTestNode(false, new NamedFeatureCapabilityWithVSTestProvider(), new ServerModeCommandLineOptions());
TestMetadataProperty[] testMetadatas = testNode.Properties.OfType().ToArray();
Assert.AreEqual(1, testMetadatas.Length);
@@ -92,7 +90,7 @@ public void ToTestNode_WhenTestResultHasMSTestDiscovererTestCategoryTestProperty
var testCategoryProperty = TestProperty.Register("MSTestDiscoverer.TestCategory", "Label", typeof(string[]), TestPropertyAttributes.None, typeof(TestCase));
testResult.SetPropertyValue(testCategoryProperty, ["category1"]);
- var testNode = testResult.ToTestNode(true, VSTestClient);
+ var testNode = testResult.ToTestNode(true, new NamedFeatureCapabilityWithVSTestProvider(), new ServerModeCommandLineOptions());
TrxCategoriesProperty[] trxCategoriesProperty = testNode.Properties.OfType().ToArray();
Assert.AreEqual(1, trxCategoriesProperty.Length);
@@ -107,7 +105,7 @@ public void ToTestNode_WhenTestResultHasTestCaseHierarchyTestProperty_TestNodePr
var testCaseHierarchy = TestProperty.Register("TestCase.Hierarchy", "Label", typeof(string[]), TestPropertyAttributes.None, typeof(TestCase));
testResult.SetPropertyValue(testCaseHierarchy, ["assembly", "class", "category", "test"]);
- var testNode = testResult.ToTestNode(false, VSTestClient);
+ var testNode = testResult.ToTestNode(false, new NamedFeatureCapabilityWithVSTestProvider(), new ServerModeCommandLineOptions());
SerializableNamedArrayStringProperty[] trxCategoriesProperty = testNode.Properties.OfType().ToArray();
Assert.AreEqual(1, trxCategoriesProperty.Length);
@@ -126,7 +124,7 @@ public void ToTestNode_WhenTestResultHasOriginalExecutorUriProperty_TestNodeProp
testResult.SetPropertyValue(originalExecutorUriProperty, new Uri("https://vs.com/"));
- var testNode = testResult.ToTestNode(false, VSTestClient);
+ var testNode = testResult.ToTestNode(false, new NamedFeatureCapabilityWithVSTestProvider(), new ServerModeCommandLineOptions());
SerializableKeyValuePairStringProperty[] serializableKeyValuePairStringProperty = testNode.Properties.OfType().ToArray();
Assert.AreEqual(3, serializableKeyValuePairStringProperty.Length);
@@ -139,7 +137,7 @@ public void ToTestNode_WhenTestResultHasFullyQualifiedTypeAndTrxEnabled_TestNode
{
TestResult testResult = new(new TestCase("assembly.class.test", new("executor://uri", UriKind.Absolute), "source.cs"));
- var testNode = testResult.ToTestNode(true, TestClient);
+ var testNode = testResult.ToTestNode(true, null, new ConsoleCommandLineOptions());
Assert.AreEqual(testNode.Properties.OfType()?.Length, 1);
Assert.AreEqual("assembly.class", testNode.Properties.Single().FullyQualifiedTypeName);
@@ -150,7 +148,7 @@ public void ToTestNode_WhenTestResultHasNoFullyQualifiedTypeAndTrxEnabled_Throws
{
TestResult testResult = new(new TestCase("test", new("executor://uri", UriKind.Absolute), "source.cs"));
- string errorMessage = Assert.ThrowsException(() => testResult.ToTestNode(true, TestClient)).Message;
+ string errorMessage = Assert.ThrowsException(() => testResult.ToTestNode(true, null, new ConsoleCommandLineOptions())).Message;
Assert.IsTrue(errorMessage.Contains("Unable to parse fully qualified type name from test case: "));
}
@@ -168,7 +166,7 @@ public void ToTestNode_FromTestResult_TestNodePropertiesContainCorrectTimingProp
EndTime = endTime,
Duration = duration,
};
- var testNode = testResult.ToTestNode(false, TestClient);
+ var testNode = testResult.ToTestNode(false, null, new ConsoleCommandLineOptions());
var testResultTimingProperty = new TimingProperty(new(startTime, endTime, duration), []);
Assert.AreEqual(testNode.Properties.OfType()[0], testResultTimingProperty);
@@ -182,7 +180,7 @@ public void ToTestNode_WhenTestResultOutcomeIsNotFoundWithoutSetErrorMessage_Tes
Outcome = TestOutcome.NotFound,
ErrorStackTrace = "SomeStackTrace",
};
- var testNode = testResult.ToTestNode(false, TestClient);
+ var testNode = testResult.ToTestNode(false, null, new ConsoleCommandLineOptions());
ErrorTestNodeStateProperty[] errorTestNodeStateProperties = testNode.Properties.OfType().ToArray();
Assert.AreEqual(1, errorTestNodeStateProperties.Length);
@@ -198,7 +196,7 @@ public void ToTestNode_WhenTestResultOutcomeIsSkipped_TestNodePropertiesContainS
{
Outcome = TestOutcome.Skipped,
};
- var testNode = testResult.ToTestNode(false, TestClient);
+ var testNode = testResult.ToTestNode(false, null, new ConsoleCommandLineOptions());
SkippedTestNodeStateProperty[] skipTestNodeStateProperties = testNode.Properties.OfType().ToArray();
Assert.AreEqual(1, skipTestNodeStateProperties.Length);
@@ -211,7 +209,7 @@ public void ToTestNode_WhenTestResultOutcomeIsNone_TestNodePropertiesContainSkip
{
Outcome = TestOutcome.None,
};
- var testNode = testResult.ToTestNode(false, TestClient);
+ var testNode = testResult.ToTestNode(false, null, new ConsoleCommandLineOptions());
SkippedTestNodeStateProperty[] skipTestNodeStateProperties = testNode.Properties.OfType().ToArray();
Assert.AreEqual(1, skipTestNodeStateProperties.Length);
@@ -224,7 +222,7 @@ public void ToTestNode_WhenTestResultOutcomeIsPassed_TestNodePropertiesContainPa
{
Outcome = TestOutcome.Passed,
};
- var testNode = testResult.ToTestNode(false, TestClient);
+ var testNode = testResult.ToTestNode(false, null, new ConsoleCommandLineOptions());
PassedTestNodeStateProperty[] passedTestNodeStateProperties = testNode.Properties.OfType().ToArray();
Assert.AreEqual(1, passedTestNodeStateProperties.Length);
@@ -238,7 +236,7 @@ public void ToTestNode_WhenTestResultHasUidAndDisplayNameWithWellKnownClient_Tes
DisplayName = "TestName",
};
- var testNode = testResult.ToTestNode(false, VSTestClient);
+ var testNode = testResult.ToTestNode(false, new NamedFeatureCapabilityWithVSTestProvider(), new ServerModeCommandLineOptions());
SerializableKeyValuePairStringProperty[] errorTestNodeStateProperties = testNode.Properties.OfType().ToArray();
Assert.AreEqual(2, errorTestNodeStateProperties.Length, "Expected 2 SerializableKeyValuePairStringProperty");
@@ -256,7 +254,7 @@ public void ToTestNode_WhenTestResultHasTraits_TestNodePropertiesContainIt()
Traits = { new Trait("key", "value") },
};
- var testNode = testResult.ToTestNode(false, VSTestClient);
+ var testNode = testResult.ToTestNode(false, new NamedFeatureCapabilityWithVSTestProvider(), new ServerModeCommandLineOptions());
TestMetadataProperty[] testMetadatas = testNode.Properties.OfType().ToArray();
Assert.AreEqual(1, testMetadatas.Length);
@@ -277,7 +275,7 @@ public void ToTestNode_WhenTestResultHasMultipleStandardOutputMessages_TestNodeP
},
};
- var testNode = testResult.ToTestNode(false, VSTestClient);
+ var testNode = testResult.ToTestNode(false, new NamedFeatureCapabilityWithVSTestProvider(), new ServerModeCommandLineOptions());
StandardOutputProperty[] standardOutputProperties = testNode.Properties.OfType().ToArray();
Assert.IsTrue(standardOutputProperties.Length == 1);
@@ -297,10 +295,29 @@ public void ToTestNode_WhenTestResultHasMultipleStandardErrorMessages_TestNodePr
},
};
- var testNode = testResult.ToTestNode(false, VSTestClient);
+ var testNode = testResult.ToTestNode(false, new NamedFeatureCapabilityWithVSTestProvider(), new ServerModeCommandLineOptions());
StandardErrorProperty[] standardErrorProperties = testNode.Properties.OfType().ToArray();
Assert.IsTrue(standardErrorProperties.Length == 1);
Assert.AreEqual($"message1{Environment.NewLine}message2", standardErrorProperties[0].StandardError);
}
+
+ private sealed class NamedFeatureCapabilityWithVSTestProvider : INamedFeatureCapability
+ {
+ public bool IsSupported(string featureName) => featureName is JsonRpcStrings.VSTestProviderSupport;
+ }
+
+ private sealed class ServerModeCommandLineOptions : ICommandLineOptions
+ {
+ public bool IsOptionSet(string optionName) => optionName is PlatformCommandLineProvider.ServerOptionKey;
+
+ public bool TryGetOptionArgumentList(string optionName, [NotNullWhen(true)] out string[]? arguments) => throw new NotImplementedException();
+ }
+
+ private sealed class ConsoleCommandLineOptions : ICommandLineOptions
+ {
+ public bool IsOptionSet(string optionName) => false;
+
+ public bool TryGetOptionArgumentList(string optionName, [NotNullWhen(true)] out string[]? arguments) => throw new NotImplementedException();
+ }
}
diff --git a/test/UnitTests/Microsoft.Testing.Platform.UnitTests/ServerMode/FormatterUtilitiesTests.cs b/test/UnitTests/Microsoft.Testing.Platform.UnitTests/ServerMode/FormatterUtilitiesTests.cs
index 47d988925c..db22bb0f74 100644
--- a/test/UnitTests/Microsoft.Testing.Platform.UnitTests/ServerMode/FormatterUtilitiesTests.cs
+++ b/test/UnitTests/Microsoft.Testing.Platform.UnitTests/ServerMode/FormatterUtilitiesTests.cs
@@ -176,7 +176,7 @@ private static void AssertSerialize(Type type, string instanceSerialized)
if (type == typeof(TestNode))
{
- Assert.AreEqual("""{"uid":"uid","display-name":"DisplayName","traits":[{"testmetadata-key":"testmetadata-value"}],"array-key":["1","2"],"standardError":"textProperty2","standardOutput":"textProperty","time.start-utc":"2023-01-01T01:01:01.0000000+00:00","time.stop-utc":"2023-01-01T01:01:01.0000000+00:00","time.duration-ms":0,"location.namespace":"namespace","location.type":"typeName","location.method":"methodName(param1,param2)","location.file":"filePath","location.line-start":1,"location.line-end":2,"key":"value","node-type":"action","execution-state":"failed","error.message":"sample","error.stacktrace":"","assert.actual":"","assert.expected":""}""".Replace(" ", string.Empty), instanceSerialized, because);
+ Assert.AreEqual("""{"uid":"uid","display-name":"DisplayName","traits":[{"testmetadata-key":"testmetadata-value"}],"array-key":["1","2"],"standardError":"textProperty2","standardOutput":"textProperty","time.start-utc":"2023-01-01T01:01:01.0000000+00:00","time.stop-utc":"2023-01-01T01:01:01.0000000+00:00","time.duration-ms":0,"location.type":"namespace.typeName","location.method":"methodName(param1,param2)","location.file":"filePath","location.line-start":1,"location.line-end":2,"key":"value","node-type":"action","execution-state":"failed","error.message":"sample","error.stacktrace":"","assert.actual":"","assert.expected":""}""".Replace(" ", string.Empty), instanceSerialized, because);
return;
}
@@ -188,7 +188,7 @@ private static void AssertSerialize(Type type, string instanceSerialized)
if (type == typeof(TestNodeUpdateMessage))
{
- Assert.AreEqual("""{"node":{"uid":"uid","display-name":"DisplayName","traits":[{"testmetadata-key":"testmetadata-value"}],"array-key":["1","2"],"standardError":"textProperty2","standardOutput":"textProperty","time.start-utc":"2023-01-01T01:01:01.0000000+00:00","time.stop-utc":"2023-01-01T01:01:01.0000000+00:00","time.duration-ms":0,"location.namespace":"namespace","location.type":"typeName","location.method":"methodName(param1,param2)","location.file":"filePath","location.line-start":1,"location.line-end":2,"key":"value","node-type":"action","execution-state":"failed","error.message":"sample","error.stacktrace":"","assert.actual":"","assert.expected":""},"parent":"parent-uid"}""".Replace(" ", string.Empty), instanceSerialized, because);
+ Assert.AreEqual("""{"node":{"uid":"uid","display-name":"DisplayName","traits":[{"testmetadata-key":"testmetadata-value"}],"array-key":["1","2"],"standardError":"textProperty2","standardOutput":"textProperty","time.start-utc":"2023-01-01T01:01:01.0000000+00:00","time.stop-utc":"2023-01-01T01:01:01.0000000+00:00","time.duration-ms":0,"location.type":"namespace.typeName","location.method":"methodName(param1,param2)","location.file":"filePath","location.line-start":1,"location.line-end":2,"key":"value","node-type":"action","execution-state":"failed","error.message":"sample","error.stacktrace":"","assert.actual":"","assert.expected":""},"parent":"parent-uid"}""".Replace(" ", string.Empty), instanceSerialized, because);
return;
}