diff --git a/Directory.Build.props b/Directory.Build.props
index c52560a235..fe3901dfe7 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -75,17 +75,6 @@
Microsoft.Testing.Platform
-
-
- true
-
- true
- true
- true
-
-
diff --git a/Directory.Packages.props b/Directory.Packages.props
index 16c4bec7c0..179a218047 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -59,7 +59,6 @@
-
diff --git a/src/Adapter/MSTest.Engine/Engine/TestArgumentsManager.cs b/src/Adapter/MSTest.Engine/Engine/TestArgumentsManager.cs
index 01ce2baed0..142f2bfdaa 100644
--- a/src/Adapter/MSTest.Engine/Engine/TestArgumentsManager.cs
+++ b/src/Adapter/MSTest.Engine/Engine/TestArgumentsManager.cs
@@ -19,10 +19,8 @@ public void RegisterTestArgumentsEntryProvider(
throw new InvalidOperationException("Cannot register TestArgumentsEntry provider after registration is frozen.");
}
- if (!_testArgumentsEntryProviders.TryAdd(testNodeStableUid, argumentPropertiesProviderCallback))
- {
- throw new InvalidOperationException($"TestArgumentsEntry provider is already registered for test node with UID '{testNodeStableUid}'.");
- }
+ // Add will throw an exception if the key already exists, which is intended.
+ _testArgumentsEntryProviders.Add(testNodeStableUid, argumentPropertiesProviderCallback);
}
internal void FreezeRegistration() => _isRegistrationFrozen = true;
diff --git a/src/Adapter/MSTest.Engine/MSTest.Engine.csproj b/src/Adapter/MSTest.Engine/MSTest.Engine.csproj
index d9d5992e1e..77fd557b59 100644
--- a/src/Adapter/MSTest.Engine/MSTest.Engine.csproj
+++ b/src/Adapter/MSTest.Engine/MSTest.Engine.csproj
@@ -60,7 +60,7 @@ This package provides a new experimental engine for MSTest test framework.]]>
-
+
diff --git a/src/Adapter/MSTest.TestAdapter/MSTest.TestAdapter.csproj b/src/Adapter/MSTest.TestAdapter/MSTest.TestAdapter.csproj
index b6d063c7d2..5d44f04283 100644
--- a/src/Adapter/MSTest.TestAdapter/MSTest.TestAdapter.csproj
+++ b/src/Adapter/MSTest.TestAdapter/MSTest.TestAdapter.csproj
@@ -66,7 +66,7 @@
-
+
diff --git a/src/Adapter/MSTest.TestAdapter/VSTestAdapter/MSTestExecutor.cs b/src/Adapter/MSTest.TestAdapter/VSTestAdapter/MSTestExecutor.cs
index aa358c28f5..098ac21a30 100644
--- a/src/Adapter/MSTest.TestAdapter/VSTestAdapter/MSTestExecutor.cs
+++ b/src/Adapter/MSTest.TestAdapter/VSTestAdapter/MSTestExecutor.cs
@@ -107,7 +107,13 @@ internal async Task RunTestsAsync(IEnumerable? tests, IRunContext? run
throw new ArgumentNullException(nameof(frameworkHandle));
}
- Ensure.NotNullOrEmpty(tests);
+ // TODO: Verify why VSTest annotates the IEnumerable as nullable.
+ if (tests is null)
+ {
+ throw new ArgumentNullException(nameof(tests));
+ }
+
+ Ensure.NotEmpty(tests);
if (!MSTestDiscovererHelpers.InitializeDiscovery(from test in tests select test.Source, runContext, frameworkHandle, configuration, new TestSourceHandler()))
{
@@ -129,7 +135,13 @@ internal async Task RunTestsAsync(IEnumerable? sources, IRunContext? run
throw new ArgumentNullException(nameof(frameworkHandle));
}
- Ensure.NotNullOrEmpty(sources);
+ // TODO: Verify why VSTest annotates the IEnumerable as nullable.
+ if (sources is null)
+ {
+ throw new ArgumentNullException(nameof(sources));
+ }
+
+ Ensure.NotEmpty(sources);
TestSourceHandler testSourceHandler = new();
if (!MSTestDiscovererHelpers.InitializeDiscovery(sources, runContext, frameworkHandle, configuration, testSourceHandler))
diff --git a/src/Adapter/MSTestAdapter.PlatformServices/AssemblyResolver.cs b/src/Adapter/MSTestAdapter.PlatformServices/AssemblyResolver.cs
index 9246404f96..345e8a2a27 100644
--- a/src/Adapter/MSTestAdapter.PlatformServices/AssemblyResolver.cs
+++ b/src/Adapter/MSTestAdapter.PlatformServices/AssemblyResolver.cs
@@ -82,7 +82,11 @@ class AssemblyResolver :
///
/// lock for the loaded assemblies cache.
///
+#if NET9_0_OR_GREATER
private readonly Lock _syncLock = new();
+#else
+ private readonly object _syncLock = new();
+#endif
private static List? s_currentlyLoading;
private bool _disposed;
@@ -99,7 +103,16 @@ class AssemblyResolver :
///
public AssemblyResolver(IList directories)
{
- Ensure.NotNullOrEmpty(directories);
+ if (directories is null)
+ {
+ throw new ArgumentNullException(nameof(directories));
+ }
+
+ // Caller always ensures non-empty.
+ if (directories.Count == 0)
+ {
+ throw ApplicationStateGuard.Unreachable();
+ }
_searchDirectories = [.. directories];
_directoryList = new Queue();
diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Execution/TestExecutionManager.cs b/src/Adapter/MSTestAdapter.PlatformServices/Execution/TestExecutionManager.cs
index c66382a236..3ca621511a 100644
--- a/src/Adapter/MSTestAdapter.PlatformServices/Execution/TestExecutionManager.cs
+++ b/src/Adapter/MSTestAdapter.PlatformServices/Execution/TestExecutionManager.cs
@@ -547,16 +547,16 @@ private async Task ExecuteTestsWithTestRunnerAsync(
// Add tcm properties.
if (tcmProperties is not null)
{
- foreach ((TestProperty key, object? value) in tcmProperties)
+ foreach (KeyValuePair kvp in tcmProperties)
{
- testContextProperties[key.Id] = value;
+ testContextProperties[kvp.Key.Id] = kvp.Value;
}
}
// Add source level parameters.
- foreach ((string key, object value) in sourceLevelParameters)
+ foreach (KeyValuePair kvp in sourceLevelParameters)
{
- testContextProperties[key] = value;
+ testContextProperties[kvp.Key] = kvp.Value;
}
if (unitTestElement.Traits is { Length: > 0 })
diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Execution/TestMethodInfo.cs b/src/Adapter/MSTestAdapter.PlatformServices/Execution/TestMethodInfo.cs
index c64fd37f63..1b8756af00 100644
--- a/src/Adapter/MSTestAdapter.PlatformServices/Execution/TestMethodInfo.cs
+++ b/src/Adapter/MSTestAdapter.PlatformServices/Execution/TestMethodInfo.cs
@@ -1070,7 +1070,9 @@ private async Task ExecuteInternalWithTimeoutAsync(object?[]? argume
else
{
// Cancel the token source as test has timed out
- await TestContext.Context.CancellationTokenSource.CancelAsync().ConfigureAwait(false);
+#pragma warning disable VSTHRD103 // Call async methods when in an async method - likely fine in this context. CancelAsync is .NET Core only. We prefer having the same behavior between .NET Core and .NET Framework.
+ TestContext.Context.CancellationTokenSource.Cancel();
+#pragma warning restore VSTHRD103 // Call async methods when in an async method
}
TestResult timeoutResult = new() { Outcome = UnitTestOutcome.Timeout, TestFailureException = new TestFailedException(UnitTestOutcome.Timeout, errorMessage) };
diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Execution/TypeCache.cs b/src/Adapter/MSTestAdapter.PlatformServices/Execution/TypeCache.cs
index fc670325af..8a46685730 100644
--- a/src/Adapter/MSTestAdapter.PlatformServices/Execution/TypeCache.cs
+++ b/src/Adapter/MSTestAdapter.PlatformServices/Execution/TypeCache.cs
@@ -134,26 +134,41 @@ public IEnumerable AssemblyInfoListWithExecutableCleanupMethod
DebugEx.Assert(testMethod != null, "test method is null");
string typeName = testMethod.FullClassName;
+
// Using GetOrAdd to ensure we calculate only once when this is called by different threads in parallel.
// Using a static lambda to ensure we don't capture.
- return _classInfoCache.GetOrAdd(typeName, static (typeName, tuple) =>
+#if NETCOREAPP
+ return _classInfoCache.GetOrAdd(typeName, CreateTestClassInfo, (this, testMethod));
+#else
+ // On .NET Framework, we don't have the GetOrAdd overload that prevents capturing lambdas.
+ // So, we first try to get the value from the cache.
+ if (_classInfoCache.TryGetValue(typeName, out TestClassInfo? cachedClassInfo))
{
- TestMethod testMethod = tuple.testMethod;
- TypeCache @this = tuple.Item1;
+ return cachedClassInfo;
+ }
- // Load the class type
- Type? type = LoadType(typeName, testMethod.AssemblyName);
+ // If value doesn't already exist in the cache, we fallback to the GetOrAdd that allocates.
+ return _classInfoCache.GetOrAdd(typeName, typeName => CreateTestClassInfo(typeName, (this, testMethod)));
+#endif
+ }
- if (type == null)
- {
- // This means the class containing the test method could not be found.
- // Return null so we return a not found result.
- return null;
- }
+ private static TestClassInfo? CreateTestClassInfo(string typeName, (TypeCache Cache, TestMethod Method) tuple)
+ {
+ TestMethod testMethod = tuple.Method;
+ TypeCache @this = tuple.Cache;
+
+ // Load the class type
+ Type? type = LoadType(typeName, testMethod.AssemblyName);
+
+ if (type == null)
+ {
+ // This means the class containing the test method could not be found.
+ // Return null so we return a not found result.
+ return null;
+ }
- // Get the classInfo
- return @this.CreateClassInfo(type);
- }, (this, testMethod));
+ // Get the classInfo
+ return @this.CreateClassInfo(type);
}
///
@@ -321,80 +336,94 @@ private TestClassInfo CreateClassInfo(Type classType)
/// The assembly to get its info.
/// The instance.
private TestAssemblyInfo GetAssemblyInfo(Assembly assembly)
+ {
+#if NETCOREAPP
// Using GetOrAdd to ensure we calculate only once when this is called by different threads in parallel.
// Using a static lambda to ensure we don't capture.
- => _testAssemblyInfoCache.GetOrAdd(assembly, static (assembly, @this) =>
+ return _testAssemblyInfoCache.GetOrAdd(assembly, CreateTestAssemblyInfo, this);
+#else
+ if (_testAssemblyInfoCache.TryGetValue(assembly, out TestAssemblyInfo cachedTestAssemblyInfo))
+ {
+ return cachedTestAssemblyInfo;
+ }
+
+ // Not cached already. Fallback to GetOrAdd call that captures "this" and allocates.
+ return _testAssemblyInfoCache.GetOrAdd(assembly, assembly => CreateTestAssemblyInfo(assembly, this));
+#endif
+ }
+
+ private static TestAssemblyInfo CreateTestAssemblyInfo(Assembly assembly, TypeCache @this)
+ {
+ var assemblyInfo = new TestAssemblyInfo(assembly);
+
+ Type[] types = AssemblyEnumerator.GetTypes(assembly);
+
+ foreach (Type t in types)
+ {
+ try
+ {
+ // Only examine classes which are TestClass or derives from TestClass attribute
+ if (!@this._reflectionHelper.IsAttributeDefined(t))
+ {
+ continue;
+ }
+ }
+ catch (Exception ex)
{
- var assemblyInfo = new TestAssemblyInfo(assembly);
+ // If we fail to discover type from an assembly, then do not abort. Pick the next type.
+ if (PlatformServiceProvider.Instance.AdapterTraceLogger.IsWarningEnabled)
+ {
+ PlatformServiceProvider.Instance.AdapterTraceLogger.Warning(
+ "TypeCache: Exception occurred while checking whether type {0} is a test class or not. {1}",
+ t.FullName,
+ ex);
+ }
- Type[] types = AssemblyEnumerator.GetTypes(assembly);
+ continue;
+ }
- foreach (Type t in types)
+ // Enumerate through all methods and identify the Assembly Init and cleanup methods.
+ foreach (MethodInfo methodInfo in PlatformServiceProvider.Instance.ReflectionOperations.GetDeclaredMethods(t))
+ {
+ if (@this.IsAssemblyOrClassInitializeMethod(methodInfo))
{
- try
- {
- // Only examine classes which are TestClass or derives from TestClass attribute
- if (!@this._reflectionHelper.IsAttributeDefined(t))
- {
- continue;
- }
- }
- catch (Exception ex)
+ assemblyInfo.AssemblyInitializeMethod = methodInfo;
+ assemblyInfo.AssemblyInitializeMethodTimeoutMilliseconds = @this.TryGetTimeoutInfo(methodInfo, FixtureKind.AssemblyInitialize);
+ }
+ else if (@this.IsAssemblyOrClassCleanupMethod(methodInfo))
+ {
+ assemblyInfo.AssemblyCleanupMethod = methodInfo;
+ assemblyInfo.AssemblyCleanupMethodTimeoutMilliseconds = @this.TryGetTimeoutInfo(methodInfo, FixtureKind.AssemblyCleanup);
+ }
+
+ bool isGlobalTestInitialize = @this._reflectionHelper.IsAttributeDefined(methodInfo);
+ bool isGlobalTestCleanup = @this._reflectionHelper.IsAttributeDefined(methodInfo);
+
+ if (isGlobalTestInitialize || isGlobalTestCleanup)
+ {
+ // Only try to validate the method if it already has the needed attribute.
+ // This avoids potential type load exceptions when the return type cannot be resolved.
+ // NOTE: Users tend to load assemblies in AssemblyInitialize after finishing the discovery.
+ // We want to avoid loading types early as much as we can.
+ bool isValid = methodInfo is { IsSpecialName: false, IsPublic: true, IsStatic: true, IsGenericMethod: false, DeclaringType.IsGenericType: false, DeclaringType.IsPublic: true } &&
+ methodInfo.GetParameters() is { } parameters && parameters.Length == 1 && parameters[0].ParameterType == typeof(TestContext) &&
+ methodInfo.IsValidReturnType();
+
+ if (isValid && isGlobalTestInitialize)
{
- // If we fail to discover type from an assembly, then do not abort. Pick the next type.
- if (PlatformServiceProvider.Instance.AdapterTraceLogger.IsWarningEnabled)
- {
- PlatformServiceProvider.Instance.AdapterTraceLogger.Warning(
- "TypeCache: Exception occurred while checking whether type {0} is a test class or not. {1}",
- t.FullName,
- ex);
- }
-
- continue;
+ assemblyInfo.GlobalTestInitializations.Add((methodInfo, @this.TryGetTimeoutInfo(methodInfo, FixtureKind.TestInitialize)));
}
- // Enumerate through all methods and identify the Assembly Init and cleanup methods.
- foreach (MethodInfo methodInfo in PlatformServiceProvider.Instance.ReflectionOperations.GetDeclaredMethods(t))
+ if (isValid && isGlobalTestCleanup)
{
- if (@this.IsAssemblyOrClassInitializeMethod(methodInfo))
- {
- assemblyInfo.AssemblyInitializeMethod = methodInfo;
- assemblyInfo.AssemblyInitializeMethodTimeoutMilliseconds = @this.TryGetTimeoutInfo(methodInfo, FixtureKind.AssemblyInitialize);
- }
- else if (@this.IsAssemblyOrClassCleanupMethod(methodInfo))
- {
- assemblyInfo.AssemblyCleanupMethod = methodInfo;
- assemblyInfo.AssemblyCleanupMethodTimeoutMilliseconds = @this.TryGetTimeoutInfo(methodInfo, FixtureKind.AssemblyCleanup);
- }
-
- bool isGlobalTestInitialize = @this._reflectionHelper.IsAttributeDefined(methodInfo);
- bool isGlobalTestCleanup = @this._reflectionHelper.IsAttributeDefined(methodInfo);
-
- if (isGlobalTestInitialize || isGlobalTestCleanup)
- {
- // Only try to validate the method if it already has the needed attribute.
- // This avoids potential type load exceptions when the return type cannot be resolved.
- // NOTE: Users tend to load assemblies in AssemblyInitialize after finishing the discovery.
- // We want to avoid loading types early as much as we can.
- bool isValid = methodInfo is { IsSpecialName: false, IsPublic: true, IsStatic: true, IsGenericMethod: false, DeclaringType.IsGenericType: false, DeclaringType.IsPublic: true } &&
- methodInfo.GetParameters() is { } parameters && parameters.Length == 1 && parameters[0].ParameterType == typeof(TestContext) &&
- methodInfo.IsValidReturnType();
-
- if (isValid && isGlobalTestInitialize)
- {
- assemblyInfo.GlobalTestInitializations.Add((methodInfo, @this.TryGetTimeoutInfo(methodInfo, FixtureKind.TestInitialize)));
- }
-
- if (isValid && isGlobalTestCleanup)
- {
- assemblyInfo.GlobalTestCleanups.Add((methodInfo, @this.TryGetTimeoutInfo(methodInfo, FixtureKind.TestCleanup)));
- }
- }
+ assemblyInfo.GlobalTestCleanups.Add((methodInfo, @this.TryGetTimeoutInfo(methodInfo, FixtureKind.TestCleanup)));
}
}
+ }
+ }
- return assemblyInfo;
- }, this);
+ return assemblyInfo;
+ }
///
/// Verify if a given method is an Assembly or Class Initialize method.
@@ -650,10 +679,14 @@ private DiscoveryTestMethodInfo ResolveTestMethodInfoForDiscovery(TestMethod tes
/// The .
private MethodInfo GetMethodInfoForTestMethod(TestMethod testMethod, TestClassInfo testClassInfo)
{
- bool discoverInternals = _discoverInternalsCache.GetOrAdd(
- testMethod.AssemblyName,
- static (_, testClassInfo) => testClassInfo.Parent.Assembly.GetCustomAttribute() != null,
- testClassInfo);
+ // TODO: The cache key could be TestAssemblyInfo or Assembly which would simplify this to not need to capture.
+ // TODO: We might not even need a dictionary cache at all, just let it be part of TestAssemblyInfo directly.
+ if (!_discoverInternalsCache.TryGetValue(testMethod.AssemblyName, out bool discoverInternals))
+ {
+ discoverInternals = _discoverInternalsCache.GetOrAdd(
+ testMethod.AssemblyName,
+ _ => testClassInfo.Parent.Assembly.GetCustomAttribute() is not null);
+ }
MethodInfo? testMethodInfo = testMethod.HasManagedMethodAndTypeProperties
? GetMethodInfoUsingManagedNameHelper(testMethod, testClassInfo, discoverInternals)
diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Execution/UnitTestRunner.cs b/src/Adapter/MSTestAdapter.PlatformServices/Execution/UnitTestRunner.cs
index 13c45e5665..4fe41e6f38 100644
--- a/src/Adapter/MSTestAdapter.PlatformServices/Execution/UnitTestRunner.cs
+++ b/src/Adapter/MSTestAdapter.PlatformServices/Execution/UnitTestRunner.cs
@@ -101,8 +101,15 @@ internal TestResult[] RunSingleTest(UnitTestElement unitTestElement, IDictionary
/// The .
internal async Task RunSingleTestAsync(UnitTestElement unitTestElement, IDictionary testContextProperties, IMessageLogger messageLogger)
{
- Ensure.NotNull(unitTestElement);
- Ensure.NotNull(testContextProperties);
+ if (unitTestElement is null)
+ {
+ throw new ArgumentNullException(nameof(unitTestElement));
+ }
+
+ if (testContextProperties is null)
+ {
+ throw new ArgumentNullException(nameof(testContextProperties));
+ }
TestMethod testMethod = unitTestElement.TestMethod;
ITestContext? testContextForTestExecution = null;
diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Extensions/MethodInfoExtensions.cs b/src/Adapter/MSTestAdapter.PlatformServices/Extensions/MethodInfoExtensions.cs
index 933ab3a2f3..99ebd885cc 100644
--- a/src/Adapter/MSTestAdapter.PlatformServices/Extensions/MethodInfoExtensions.cs
+++ b/src/Adapter/MSTestAdapter.PlatformServices/Extensions/MethodInfoExtensions.cs
@@ -199,7 +199,7 @@ private static bool IsValueTask(this MethodInfo method)
private static void InferGenerics(Type parameterType, Type argumentType, List<(Type ParameterType, Type Substitution)> result)
{
- if (parameterType.IsGenericMethodParameter())
+ if (parameterType.IsGenericParameter && parameterType.DeclaringMethod is not null)
{
// We found a generic parameter. The argument type should be the substitution for it.
result.Add((parameterType, argumentType));
diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Helpers/ReflectHelper.cs b/src/Adapter/MSTestAdapter.PlatformServices/Helpers/ReflectHelper.cs
index 78d440a885..49de9849b7 100644
--- a/src/Adapter/MSTestAdapter.PlatformServices/Helpers/ReflectHelper.cs
+++ b/src/Adapter/MSTestAdapter.PlatformServices/Helpers/ReflectHelper.cs
@@ -31,7 +31,10 @@ internal class ReflectHelper : MarshalByRefObject
public virtual /* for testing */ bool IsAttributeDefined(MemberInfo memberInfo)
where TAttribute : Attribute
{
- Ensure.NotNull(memberInfo);
+ if (memberInfo is null)
+ {
+ throw new ArgumentNullException(nameof(memberInfo));
+ }
// Get all attributes on the member.
Attribute[] attributes = GetCustomAttributesCached(memberInfo);
@@ -130,11 +133,7 @@ internal class ReflectHelper : MarshalByRefObject
/// The return type to match.
/// True if there is a match.
internal static bool MatchReturnType(MethodInfo method, Type returnType)
- {
- Ensure.NotNull(method);
- Ensure.NotNull(returnType);
- return method.ReturnType.Equals(returnType);
- }
+ => method.ReturnType.Equals(returnType);
///
/// Get categories applied to the test method.
diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Helpers/RunSettingsUtilities.cs b/src/Adapter/MSTestAdapter.PlatformServices/Helpers/RunSettingsUtilities.cs
index e4a457b0cc..a8d30dc0de 100644
--- a/src/Adapter/MSTestAdapter.PlatformServices/Helpers/RunSettingsUtilities.cs
+++ b/src/Adapter/MSTestAdapter.PlatformServices/Helpers/RunSettingsUtilities.cs
@@ -24,7 +24,7 @@ internal static class RunSettingsUtilities
/// The runsettings xml.
/// The test run parameters.
/// If there is no test run parameters section defined in the settingsxml a blank dictionary is returned.
- internal static Dictionary? GetTestRunParameters([StringSyntax(StringSyntaxAttribute.Xml, nameof(settingsXml))] string? settingsXml)
+ internal static Dictionary? GetTestRunParameters(string? settingsXml)
=> GetNodeValue(settingsXml, Constants.TestRunParametersName, TestRunParameters.FromXml);
///
@@ -47,7 +47,7 @@ internal static void ThrowOnHasAttributes(XmlReader reader)
}
private static T? GetNodeValue(
- [StringSyntax(StringSyntaxAttribute.Xml, nameof(settingsXml))] string? settingsXml,
+ string? settingsXml,
string nodeName,
Func nodeParser)
{
diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Helpers/TestDataSourceHelpers.cs b/src/Adapter/MSTestAdapter.PlatformServices/Helpers/TestDataSourceHelpers.cs
index 4f3e0b614a..e48a8bff04 100644
--- a/src/Adapter/MSTestAdapter.PlatformServices/Helpers/TestDataSourceHelpers.cs
+++ b/src/Adapter/MSTestAdapter.PlatformServices/Helpers/TestDataSourceHelpers.cs
@@ -53,7 +53,7 @@ public static bool TryHandleITestDataRow(
public static bool TryHandleTupleDataSource(object? data, ParameterInfo[] testMethodParameters, out object?[] array)
{
if (testMethodParameters.Length == 1 &&
- data?.GetType().IsAssignableTo(testMethodParameters[0].ParameterType) == true)
+ testMethodParameters[0].ParameterType?.IsAssignableFrom(data?.GetType()) == true)
{
array = [];
return false;
diff --git a/src/Adapter/MSTestAdapter.PlatformServices/MSTestAdapter.PlatformServices.csproj b/src/Adapter/MSTestAdapter.PlatformServices/MSTestAdapter.PlatformServices.csproj
index 3393d8818c..c55d5ca1a7 100644
--- a/src/Adapter/MSTestAdapter.PlatformServices/MSTestAdapter.PlatformServices.csproj
+++ b/src/Adapter/MSTestAdapter.PlatformServices/MSTestAdapter.PlatformServices.csproj
@@ -12,6 +12,8 @@
Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices
$(DefineConstants);TRACE
+
+ $(DefineConstants);EXCLUDE_OS_POLYFILL
true
@@ -35,10 +37,13 @@
-
+
+
+
+
diff --git a/src/Adapter/MSTestAdapter.PlatformServices/MSTestSettings.cs b/src/Adapter/MSTestAdapter.PlatformServices/MSTestSettings.cs
index 1d8692e804..9a318607f9 100644
--- a/src/Adapter/MSTestAdapter.PlatformServices/MSTestSettings.cs
+++ b/src/Adapter/MSTestAdapter.PlatformServices/MSTestSettings.cs
@@ -298,7 +298,7 @@ internal static void PopulateSettings(IDiscoveryContext? context, IMessageLogger
/// The logger for messages.
/// The settings if found. Null otherwise.
internal static MSTestSettings? GetSettings(
- [StringSyntax(StringSyntaxAttribute.Xml, nameof(runSettingsXml))] string? runSettingsXml,
+ string? runSettingsXml,
string settingName, IMessageLogger? logger)
{
if (StringEx.IsNullOrWhiteSpace(runSettingsXml))
@@ -346,7 +346,10 @@ internal static void Reset()
/// An instance of the class.
private static MSTestSettings ToSettings(XmlReader reader, IMessageLogger? logger)
{
- Ensure.NotNull(reader);
+ if (reader is null)
+ {
+ throw new ArgumentNullException(nameof(reader));
+ }
// Expected format of the xml is: -
//
@@ -673,7 +676,7 @@ private static void SetParallelSettings(XmlReader reader, MSTestSettings setting
CultureInfo.CurrentCulture,
Resource.InvalidParallelScopeValue,
value,
- string.Join(", ", Enum.GetNames())));
+ string.Join(", ", Enum.GetNames(typeof(ExecutionScope)))));
break;
}
@@ -700,10 +703,14 @@ private static void SetParallelSettings(XmlReader reader, MSTestSettings setting
private static bool TryParseEnum(string value, out T result)
where T : struct, Enum
=> Enum.TryParse(value, true, out result)
+#if NETCOREAPP
&& Enum.IsDefined(result);
+#else
+ && Enum.IsDefined(typeof(T), result);
+#endif
private static void SetGlobalSettings(
- [StringSyntax(StringSyntaxAttribute.Xml, nameof(runsettingsXml))] string runsettingsXml,
+ string runsettingsXml,
MSTestSettings settings, IMessageLogger? logger)
{
XElement? runConfigElement = XDocument.Parse(runsettingsXml).Element("RunSettings")?.Element("RunConfiguration");
@@ -862,7 +869,7 @@ internal static void SetSettingsFromConfig(IConfiguration configuration, IMessag
CultureInfo.CurrentCulture,
Resource.InvalidParallelScopeValue,
value,
- string.Join(", ", Enum.GetNames())));
+ string.Join(", ", Enum.GetNames(typeof(ExecutionScope)))));
}
settings.ParallelizationScope = scope;
diff --git a/src/Adapter/MSTestAdapter.PlatformServices/ObjectModel/UnitTestElement.cs b/src/Adapter/MSTestAdapter.PlatformServices/ObjectModel/UnitTestElement.cs
index 7f2390c8e4..ede437c595 100644
--- a/src/Adapter/MSTestAdapter.PlatformServices/ObjectModel/UnitTestElement.cs
+++ b/src/Adapter/MSTestAdapter.PlatformServices/ObjectModel/UnitTestElement.cs
@@ -27,7 +27,10 @@ internal sealed class UnitTestElement
/// Thrown when method is null.
public UnitTestElement(TestMethod testMethod)
{
- Ensure.NotNull(testMethod);
+ if (testMethod is null)
+ {
+ throw new ArgumentNullException(nameof(testMethod));
+ }
DebugEx.Assert(testMethod.FullClassName != null, "Full className cannot be empty");
TestMethod = testMethod;
diff --git a/src/Adapter/MSTestAdapter.PlatformServices/RunConfigurationSettings.cs b/src/Adapter/MSTestAdapter.PlatformServices/RunConfigurationSettings.cs
index a064111737..b94619b662 100644
--- a/src/Adapter/MSTestAdapter.PlatformServices/RunConfigurationSettings.cs
+++ b/src/Adapter/MSTestAdapter.PlatformServices/RunConfigurationSettings.cs
@@ -29,8 +29,7 @@ internal sealed class RunConfigurationSettings
/// Gets the configuration settings from the xml.
///
/// The xml with the settings passed from the test platform.
- public static RunConfigurationSettings GetSettings(
- [StringSyntax(StringSyntaxAttribute.Xml, nameof(runSettingsXml))] string? runSettingsXml)
+ public static RunConfigurationSettings GetSettings(string? runSettingsXml)
{
if (StringEx.IsNullOrEmpty(runSettingsXml))
{
@@ -68,7 +67,10 @@ public static RunConfigurationSettings GetSettings(
/// An instance of the class.
private static RunConfigurationSettings ToSettings(XmlReader reader)
{
- Ensure.NotNull(reader);
+ if (reader is null)
+ {
+ throw new ArgumentNullException(nameof(reader));
+ }
// Expected format of the xml is: -
//
diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Services/MSTestAdapterSettings.cs b/src/Adapter/MSTestAdapter.PlatformServices/Services/MSTestAdapterSettings.cs
index a2724fc3af..d844431a45 100644
--- a/src/Adapter/MSTestAdapter.PlatformServices/Services/MSTestAdapterSettings.cs
+++ b/src/Adapter/MSTestAdapter.PlatformServices/Services/MSTestAdapterSettings.cs
@@ -58,7 +58,10 @@ public MSTestAdapterSettings()
/// An instance of the class.
public static MSTestAdapterSettings ToSettings(XmlReader reader)
{
- Ensure.NotNull(reader);
+ if (reader is null)
+ {
+ throw new ArgumentNullException(nameof(reader));
+ }
// Expected format of the xml is: -
//
@@ -345,7 +348,10 @@ public List GetDirectoryListWithRecursiveProperty(string
private void ReadAssemblyResolutionPath(XmlReader reader)
{
- Ensure.NotNull(reader);
+ if (reader is null)
+ {
+ throw new ArgumentNullException(nameof(reader));
+ }
// Expected format of the xml is: -
//
diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Services/SettingsProvider.cs b/src/Adapter/MSTestAdapter.PlatformServices/Services/SettingsProvider.cs
index f7ccf31e0d..01556d847f 100644
--- a/src/Adapter/MSTestAdapter.PlatformServices/Services/SettingsProvider.cs
+++ b/src/Adapter/MSTestAdapter.PlatformServices/Services/SettingsProvider.cs
@@ -52,7 +52,11 @@ internal static void Load(IConfiguration configuration)
public void Load(XmlReader reader)
{
#if !WINDOWS_UWP
- Ensure.NotNull(reader);
+ if (reader is null)
+ {
+ throw new ArgumentNullException(nameof(reader));
+ }
+
var settings = MSTestAdapterSettings.ToSettings(reader);
if (!ReferenceEquals(settings, Settings))
{
diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Services/TestDataSource.cs b/src/Adapter/MSTestAdapter.PlatformServices/Services/TestDataSource.cs
index 2fea97032a..c1a15cfe16 100644
--- a/src/Adapter/MSTestAdapter.PlatformServices/Services/TestDataSource.cs
+++ b/src/Adapter/MSTestAdapter.PlatformServices/Services/TestDataSource.cs
@@ -142,7 +142,11 @@ private static void GetConnectionProperties(DataSourceAttribute dataSourceAttrib
providerNameInvariant = ConfigurationManager.ConnectionStrings[element.ConnectionString].ProviderName;
connectionString = ConfigurationManager.ConnectionStrings[element.ConnectionString].ConnectionString;
tableName = element.DataTableName;
+#if NETCOREAPP
dataAccessMethod = Enum.Parse(element.DataAccessMethod);
+#else
+ dataAccessMethod = (DataAccessMethod)Enum.Parse(typeof(DataAccessMethod), element.DataAccessMethod);
+#endif
}
#endif
}
diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Services/TestSourceHost.cs b/src/Adapter/MSTestAdapter.PlatformServices/Services/TestSourceHost.cs
index 4748c91562..0e8c0c8be6 100644
--- a/src/Adapter/MSTestAdapter.PlatformServices/Services/TestSourceHost.cs
+++ b/src/Adapter/MSTestAdapter.PlatformServices/Services/TestSourceHost.cs
@@ -131,7 +131,7 @@ public void SetupHost()
if (PlatformServiceProvider.Instance.AdapterTraceLogger.IsInfoEnabled)
{
- PlatformServiceProvider.Instance.AdapterTraceLogger.Info("DesktopTestSourceHost.SetupHost(): Creating assembly resolver with resolution paths {0}.", string.Join(',', resolutionPaths));
+ PlatformServiceProvider.Instance.AdapterTraceLogger.Info("DesktopTestSourceHost.SetupHost(): Creating assembly resolver with resolution paths {0}.", string.Join(",", resolutionPaths));
}
// NOTE: These 2 lines are super important, see https://github.com/microsoft/testfx/issues/2922
diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Utilities/DeploymentItemUtility.cs b/src/Adapter/MSTestAdapter.PlatformServices/Utilities/DeploymentItemUtility.cs
index 432db7470e..294c2366cf 100644
--- a/src/Adapter/MSTestAdapter.PlatformServices/Utilities/DeploymentItemUtility.cs
+++ b/src/Adapter/MSTestAdapter.PlatformServices/Utilities/DeploymentItemUtility.cs
@@ -257,9 +257,9 @@ private static List GetDeploymentItems(IEnumerable result = [];
- foreach ((string? key, string? value) in deploymentItemsData)
+ foreach (KeyValuePair kvp in deploymentItemsData)
{
- AddDeploymentItem(result, new DeploymentItem(key, value));
+ AddDeploymentItem(result, new DeploymentItem(kvp.Key, kvp.Value));
}
return result;
diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Utilities/DeploymentUtility.cs b/src/Adapter/MSTestAdapter.PlatformServices/Utilities/DeploymentUtility.cs
index 00aaac90be..eee32a30f2 100644
--- a/src/Adapter/MSTestAdapter.PlatformServices/Utilities/DeploymentUtility.cs
+++ b/src/Adapter/MSTestAdapter.PlatformServices/Utilities/DeploymentUtility.cs
@@ -57,6 +57,32 @@ public override void AddDeploymentItemsBasedOnMsTestSetting(string testSourceHan
#endif
}
+#if !NETCOREAPP
+ private static int ProcessId
+ {
+ get
+ {
+ int processId = field;
+ if (processId == 0)
+ {
+ field = processId = GetProcessId();
+ // Assume that process Id zero is invalid for user processes. It holds for all mainstream operating systems.
+ Debug.Assert(processId != 0, "processId is expected to be non-zero.");
+ }
+
+ return processId;
+
+ static int GetProcessId()
+ {
+ using var process = Process.GetCurrentProcess();
+ return process.Id;
+ }
+ }
+ }
+#else
+ private static int ProcessId => Environment.ProcessId;
+#endif
+
///
/// Get root deployment directory.
///
@@ -64,7 +90,8 @@ public override void AddDeploymentItemsBasedOnMsTestSetting(string testSourceHan
/// Root deployment directory.
public override string GetRootDeploymentDirectory(string baseDirectory)
{
- string dateTimeSuffix = $"{DateTime.Now.ToString("yyyyMMddTHHmmss", DateTimeFormatInfo.InvariantInfo)}_{Environment.ProcessId}";
+ string dateTimeSuffix = $"{DateTime.Now.ToString("yyyyMMddTHHmmss", DateTimeFormatInfo.InvariantInfo)}_{ProcessId}";
+
string directoryName = string.Format(CultureInfo.InvariantCulture, Resource.TestRunName, DeploymentFolderPrefix,
#if NETFRAMEWORK
Environment.UserName,
diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Utilities/DeploymentUtilityBase.cs b/src/Adapter/MSTestAdapter.PlatformServices/Utilities/DeploymentUtilityBase.cs
index 2f407266ac..c9c93d3fd6 100644
--- a/src/Adapter/MSTestAdapter.PlatformServices/Utilities/DeploymentUtilityBase.cs
+++ b/src/Adapter/MSTestAdapter.PlatformServices/Utilities/DeploymentUtilityBase.cs
@@ -155,8 +155,6 @@ protected IEnumerable Deploy(IList deploymentItems, stri
// Copy the deployment items. (As deployment item can correspond to directories as well, so each deployment item may map to n files)
foreach (DeploymentItem deploymentItem in deploymentItems)
{
- Ensure.NotNull(deploymentItem);
-
// Validate the output directory.
if (!IsOutputDirectoryValid(deploymentItem, deploymentDirectory, warnings))
{
@@ -415,7 +413,6 @@ private static void LogWarnings(ITestExecutionRecorder testExecutionRecorder, IE
private bool Deploy(string source, IRunContext? runContext, ITestExecutionRecorder testExecutionRecorder, IList deploymentItems, TestRunDirectories runDirectories)
{
- Ensure.NotNull(runDirectories);
if (PlatformServiceProvider.Instance.AdapterTraceLogger.IsInfoEnabled)
{
PlatformServiceProvider.Instance.AdapterTraceLogger.Info("MSTestExecutor: Found that deployment items for source {0} are: ", source);
diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Utilities/XmlUtilities.cs b/src/Adapter/MSTestAdapter.PlatformServices/Utilities/XmlUtilities.cs
index 518180b254..6f583874ed 100644
--- a/src/Adapter/MSTestAdapter.PlatformServices/Utilities/XmlUtilities.cs
+++ b/src/Adapter/MSTestAdapter.PlatformServices/Utilities/XmlUtilities.cs
@@ -100,7 +100,10 @@ private static void AddAssemblyBindingRedirect(
string fromVersion,
string toVersion)
{
- Ensure.NotNull(assemblyName);
+ if (assemblyName is null)
+ {
+ throw new ArgumentNullException(nameof(assemblyName));
+ }
// Convert the public key token into a string.
StringBuilder? publicKeyTokenString = null;
diff --git a/src/Analyzers/MSTest.Analyzers.CodeFixes/FlowTestContextCancellationTokenFixer.cs b/src/Analyzers/MSTest.Analyzers.CodeFixes/FlowTestContextCancellationTokenFixer.cs
index b598080ce4..e6a977eaf4 100644
--- a/src/Analyzers/MSTest.Analyzers.CodeFixes/FlowTestContextCancellationTokenFixer.cs
+++ b/src/Analyzers/MSTest.Analyzers.CodeFixes/FlowTestContextCancellationTokenFixer.cs
@@ -115,7 +115,11 @@ internal static Document ApplyFix(
}
else
{
- Ensure.NotNull(testContextMemberName);
+ if (testContextMemberName is null)
+ {
+ throw new ArgumentNullException(nameof(testContextMemberName));
+ }
+
AddCancellationTokenArgument(editor, invocationExpression, testContextMemberName, cancellationTokenParameterName);
}
diff --git a/src/Analyzers/MSTest.Analyzers.CodeFixes/MSTest.Analyzers.CodeFixes.csproj b/src/Analyzers/MSTest.Analyzers.CodeFixes/MSTest.Analyzers.CodeFixes.csproj
index ad9bdcf545..681f7842d4 100644
--- a/src/Analyzers/MSTest.Analyzers.CodeFixes/MSTest.Analyzers.CodeFixes.csproj
+++ b/src/Analyzers/MSTest.Analyzers.CodeFixes/MSTest.Analyzers.CodeFixes.csproj
@@ -8,7 +8,10 @@
-
+
+
+
+
diff --git a/src/Analyzers/MSTest.Analyzers/DataRowShouldBeValidAnalyzer.cs b/src/Analyzers/MSTest.Analyzers/DataRowShouldBeValidAnalyzer.cs
index a76213bc37..4a0042aeab 100644
--- a/src/Analyzers/MSTest.Analyzers/DataRowShouldBeValidAnalyzer.cs
+++ b/src/Analyzers/MSTest.Analyzers/DataRowShouldBeValidAnalyzer.cs
@@ -331,11 +331,11 @@ private static void AnalyzeGenericMethod(
if (parameterTypesSubstitutions.TryGetValue(parameterType, out (ITypeSymbol Symbol, Type SystemType) existingType))
{
- if (argumentType.IsAssignableTo(existingType.SystemType))
+ if (existingType.SystemType.IsAssignableFrom(argumentType))
{
continue;
}
- else if (existingType.SystemType.IsAssignableTo(argumentType))
+ else if (argumentType.IsAssignableFrom(existingType.SystemType))
{
parameterTypesSubstitutions[parameterType] = (parameterType, argumentType);
}
diff --git a/src/Analyzers/MSTest.Analyzers/DoNotUseShadowingAnalyzer.cs b/src/Analyzers/MSTest.Analyzers/DoNotUseShadowingAnalyzer.cs
index 99f2fca090..20eea23415 100644
--- a/src/Analyzers/MSTest.Analyzers/DoNotUseShadowingAnalyzer.cs
+++ b/src/Analyzers/MSTest.Analyzers/DoNotUseShadowingAnalyzer.cs
@@ -64,7 +64,12 @@ private static void AnalyzeSymbol(SymbolAnalysisContext context, INamedTypeSymbo
Dictionary> membersByName = GetBaseMembers(namedTypeSymbol);
foreach (ISymbol member in namedTypeSymbol.GetMembers())
{
- foreach (ISymbol baseMember in membersByName.GetValueOrDefault(member.Name, []))
+ if (!membersByName.TryGetValue(member.Name, out List? members))
+ {
+ continue;
+ }
+
+ foreach (ISymbol baseMember in members)
{
// Check if the member is shadowing a base class member
if (IsMemberShadowing(member, baseMember))
diff --git a/src/Analyzers/MSTest.Analyzers/FlowTestContextCancellationTokenAnalyzer.cs b/src/Analyzers/MSTest.Analyzers/FlowTestContextCancellationTokenAnalyzer.cs
index 582ff7cceb..b36519882c 100644
--- a/src/Analyzers/MSTest.Analyzers/FlowTestContextCancellationTokenAnalyzer.cs
+++ b/src/Analyzers/MSTest.Analyzers/FlowTestContextCancellationTokenAnalyzer.cs
@@ -230,7 +230,7 @@ private static bool HasOrCouldHaveTestContextInScope(
testContextMember = (testContextMember as IFieldSymbol)?.AssociatedSymbol ?? testContextMember;
// Workaround https://github.com/dotnet/roslyn/issues/70208
// https://github.com/dotnet/roslyn/blob/f25ae8e02a91169f45060951a168b233ad588ed3/src/Compilers/CSharp/Portable/Symbols/Synthesized/GeneratedNameKind.cs#L47
- testContextMemberNameInScope = testContextMember.Name.StartsWith('<') && testContextMember.Name.EndsWith(">P", StringComparison.Ordinal)
+ testContextMemberNameInScope = testContextMember.Name.StartsWith("<", StringComparison.Ordinal) && testContextMember.Name.EndsWith(">P", StringComparison.Ordinal)
? testContextMember.Name.Substring(1, testContextMember.Name.Length - 3)
: testContextMember.Name;
testContextState = TestContextState.InScope;
diff --git a/src/Analyzers/MSTest.Analyzers/MSTest.Analyzers.csproj b/src/Analyzers/MSTest.Analyzers/MSTest.Analyzers.csproj
index 77efce2f98..d8d91fad54 100644
--- a/src/Analyzers/MSTest.Analyzers/MSTest.Analyzers.csproj
+++ b/src/Analyzers/MSTest.Analyzers/MSTest.Analyzers.csproj
@@ -20,7 +20,9 @@
-
+
+
+
diff --git a/src/Analyzers/MSTest.Analyzers/RoslynAnalyzerHelpers/ArrayBuilder.cs b/src/Analyzers/MSTest.Analyzers/RoslynAnalyzerHelpers/ArrayBuilder.cs
index 8f4571e6a3..71bf118676 100644
--- a/src/Analyzers/MSTest.Analyzers/RoslynAnalyzerHelpers/ArrayBuilder.cs
+++ b/src/Analyzers/MSTest.Analyzers/RoslynAnalyzerHelpers/ArrayBuilder.cs
@@ -324,9 +324,9 @@ internal Dictionary> ToDictionary(Func keySelector
var dictionary = new Dictionary>(accumulator.Count, comparer);
// freeze
- foreach ((K? key, ArrayBuilder? value) in accumulator)
+ foreach (KeyValuePair> kvp in accumulator)
{
- dictionary.Add(key, value.ToImmutableAndFree());
+ dictionary.Add(kvp.Key, kvp.Value.ToImmutableAndFree());
}
return dictionary;
diff --git a/src/Analyzers/MSTest.Analyzers/TestContextShouldBeValidAnalyzer.cs b/src/Analyzers/MSTest.Analyzers/TestContextShouldBeValidAnalyzer.cs
index 6838d3bbc7..361668c8f5 100644
--- a/src/Analyzers/MSTest.Analyzers/TestContextShouldBeValidAnalyzer.cs
+++ b/src/Analyzers/MSTest.Analyzers/TestContextShouldBeValidAnalyzer.cs
@@ -232,7 +232,7 @@ public override void Initialize(AnalysisContext context)
if (fieldSymbol.AssociatedSymbol is not null ||
// Workaround https://github.com/dotnet/roslyn/issues/70208
// https://github.com/dotnet/roslyn/blob/05e49aa98995349ffa26a19020333293ffe99670/src/Compilers/CSharp/Portable/Symbols/Synthesized/GeneratedNameKind.cs#L47
- (fieldSymbol.Name.StartsWith('<') && fieldSymbol.Name.EndsWith(">P", StringComparison.Ordinal)) ||
+ (fieldSymbol.Name.StartsWith("<", StringComparison.Ordinal) && fieldSymbol.Name.EndsWith(">P", StringComparison.Ordinal)) ||
!SymbolEqualityComparer.Default.Equals(fieldSymbol.Type, testContextSymbol))
{
continue;
diff --git a/src/Platform/Microsoft.Testing.Extensions.AzureDevOpsReport/BannedSymbols.txt b/src/Platform/Microsoft.Testing.Extensions.AzureDevOpsReport/BannedSymbols.txt
index 09d715c49c..64ef236c50 100644
--- a/src/Platform/Microsoft.Testing.Extensions.AzureDevOpsReport/BannedSymbols.txt
+++ b/src/Platform/Microsoft.Testing.Extensions.AzureDevOpsReport/BannedSymbols.txt
@@ -1,5 +1,4 @@
-T:System.ArgumentNullException; Use 'ArgumentGuard' instead
-P:System.DateTime.Now; Use 'IClock' instead
+P:System.DateTime.Now; Use 'IClock' instead
P:System.DateTime.UtcNow; Use 'IClock' instead
M:System.Threading.Tasks.Task.Run(System.Action); Use 'ITask' instead
M:System.Threading.Tasks.Task.WhenAll(System.Threading.Tasks.Task[]); Use 'ITask' instead
diff --git a/src/Platform/Microsoft.Testing.Extensions.AzureDevOpsReport/Microsoft.Testing.Extensions.AzureDevOpsReport.csproj b/src/Platform/Microsoft.Testing.Extensions.AzureDevOpsReport/Microsoft.Testing.Extensions.AzureDevOpsReport.csproj
index 9c467429e1..c3c7cf4e4c 100644
--- a/src/Platform/Microsoft.Testing.Extensions.AzureDevOpsReport/Microsoft.Testing.Extensions.AzureDevOpsReport.csproj
+++ b/src/Platform/Microsoft.Testing.Extensions.AzureDevOpsReport/Microsoft.Testing.Extensions.AzureDevOpsReport.csproj
@@ -42,10 +42,7 @@ This package extends Microsoft Testing Platform to provide a Azure DevOps report
-
-
-
-
+
diff --git a/src/Platform/Microsoft.Testing.Extensions.AzureFoundry/Microsoft.Testing.Extensions.AzureFoundry.csproj b/src/Platform/Microsoft.Testing.Extensions.AzureFoundry/Microsoft.Testing.Extensions.AzureFoundry.csproj
index 93bcbdbb9f..57beb22aea 100644
--- a/src/Platform/Microsoft.Testing.Extensions.AzureFoundry/Microsoft.Testing.Extensions.AzureFoundry.csproj
+++ b/src/Platform/Microsoft.Testing.Extensions.AzureFoundry/Microsoft.Testing.Extensions.AzureFoundry.csproj
@@ -31,7 +31,10 @@
-
+
+
+
+
diff --git a/src/Platform/Microsoft.Testing.Extensions.CrashDump/BannedSymbols.txt b/src/Platform/Microsoft.Testing.Extensions.CrashDump/BannedSymbols.txt
index 09d715c49c..64ef236c50 100644
--- a/src/Platform/Microsoft.Testing.Extensions.CrashDump/BannedSymbols.txt
+++ b/src/Platform/Microsoft.Testing.Extensions.CrashDump/BannedSymbols.txt
@@ -1,5 +1,4 @@
-T:System.ArgumentNullException; Use 'ArgumentGuard' instead
-P:System.DateTime.Now; Use 'IClock' instead
+P:System.DateTime.Now; Use 'IClock' instead
P:System.DateTime.UtcNow; Use 'IClock' instead
M:System.Threading.Tasks.Task.Run(System.Action); Use 'ITask' instead
M:System.Threading.Tasks.Task.WhenAll(System.Threading.Tasks.Task[]); Use 'ITask' instead
diff --git a/src/Platform/Microsoft.Testing.Extensions.CrashDump/Microsoft.Testing.Extensions.CrashDump.csproj b/src/Platform/Microsoft.Testing.Extensions.CrashDump/Microsoft.Testing.Extensions.CrashDump.csproj
index d69669e55b..8aeeb45416 100644
--- a/src/Platform/Microsoft.Testing.Extensions.CrashDump/Microsoft.Testing.Extensions.CrashDump.csproj
+++ b/src/Platform/Microsoft.Testing.Extensions.CrashDump/Microsoft.Testing.Extensions.CrashDump.csproj
@@ -47,7 +47,7 @@ This package extends Microsoft Testing Platform to provide a crash dump function
-
+
diff --git a/src/Platform/Microsoft.Testing.Extensions.HangDump/BannedSymbols.txt b/src/Platform/Microsoft.Testing.Extensions.HangDump/BannedSymbols.txt
index 09d715c49c..64ef236c50 100644
--- a/src/Platform/Microsoft.Testing.Extensions.HangDump/BannedSymbols.txt
+++ b/src/Platform/Microsoft.Testing.Extensions.HangDump/BannedSymbols.txt
@@ -1,5 +1,4 @@
-T:System.ArgumentNullException; Use 'ArgumentGuard' instead
-P:System.DateTime.Now; Use 'IClock' instead
+P:System.DateTime.Now; Use 'IClock' instead
P:System.DateTime.UtcNow; Use 'IClock' instead
M:System.Threading.Tasks.Task.Run(System.Action); Use 'ITask' instead
M:System.Threading.Tasks.Task.WhenAll(System.Threading.Tasks.Task[]); Use 'ITask' instead
diff --git a/src/Platform/Microsoft.Testing.Extensions.HangDump/HangDumpExtensions.cs b/src/Platform/Microsoft.Testing.Extensions.HangDump/HangDumpExtensions.cs
index 2e76ca62cb..d3c0435c38 100644
--- a/src/Platform/Microsoft.Testing.Extensions.HangDump/HangDumpExtensions.cs
+++ b/src/Platform/Microsoft.Testing.Extensions.HangDump/HangDumpExtensions.cs
@@ -7,6 +7,10 @@
using Microsoft.Testing.Platform.IPC;
using Microsoft.Testing.Platform.Services;
+#if !NETCOREAPP
+using Polyfills;
+#endif
+
namespace Microsoft.Testing.Extensions;
///
diff --git a/src/Platform/Microsoft.Testing.Extensions.HangDump/Helpers/IProcessExtensions.cs b/src/Platform/Microsoft.Testing.Extensions.HangDump/Helpers/IProcessExtensions.cs
index 9dc68a520e..09cf63650b 100644
--- a/src/Platform/Microsoft.Testing.Extensions.HangDump/Helpers/IProcessExtensions.cs
+++ b/src/Platform/Microsoft.Testing.Extensions.HangDump/Helpers/IProcessExtensions.cs
@@ -7,6 +7,10 @@
using Microsoft.Testing.Platform.Logging;
using Microsoft.Testing.Platform.OutputDevice;
+#if !NETCOREAPP
+using Polyfills;
+#endif
+
namespace Microsoft.Testing.Extensions.Diagnostics.Helpers;
///
diff --git a/src/Platform/Microsoft.Testing.Extensions.HangDump/Microsoft.Testing.Extensions.HangDump.csproj b/src/Platform/Microsoft.Testing.Extensions.HangDump/Microsoft.Testing.Extensions.HangDump.csproj
index d93376e89a..c3416cc0fc 100644
--- a/src/Platform/Microsoft.Testing.Extensions.HangDump/Microsoft.Testing.Extensions.HangDump.csproj
+++ b/src/Platform/Microsoft.Testing.Extensions.HangDump/Microsoft.Testing.Extensions.HangDump.csproj
@@ -6,7 +6,7 @@
-
+
diff --git a/src/Platform/Microsoft.Testing.Extensions.HangDump/WindowsMiniDumpWriteDump.cs b/src/Platform/Microsoft.Testing.Extensions.HangDump/WindowsMiniDumpWriteDump.cs
index 12233d34ce..1963ed4715 100644
--- a/src/Platform/Microsoft.Testing.Extensions.HangDump/WindowsMiniDumpWriteDump.cs
+++ b/src/Platform/Microsoft.Testing.Extensions.HangDump/WindowsMiniDumpWriteDump.cs
@@ -1,13 +1,13 @@
// 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
using Microsoft.Win32.SafeHandles;
namespace Microsoft.Testing.Extensions.Diagnostics;
internal static class MiniDumpWriteDump
{
- [UnsupportedOSPlatform("browser")]
public static void CollectDumpUsingMiniDumpWriteDump(int pid, string outputFile, MiniDumpTypeOption type)
{
using var process = Process.GetProcessById(pid);
@@ -112,3 +112,4 @@ internal enum MiniDumpTypeOption
Mini,
}
}
+#endif
diff --git a/src/Platform/Microsoft.Testing.Extensions.HotReload/BannedSymbols.txt b/src/Platform/Microsoft.Testing.Extensions.HotReload/BannedSymbols.txt
index 6b0c437d6e..64ef236c50 100644
--- a/src/Platform/Microsoft.Testing.Extensions.HotReload/BannedSymbols.txt
+++ b/src/Platform/Microsoft.Testing.Extensions.HotReload/BannedSymbols.txt
@@ -1,5 +1,4 @@
-T:System.ArgumentNullException; Use 'Guard' instead
-P:System.DateTime.Now; Use 'IClock' instead
+P:System.DateTime.Now; Use 'IClock' instead
P:System.DateTime.UtcNow; Use 'IClock' instead
M:System.Threading.Tasks.Task.Run(System.Action); Use 'ITask' instead
M:System.Threading.Tasks.Task.WhenAll(System.Threading.Tasks.Task[]); Use 'ITask' instead
diff --git a/src/Platform/Microsoft.Testing.Extensions.HotReload/HotReloadHandler.cs b/src/Platform/Microsoft.Testing.Extensions.HotReload/HotReloadHandler.cs
index 28426efe70..7821028351 100644
--- a/src/Platform/Microsoft.Testing.Extensions.HotReload/HotReloadHandler.cs
+++ b/src/Platform/Microsoft.Testing.Extensions.HotReload/HotReloadHandler.cs
@@ -14,6 +14,10 @@
[assembly: MetadataUpdateHandler(typeof(HotReloadHandler))]
#endif
+#if !NETCOREAPP
+using Polyfills;
+#endif
+
namespace Microsoft.Testing.Extensions.Hosting;
internal sealed class HotReloadHandler
diff --git a/src/Platform/Microsoft.Testing.Extensions.HotReload/Microsoft.Testing.Extensions.HotReload.csproj b/src/Platform/Microsoft.Testing.Extensions.HotReload/Microsoft.Testing.Extensions.HotReload.csproj
index 5c4f85a4ff..1af9733bc9 100644
--- a/src/Platform/Microsoft.Testing.Extensions.HotReload/Microsoft.Testing.Extensions.HotReload.csproj
+++ b/src/Platform/Microsoft.Testing.Extensions.HotReload/Microsoft.Testing.Extensions.HotReload.csproj
@@ -29,7 +29,7 @@ This package extends Microsoft Testing Platform to provide Hot Reload support.]]
-
+
diff --git a/src/Platform/Microsoft.Testing.Extensions.MSBuild/MSBuildExtensions.cs b/src/Platform/Microsoft.Testing.Extensions.MSBuild/MSBuildExtensions.cs
index 224a5dfce8..953e1148d5 100644
--- a/src/Platform/Microsoft.Testing.Extensions.MSBuild/MSBuildExtensions.cs
+++ b/src/Platform/Microsoft.Testing.Extensions.MSBuild/MSBuildExtensions.cs
@@ -6,6 +6,10 @@
using Microsoft.Testing.Platform.Extensions;
using Microsoft.Testing.Platform.Services;
+#if !NETCOREAPP
+using Polyfills;
+#endif
+
namespace Microsoft.Testing.Platform.MSBuild;
///
diff --git a/src/Platform/Microsoft.Testing.Extensions.MSBuild/Microsoft.Testing.Extensions.MSBuild.csproj b/src/Platform/Microsoft.Testing.Extensions.MSBuild/Microsoft.Testing.Extensions.MSBuild.csproj
index c5bf06bfbf..ffce9c36df 100644
--- a/src/Platform/Microsoft.Testing.Extensions.MSBuild/Microsoft.Testing.Extensions.MSBuild.csproj
+++ b/src/Platform/Microsoft.Testing.Extensions.MSBuild/Microsoft.Testing.Extensions.MSBuild.csproj
@@ -28,7 +28,7 @@
-
+
diff --git a/src/Platform/Microsoft.Testing.Extensions.OpenTelemetry/Microsoft.Testing.Extensions.OpenTelemetry.csproj b/src/Platform/Microsoft.Testing.Extensions.OpenTelemetry/Microsoft.Testing.Extensions.OpenTelemetry.csproj
index 276c796200..1a5a8dfb48 100644
--- a/src/Platform/Microsoft.Testing.Extensions.OpenTelemetry/Microsoft.Testing.Extensions.OpenTelemetry.csproj
+++ b/src/Platform/Microsoft.Testing.Extensions.OpenTelemetry/Microsoft.Testing.Extensions.OpenTelemetry.csproj
@@ -29,11 +29,10 @@ This package provides Open Telemetry for the platform.]]>
-
-
+
diff --git a/src/Platform/Microsoft.Testing.Extensions.Retry/BannedSymbols.txt b/src/Platform/Microsoft.Testing.Extensions.Retry/BannedSymbols.txt
index 7be39f73d1..2a7440f410 100644
--- a/src/Platform/Microsoft.Testing.Extensions.Retry/BannedSymbols.txt
+++ b/src/Platform/Microsoft.Testing.Extensions.Retry/BannedSymbols.txt
@@ -1,5 +1,4 @@
-T:System.ArgumentNullException; Use 'Guard' instead
-P:System.DateTime.Now; Use 'IClock' instead
+P:System.DateTime.Now; Use 'IClock' instead
P:System.DateTime.UtcNow; Use 'IClock' instead
M:System.Threading.Tasks.Task.Run(System.Action); Use 'ITask' instead
M:System.Threading.Tasks.Task.WhenAll(System.Threading.Tasks.Task[]); Use 'ITask' instead
diff --git a/src/Platform/Microsoft.Testing.Extensions.Retry/Microsoft.Testing.Extensions.Retry.csproj b/src/Platform/Microsoft.Testing.Extensions.Retry/Microsoft.Testing.Extensions.Retry.csproj
index 7c6b529f5b..8d50a5b6c7 100644
--- a/src/Platform/Microsoft.Testing.Extensions.Retry/Microsoft.Testing.Extensions.Retry.csproj
+++ b/src/Platform/Microsoft.Testing.Extensions.Retry/Microsoft.Testing.Extensions.Retry.csproj
@@ -40,7 +40,7 @@ This package extends Microsoft Testing Platform to provide a retry policy system
-
+
diff --git a/src/Platform/Microsoft.Testing.Extensions.Retry/RetryExtensions.cs b/src/Platform/Microsoft.Testing.Extensions.Retry/RetryExtensions.cs
index 404fce2aaf..68f4d7f923 100644
--- a/src/Platform/Microsoft.Testing.Extensions.Retry/RetryExtensions.cs
+++ b/src/Platform/Microsoft.Testing.Extensions.Retry/RetryExtensions.cs
@@ -7,6 +7,10 @@
using Microsoft.Testing.Platform.Extensions;
using Microsoft.Testing.Platform.TestHost;
+#if !NETCOREAPP
+using Polyfills;
+#endif
+
namespace Microsoft.Testing.Extensions;
///
diff --git a/src/Platform/Microsoft.Testing.Extensions.Telemetry/AppInsightsProvider.cs b/src/Platform/Microsoft.Testing.Extensions.Telemetry/AppInsightsProvider.cs
index eafc424bfe..7d9cc606c1 100644
--- a/src/Platform/Microsoft.Testing.Extensions.Telemetry/AppInsightsProvider.cs
+++ b/src/Platform/Microsoft.Testing.Extensions.Telemetry/AppInsightsProvider.cs
@@ -192,14 +192,14 @@ private async Task IngestLoopAsync()
{
StringBuilder builder = new();
builder.AppendLine(CultureInfo.InvariantCulture, $"Send telemetry event: {eventName}");
- foreach ((string key, string value) in properties)
+ foreach (KeyValuePair kvp in properties)
{
- builder.AppendLine(CultureInfo.InvariantCulture, $" {key}: {value}");
+ builder.AppendLine(CultureInfo.InvariantCulture, $" {kvp.Key}: {kvp.Value}");
}
- foreach ((string key, double value) in metrics)
+ foreach (KeyValuePair kvp in metrics)
{
- builder.AppendLine(CultureInfo.InvariantCulture, $" {key}: {value.ToString("f", CultureInfo.InvariantCulture)}");
+ builder.AppendLine(CultureInfo.InvariantCulture, $" {kvp.Key}: {kvp.Value.ToString("f", CultureInfo.InvariantCulture)}");
}
await _logger.LogTraceAsync(builder.ToString()).ConfigureAwait(false);
diff --git a/src/Platform/Microsoft.Testing.Extensions.Telemetry/Microsoft.Testing.Extensions.Telemetry.csproj b/src/Platform/Microsoft.Testing.Extensions.Telemetry/Microsoft.Testing.Extensions.Telemetry.csproj
index 3d8e7ce51c..7aebf8abb5 100644
--- a/src/Platform/Microsoft.Testing.Extensions.Telemetry/Microsoft.Testing.Extensions.Telemetry.csproj
+++ b/src/Platform/Microsoft.Testing.Extensions.Telemetry/Microsoft.Testing.Extensions.Telemetry.csproj
@@ -48,7 +48,6 @@ This package provides telemetry for the platform.]]>
-
@@ -60,7 +59,7 @@ This package provides telemetry for the platform.]]>
-
+
diff --git a/src/Platform/Microsoft.Testing.Extensions.TrxReport.Abstractions/BannedSymbols.txt b/src/Platform/Microsoft.Testing.Extensions.TrxReport.Abstractions/BannedSymbols.txt
index 09d715c49c..64ef236c50 100644
--- a/src/Platform/Microsoft.Testing.Extensions.TrxReport.Abstractions/BannedSymbols.txt
+++ b/src/Platform/Microsoft.Testing.Extensions.TrxReport.Abstractions/BannedSymbols.txt
@@ -1,5 +1,4 @@
-T:System.ArgumentNullException; Use 'ArgumentGuard' instead
-P:System.DateTime.Now; Use 'IClock' instead
+P:System.DateTime.Now; Use 'IClock' instead
P:System.DateTime.UtcNow; Use 'IClock' instead
M:System.Threading.Tasks.Task.Run(System.Action); Use 'ITask' instead
M:System.Threading.Tasks.Task.WhenAll(System.Threading.Tasks.Task[]); Use 'ITask' instead
diff --git a/src/Platform/Microsoft.Testing.Extensions.TrxReport.Abstractions/Microsoft.Testing.Extensions.TrxReport.Abstractions.csproj b/src/Platform/Microsoft.Testing.Extensions.TrxReport.Abstractions/Microsoft.Testing.Extensions.TrxReport.Abstractions.csproj
index 2ad2e8b49a..43beebafb8 100644
--- a/src/Platform/Microsoft.Testing.Extensions.TrxReport.Abstractions/Microsoft.Testing.Extensions.TrxReport.Abstractions.csproj
+++ b/src/Platform/Microsoft.Testing.Extensions.TrxReport.Abstractions/Microsoft.Testing.Extensions.TrxReport.Abstractions.csproj
@@ -16,11 +16,7 @@
-
-
-
-
-
+
diff --git a/src/Platform/Microsoft.Testing.Extensions.TrxReport.Abstractions/TrxReportProperties.cs b/src/Platform/Microsoft.Testing.Extensions.TrxReport.Abstractions/TrxReportProperties.cs
index 58d45e4283..285373a7da 100644
--- a/src/Platform/Microsoft.Testing.Extensions.TrxReport.Abstractions/TrxReportProperties.cs
+++ b/src/Platform/Microsoft.Testing.Extensions.TrxReport.Abstractions/TrxReportProperties.cs
@@ -198,7 +198,16 @@ public override string ToString()
builder.Append(" { ");
builder.Append($"{nameof(Messages)} = [");
- builder.AppendJoin(", ", Messages.Select(x => x.ToString()));
+
+ for (int i = 0; i < Messages.Length; i++)
+ {
+ builder.Append(Messages[i].ToString());
+ if (i < Messages.Length - 1)
+ {
+ builder.Append(", ");
+ }
+ }
+
builder.Append(']');
builder.Append(" }");
return builder.ToString();
@@ -229,7 +238,16 @@ public override string ToString()
builder.Append(nameof(TrxCategoriesProperty));
builder.Append(" { ");
builder.Append($"{nameof(Categories)} = [");
- builder.AppendJoin(", ", Categories);
+
+ for (int i = 0; i < Categories.Length; i++)
+ {
+ builder.Append(Categories[i]);
+ if (i < Categories.Length - 1)
+ {
+ builder.Append(", ");
+ }
+ }
+
builder.Append(']');
builder.Append(" }");
return builder.ToString();
diff --git a/src/Platform/Microsoft.Testing.Extensions.TrxReport/BannedSymbols.txt b/src/Platform/Microsoft.Testing.Extensions.TrxReport/BannedSymbols.txt
index 09d715c49c..64ef236c50 100644
--- a/src/Platform/Microsoft.Testing.Extensions.TrxReport/BannedSymbols.txt
+++ b/src/Platform/Microsoft.Testing.Extensions.TrxReport/BannedSymbols.txt
@@ -1,5 +1,4 @@
-T:System.ArgumentNullException; Use 'ArgumentGuard' instead
-P:System.DateTime.Now; Use 'IClock' instead
+P:System.DateTime.Now; Use 'IClock' instead
P:System.DateTime.UtcNow; Use 'IClock' instead
M:System.Threading.Tasks.Task.Run(System.Action); Use 'ITask' instead
M:System.Threading.Tasks.Task.WhenAll(System.Threading.Tasks.Task[]); Use 'ITask' instead
diff --git a/src/Platform/Microsoft.Testing.Extensions.TrxReport/Microsoft.Testing.Extensions.TrxReport.csproj b/src/Platform/Microsoft.Testing.Extensions.TrxReport/Microsoft.Testing.Extensions.TrxReport.csproj
index d9f92058ae..fd807bce97 100644
--- a/src/Platform/Microsoft.Testing.Extensions.TrxReport/Microsoft.Testing.Extensions.TrxReport.csproj
+++ b/src/Platform/Microsoft.Testing.Extensions.TrxReport/Microsoft.Testing.Extensions.TrxReport.csproj
@@ -64,7 +64,7 @@ This package extends Microsoft Testing Platform to provide TRX test reports.]]>
-
+
@@ -74,10 +74,6 @@ This package extends Microsoft Testing Platform to provide TRX test reports.]]>
-
-
-
-
diff --git a/src/Platform/Microsoft.Testing.Extensions.TrxReport/TrxCompareTool.cs b/src/Platform/Microsoft.Testing.Extensions.TrxReport/TrxCompareTool.cs
index fce5f10989..5dbb643375 100644
--- a/src/Platform/Microsoft.Testing.Extensions.TrxReport/TrxCompareTool.cs
+++ b/src/Platform/Microsoft.Testing.Extensions.TrxReport/TrxCompareTool.cs
@@ -180,7 +180,12 @@ private static void AppendResultsAndIssues(string category, string filePath,
private static async Task CollectEntriesAndErrorsAsync(string trxFile, XNamespace ns, List results, List issues)
{
using FileStream stream = File.OpenRead(trxFile);
+#if NETCOREAPP
XElement trxTestRun = await XElement.LoadAsync(stream, LoadOptions.None, CancellationToken.None).ConfigureAwait(false);
+#else
+ var trxTestRun = XElement.Load(stream, LoadOptions.None);
+#endif
+
int testResultIndex = 0;
foreach (XElement testResult in trxTestRun.Elements(ns + "Results").Elements(ns + "UnitTestResult"))
{
diff --git a/src/Platform/Microsoft.Testing.Extensions.TrxReport/TrxDataConsumer.cs b/src/Platform/Microsoft.Testing.Extensions.TrxReport/TrxDataConsumer.cs
index d22516738a..80460a8577 100644
--- a/src/Platform/Microsoft.Testing.Extensions.TrxReport/TrxDataConsumer.cs
+++ b/src/Platform/Microsoft.Testing.Extensions.TrxReport/TrxDataConsumer.cs
@@ -191,9 +191,23 @@ public async Task OnTestSessionFinishingAsync(ITestSessionContext testSessionCon
ApplicationStateGuard.Ensure(_testStartTime is not null);
int exitCode = _testApplicationProcessExitCode.GetProcessExitCode();
- var trxReportGeneratorEngine = new TrxReportEngine(_fileSystem, _testApplicationModuleInfo, _environment, _commandLineOptionsService, _configuration,
- _clock, _artifactsByExtension,
- _testFramework, _testStartTime.Value, exitCode, cancellationToken);
+ var trxReportGeneratorEngine = new TrxReportEngine(
+ _fileSystem,
+ _testApplicationModuleInfo,
+ _environment,
+ _commandLineOptionsService,
+ _configuration,
+ _clock,
+ _artifactsByExtension,
+ _testFramework,
+ _testStartTime.Value,
+#if NETCOREAPP
+ exitCode,
+ cancellationToken);
+#else
+ exitCode);
+#endif
+
(string reportFileName, string? warning) = await trxReportGeneratorEngine.GenerateReportAsync([.. _tests]).ConfigureAwait(false);
if (warning is not null)
{
diff --git a/src/Platform/Microsoft.Testing.Extensions.TrxReport/TrxModeHelpers.cs b/src/Platform/Microsoft.Testing.Extensions.TrxReport/TrxModeHelpers.cs
index efcd1ba83f..753a155420 100644
--- a/src/Platform/Microsoft.Testing.Extensions.TrxReport/TrxModeHelpers.cs
+++ b/src/Platform/Microsoft.Testing.Extensions.TrxReport/TrxModeHelpers.cs
@@ -3,6 +3,10 @@
using Microsoft.Testing.Platform.CommandLine;
+#if !NETCOREAPP
+using Polyfills;
+#endif
+
namespace Microsoft.Testing.Extensions.TrxReport;
internal static class TrxModeHelpers
@@ -10,5 +14,5 @@ internal static class TrxModeHelpers
[UnsupportedOSPlatformGuard("BROWSER")]
public static bool ShouldUseOutOfProcessTrxGeneration(ICommandLineOptions commandLineOptions)
=> commandLineOptions.IsOptionSet(CrashDumpCommandLineOptions.CrashDumpOptionName) &&
- !OperatingSystem.IsBrowser();
+ !OperatingSystem.IsBrowser();
}
diff --git a/src/Platform/Microsoft.Testing.Extensions.TrxReport/TrxProcessLifetimeHandler.cs b/src/Platform/Microsoft.Testing.Extensions.TrxReport/TrxProcessLifetimeHandler.cs
index 21a57d9588..75f7a507cd 100644
--- a/src/Platform/Microsoft.Testing.Extensions.TrxReport/TrxProcessLifetimeHandler.cs
+++ b/src/Platform/Microsoft.Testing.Extensions.TrxReport/TrxProcessLifetimeHandler.cs
@@ -177,13 +177,22 @@ public async Task OnTestHostProcessExitedAsync(ITestHostProcessInformation testH
// If _fileNameRequest is null, that means that the TestHost crashed before it wrote the TRX file.
if (_fileNameRequest is null)
{
- var trxReportGeneratorEngine = new TrxReportEngine(_fileSystem, _testApplicationModuleInfo, _environment, _commandLineOptions, _configuration,
+ var trxReportGeneratorEngine = new TrxReportEngine(
+ _fileSystem,
+ _testApplicationModuleInfo,
+ _environment,
+ _commandLineOptions,
+ _configuration,
_clock,
artifacts,
new TestAdapterInfo(_testAdapterInformationRequest!.TestAdapterId, _testAdapterInformationRequest.TestAdapterVersion),
_startTime,
+#if NETCOREAPP
testHostProcessInformation.ExitCode,
cancellationToken);
+#else
+ testHostProcessInformation.ExitCode);
+#endif
(string fileName, string? warning) = await trxReportGeneratorEngine.GenerateReportAsync(
[],
@@ -213,13 +222,22 @@ await _messageBus.PublishAsync(
// Add attachments to the trx.
if (_fileArtifacts.Count > 0)
{
- var trxReportGeneratorEngine = new TrxReportEngine(_fileSystem, _testApplicationModuleInfo, _environment, _commandLineOptions, _configuration,
- _clock,
- artifacts,
- new TestAdapterInfo(_testAdapterInformationRequest!.TestAdapterId, _testAdapterInformationRequest.TestAdapterVersion),
- _startTime,
- testHostProcessInformation.ExitCode,
- cancellationToken);
+ var trxReportGeneratorEngine = new TrxReportEngine(
+ _fileSystem,
+ _testApplicationModuleInfo,
+ _environment,
+ _commandLineOptions,
+ _configuration,
+ _clock,
+ artifacts,
+ new TestAdapterInfo(_testAdapterInformationRequest!.TestAdapterId, _testAdapterInformationRequest.TestAdapterVersion),
+ _startTime,
+#if NETCOREAPP
+ testHostProcessInformation.ExitCode,
+ cancellationToken);
+#else
+ testHostProcessInformation.ExitCode);
+#endif
await trxReportGeneratorEngine.AddArtifactsAsync(trxFile, artifacts).ConfigureAwait(false);
}
diff --git a/src/Platform/Microsoft.Testing.Extensions.TrxReport/TrxReportEngine.cs b/src/Platform/Microsoft.Testing.Extensions.TrxReport/TrxReportEngine.cs
index d32cb388db..61ebb27157 100644
--- a/src/Platform/Microsoft.Testing.Extensions.TrxReport/TrxReportEngine.cs
+++ b/src/Platform/Microsoft.Testing.Extensions.TrxReport/TrxReportEngine.cs
@@ -83,11 +83,28 @@ internal sealed partial class TrxReportEngine
private readonly Dictionary> _artifactsByExtension;
private readonly ITestFramework _testFrameworkAdapter;
private readonly DateTimeOffset _testStartTime;
+#if NETCOREAPP
private readonly CancellationToken _cancellationToken;
+#endif
private readonly int _exitCode;
private readonly IFileSystem _fileSystem;
- public TrxReportEngine(IFileSystem fileSystem, ITestApplicationModuleInfo testApplicationModuleInfo, IEnvironment environment, ICommandLineOptions commandLineOptionsService, IConfiguration configuration, IClock clock, Dictionary> artifactsByExtension, ITestFramework testFrameworkAdapter, DateTimeOffset testStartTime, int exitCode, CancellationToken cancellationToken)
+ public TrxReportEngine(
+ IFileSystem fileSystem,
+ ITestApplicationModuleInfo testApplicationModuleInfo,
+ IEnvironment environment,
+ ICommandLineOptions commandLineOptionsService,
+ IConfiguration configuration,
+ IClock clock,
+ Dictionary> artifactsByExtension,
+ ITestFramework testFrameworkAdapter,
+ DateTimeOffset testStartTime,
+#if NETCOREAPP
+ int exitCode,
+ CancellationToken cancellationToken)
+#else
+ int exitCode)
+#endif
{
_testApplicationModuleInfo = testApplicationModuleInfo;
_environment = environment;
@@ -97,7 +114,9 @@ public TrxReportEngine(IFileSystem fileSystem, ITestApplicationModuleInfo testAp
_artifactsByExtension = artifactsByExtension;
_testFrameworkAdapter = testFrameworkAdapter;
_testStartTime = testStartTime;
+#if NETCOREAPP
_cancellationToken = cancellationToken;
+#endif
_exitCode = exitCode;
_fileSystem = fileSystem;
}
@@ -174,7 +193,11 @@ public TrxReportEngine(IFileSystem fileSystem, ITestApplicationModuleInfo testAp
// Note that we need to dispose the IFileStream, not the inner stream.
// IFileStream implementations will be responsible to dispose their inner stream.
using IFileStream stream = _fileSystem.NewFileStream(finalFileName, isFileNameExplicitlyProvided ? FileMode.Create : FileMode.CreateNew);
+#if NETCOREAPP
await document.SaveAsync(stream.Stream, SaveOptions.None, _cancellationToken).ConfigureAwait(false);
+#else
+ document.Save(stream.Stream, SaveOptions.None);
+#endif
return isFileNameExplicitlyProvidedAndFileExists
? (finalFileName, string.Format(CultureInfo.InvariantCulture, ExtensionResources.TrxFileExistsAndWillBeOverwritten, finalFileName))
: (finalFileName, null);
@@ -228,7 +251,11 @@ public async Task AddArtifactsAsync(FileInfo trxFile, Dictionary> artifacts, XElement collectorDataEntries, string runDeploymentRoot)
diff --git a/src/Platform/Microsoft.Testing.Extensions.TrxReport/TrxReportExtensions.cs b/src/Platform/Microsoft.Testing.Extensions.TrxReport/TrxReportExtensions.cs
index d0bfbffc1a..6219790214 100644
--- a/src/Platform/Microsoft.Testing.Extensions.TrxReport/TrxReportExtensions.cs
+++ b/src/Platform/Microsoft.Testing.Extensions.TrxReport/TrxReportExtensions.cs
@@ -11,6 +11,10 @@
using Microsoft.Testing.Platform.Services;
using Microsoft.Testing.Platform.TestHostControllers;
+#if !NETCOREAPP
+using Polyfills;
+#endif
+
namespace Microsoft.Testing.Extensions;
///
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 e6df831a7a..9083c8659c 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
@@ -17,10 +17,13 @@
-
+
+
+
+
@@ -41,8 +44,4 @@ This package provides a bridge integration for test adapters wanting to target b
-
-
-
-
diff --git a/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/VSTestBridgedTestFrameworkBase.cs b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/VSTestBridgedTestFrameworkBase.cs
index 8947174a9f..84b1b3c677 100644
--- a/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/VSTestBridgedTestFrameworkBase.cs
+++ b/src/Platform/Microsoft.Testing.Extensions.VSTestBridge/VSTestBridgedTestFrameworkBase.cs
@@ -29,8 +29,7 @@ public abstract class VSTestBridgedTestFrameworkBase : ITestFramework, IDataProd
/// The test framework capabilities.
protected VSTestBridgedTestFrameworkBase(IServiceProvider serviceProvider, ITestFrameworkCapabilities capabilities)
{
- Ensure.NotNull(serviceProvider);
- ServiceProvider = serviceProvider;
+ ServiceProvider = serviceProvider ?? throw new ArgumentNullException(nameof(serviceProvider));
// NOTE: It's too early to determine from the capability at this point whether or not trx is enabled.
// We store the capability and check it later when IsTrxEnabled is accessed.
_trxReportCapability = capabilities.GetCapability();
diff --git a/src/Platform/Microsoft.Testing.Platform.AI/Microsoft.Testing.Platform.AI.csproj b/src/Platform/Microsoft.Testing.Platform.AI/Microsoft.Testing.Platform.AI.csproj
index 402bba36b9..1c763e42eb 100644
--- a/src/Platform/Microsoft.Testing.Platform.AI/Microsoft.Testing.Platform.AI.csproj
+++ b/src/Platform/Microsoft.Testing.Platform.AI/Microsoft.Testing.Platform.AI.csproj
@@ -13,7 +13,10 @@
-
+
+
+
+
diff --git a/src/Platform/Microsoft.Testing.Platform.MSBuild/Microsoft.Testing.Platform.MSBuild.csproj b/src/Platform/Microsoft.Testing.Platform.MSBuild/Microsoft.Testing.Platform.MSBuild.csproj
index 6eb4132a3d..9184c4549d 100644
--- a/src/Platform/Microsoft.Testing.Platform.MSBuild/Microsoft.Testing.Platform.MSBuild.csproj
+++ b/src/Platform/Microsoft.Testing.Platform.MSBuild/Microsoft.Testing.Platform.MSBuild.csproj
@@ -29,7 +29,10 @@
-
+
+
+
+
diff --git a/src/Platform/Microsoft.Testing.Platform.MSBuild/Tasks/ConfigurationFileTask.cs b/src/Platform/Microsoft.Testing.Platform.MSBuild/Tasks/ConfigurationFileTask.cs
index d9f67c5476..1c885722d1 100644
--- a/src/Platform/Microsoft.Testing.Platform.MSBuild/Tasks/ConfigurationFileTask.cs
+++ b/src/Platform/Microsoft.Testing.Platform.MSBuild/Tasks/ConfigurationFileTask.cs
@@ -17,11 +17,8 @@ public sealed class ConfigurationFileTask : Build.Utilities.Task
private const string ConfigurationFileNameSuffix = "testconfig.json";
private readonly IFileSystem _fileSystem;
- internal ConfigurationFileTask(IFileSystem? fileSystem)
- {
- Ensure.NotNull(fileSystem);
- _fileSystem = fileSystem;
- }
+ internal ConfigurationFileTask(IFileSystem fileSystem)
+ => _fileSystem = fileSystem ?? throw new ArgumentNullException(nameof(fileSystem));
///
/// Initializes a new instance of the class.
diff --git a/src/Platform/Microsoft.Testing.Platform.MSBuild/Tasks/InvokeTestingPlatformTask.cs b/src/Platform/Microsoft.Testing.Platform.MSBuild/Tasks/InvokeTestingPlatformTask.cs
index 544781520b..5b3fec02c0 100644
--- a/src/Platform/Microsoft.Testing.Platform.MSBuild/Tasks/InvokeTestingPlatformTask.cs
+++ b/src/Platform/Microsoft.Testing.Platform.MSBuild/Tasks/InvokeTestingPlatformTask.cs
@@ -34,7 +34,13 @@ public class InvokeTestingPlatformTask : Build.Utilities.ToolTask, IDisposable
private readonly CancellationTokenSource _waitForConnections = new();
private readonly List _connections = [];
private readonly StringBuilder _output = new();
+
+#if NET9_0_OR_GREATER
private readonly Lock _initLock = new();
+#else
+ private readonly object _initLock = new();
+#endif
+
private readonly Architecture _currentProcessArchitecture = RuntimeInformation.ProcessArchitecture;
private Task? _connectionLoopTask;
@@ -208,7 +214,12 @@ protected override string ToolName
}
Log.LogMessage(MessageImportance.Low, $"Current process architecture '{_currentProcessArchitecture}'. Requested test architecture '{TestArchitecture.ItemSpec}'");
+
+#if NETCOREAPP
PlatformArchitecture targetArchitecture = Enum.Parse(TestArchitecture.ItemSpec, ignoreCase: true);
+#else
+ var targetArchitecture = (PlatformArchitecture)Enum.Parse(typeof(PlatformArchitecture), TestArchitecture.ItemSpec, ignoreCase: true);
+#endif
StringBuilder resolutionLog = new();
DotnetMuxerLocator dotnetMuxerLocator = new(log => resolutionLog.AppendLine(log));
if (dotnetMuxerLocator.TryGetDotnetPathByArchitecture(targetArchitecture, out string? dotnetPath))
@@ -242,7 +253,11 @@ protected override string ToolName
}
private bool IsCurrentProcessArchitectureCompatible() =>
+#if NETCOREAPP
_currentProcessArchitecture == Enum.Parse(TestArchitecture.ItemSpec, ignoreCase: true);
+#else
+ _currentProcessArchitecture == (Architecture)Enum.Parse(typeof(Architecture), TestArchitecture.ItemSpec, ignoreCase: true);
+#endif
private string? TryGetRunCommand()
{
diff --git a/src/Platform/Microsoft.Testing.Platform/BannedSymbols.txt b/src/Platform/Microsoft.Testing.Platform/BannedSymbols.txt
index 96906f3552..970d4b8294 100644
--- a/src/Platform/Microsoft.Testing.Platform/BannedSymbols.txt
+++ b/src/Platform/Microsoft.Testing.Platform/BannedSymbols.txt
@@ -1,6 +1,4 @@
-M:System.ArgumentNullException.ThrowIfNull(System.Object,System.String); Use 'ArgumentGuard' class instead
-M:System.ArgumentNullException.#ctor; Use 'ArgumentGuard' class instead
-P:System.DateTime.Now; Use 'IClock' instead
+P:System.DateTime.Now; Use 'IClock' instead
P:System.DateTime.UtcNow; Use 'IClock' instead
T:System.Environment; Use 'IEnvironment' instead
M:System.Diagnostics.Process.GetCurrentProcess(); Use 'IProcess' instead
diff --git a/src/Platform/Microsoft.Testing.Platform/Builder/TestApplication.cs b/src/Platform/Microsoft.Testing.Platform/Builder/TestApplication.cs
index b0b5f331e0..1421a35431 100644
--- a/src/Platform/Microsoft.Testing.Platform/Builder/TestApplication.cs
+++ b/src/Platform/Microsoft.Testing.Platform/Builder/TestApplication.cs
@@ -81,10 +81,8 @@ public static async Task CreateBuilderAsync(string[] ar
{
throw new PlatformNotSupportedException(PlatformResources.WaitDebuggerAttachNotSupportedInBrowserErrorMessage);
}
- else
- {
- WaitForDebuggerToAttach(systemEnvironment, systemConsole, systemProcess);
- }
+
+ WaitForDebuggerToAttach(systemEnvironment, systemConsole, systemProcess);
}
TestHostControllerInfo testHostControllerInfo = new(parseResult);
@@ -235,10 +233,8 @@ private static void AttachDebuggerIfNeeded(SystemEnvironment environment, System
{
throw new PlatformNotSupportedException(PlatformResources.WaitDebuggerAttachNotSupportedInBrowserErrorMessage);
}
- else
- {
- WaitForDebuggerToAttach(environment, console, systemProcess);
- }
+
+ WaitForDebuggerToAttach(environment, console, systemProcess);
}
}
@@ -294,7 +290,11 @@ private static ApplicationLoggingState CreateFileLoggerIfDiagnosticIsEnabled(
if (result.TryGetOptionArgumentList(PlatformCommandLineProvider.DiagnosticVerbosityOptionKey, out string[]? verbosity))
{
+#if NETCOREAPP
logLevel = Enum.Parse(verbosity[0], true);
+#else
+ logLevel = (LogLevel)Enum.Parse(typeof(LogLevel), verbosity[0], true);
+#endif
}
// Override the log level if the environment variable is set
diff --git a/src/Platform/Microsoft.Testing.Platform/CommandLine/Parser.cs b/src/Platform/Microsoft.Testing.Platform/CommandLine/Parser.cs
index 58a06e7c63..6ce2d0ab8d 100644
--- a/src/Platform/Microsoft.Testing.Platform/CommandLine/Parser.cs
+++ b/src/Platform/Microsoft.Testing.Platform/CommandLine/Parser.cs
@@ -46,7 +46,7 @@ private static CommandLineParseResult Parse(List args, IEnvironment envi
{
string? currentArg = args[i];
- if (currentArg.StartsWith('@') && ResponseFileHelper.TryReadResponseFile(currentArg.Substring(1), errors, out string[]? newArguments))
+ if (currentArg.StartsWith("@", StringComparison.Ordinal) && ResponseFileHelper.TryReadResponseFile(currentArg.Substring(1), errors, out string[]? newArguments))
{
args.InsertRange(i + 1, newArguments);
continue;
@@ -121,7 +121,7 @@ static bool TryUnescape(string input, string? option, IEnvironment environment,
// Enclosing characters in single-quotes ( '' ) shall preserve the literal value of each character within the single-quotes.
// A single-quote cannot occur within single-quotes.
- if (input.StartsWith('\'') && input.EndsWith('\''))
+ if (input.StartsWith("\'", StringComparison.Ordinal) && input.EndsWith("\'", StringComparison.Ordinal))
{
if (input.IndexOf('\'', 1, input.Length - 2) != -1)
{
@@ -141,7 +141,7 @@ static bool TryUnescape(string input, string? option, IEnvironment environment,
// * The shall retain its special meaning introducing parameter expansion. [NOT SUPPORTED]
// * The backslash shall retain its special meaning as an escape character only when followed by one of the following characters when considered special:
// $ ` " \
- if (input.StartsWith('"') && input.EndsWith('"'))
+ if (input.StartsWith("\"", StringComparison.Ordinal) && input.EndsWith("\"", StringComparison.Ordinal))
{
unescapedArg = input[1..^1].Replace(@"\\", "\\")
.Replace(@"\""", "\"")
diff --git a/src/Platform/Microsoft.Testing.Platform/Configurations/ConfigurationExtensions.cs b/src/Platform/Microsoft.Testing.Platform/Configurations/ConfigurationExtensions.cs
index 0462e1f0df..116217d5fb 100644
--- a/src/Platform/Microsoft.Testing.Platform/Configurations/ConfigurationExtensions.cs
+++ b/src/Platform/Microsoft.Testing.Platform/Configurations/ConfigurationExtensions.cs
@@ -1,6 +1,8 @@
// 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.Helpers;
+
namespace Microsoft.Testing.Platform.Configurations;
///
@@ -16,7 +18,7 @@ public static class ConfigurationExtensions
public static string GetTestResultDirectory(this IConfiguration configuration)
{
string? resultDirectory = configuration[PlatformConfigurationConstants.PlatformResultDirectory];
- return Ensure.NotNull(resultDirectory);
+ return resultDirectory ?? throw ApplicationStateGuard.Unreachable();
}
///
@@ -27,6 +29,6 @@ public static string GetTestResultDirectory(this IConfiguration configuration)
public static string GetCurrentWorkingDirectory(this IConfiguration configuration)
{
string? workingDirectory = configuration[PlatformConfigurationConstants.PlatformCurrentWorkingDirectory];
- return Ensure.NotNull(workingDirectory);
+ return workingDirectory ?? throw ApplicationStateGuard.Unreachable();
}
}
diff --git a/src/Platform/Microsoft.Testing.Platform/Configurations/EnvironmentVariablesConfigurationProvider.cs b/src/Platform/Microsoft.Testing.Platform/Configurations/EnvironmentVariablesConfigurationProvider.cs
index 3adf515856..31f068a7d3 100644
--- a/src/Platform/Microsoft.Testing.Platform/Configurations/EnvironmentVariablesConfigurationProvider.cs
+++ b/src/Platform/Microsoft.Testing.Platform/Configurations/EnvironmentVariablesConfigurationProvider.cs
@@ -74,7 +74,8 @@ public Task LoadAsync()
public bool TryGet(string key, out string? value)
{
- Ensure.NotNullOrEmpty(key, nameof(key));
+ _ = key ?? throw new ArgumentNullException(nameof(key));
+ Ensure.NotEmpty(key);
return _data.TryGetValue(key, out value);
}
diff --git a/src/Platform/Microsoft.Testing.Platform/Extensions/CompositeExtensionsFactory.cs b/src/Platform/Microsoft.Testing.Platform/Extensions/CompositeExtensionsFactory.cs
index c5113f0b2e..a7f21e3103 100644
--- a/src/Platform/Microsoft.Testing.Platform/Extensions/CompositeExtensionsFactory.cs
+++ b/src/Platform/Microsoft.Testing.Platform/Extensions/CompositeExtensionsFactory.cs
@@ -17,7 +17,12 @@ namespace Microsoft.Testing.Platform.Extensions;
public class CompositeExtensionFactory : ICompositeExtensionFactory, ICloneable
where TExtension : class, IExtension
{
+#if NET9_0_OR_GREATER
private readonly Lock _syncLock = new();
+#else
+ private readonly object _syncLock = new();
+#endif
+
private readonly Func? _factoryWithServiceProvider;
private readonly Func? _factory;
private TExtension? _instance;
@@ -35,20 +40,14 @@ You cannot compose extensions that belong to different areas.
///
/// The factory function that creates the extension with a service provider.
public CompositeExtensionFactory(Func factory)
- {
- Ensure.NotNull(factory);
- _factoryWithServiceProvider = factory;
- }
+ => _factoryWithServiceProvider = factory ?? throw new ArgumentNullException(nameof(factory));
///
/// Initializes a new instance of the class.
///
/// The factory function that creates the extension.
public CompositeExtensionFactory(Func factory)
- {
- Ensure.NotNull(factory);
- _factory = factory;
- }
+ => _factory = factory ?? throw new ArgumentNullException(nameof(factory));
///
object ICloneable.Clone()
diff --git a/src/Platform/Microsoft.Testing.Platform/Helpers/ExtensionValidationHelper.cs b/src/Platform/Microsoft.Testing.Platform/Helpers/ExtensionValidationHelper.cs
index 834763d9d7..cf10332bfa 100644
--- a/src/Platform/Microsoft.Testing.Platform/Helpers/ExtensionValidationHelper.cs
+++ b/src/Platform/Microsoft.Testing.Platform/Helpers/ExtensionValidationHelper.cs
@@ -18,9 +18,9 @@ internal static class ExtensionValidationHelper
/// Function to extract the IExtension from the collection item.
public static void ValidateUniqueExtension(this IEnumerable existingExtensions, IExtension newExtension, Func extensionSelector)
{
- Ensure.NotNull(existingExtensions);
- Ensure.NotNull(newExtension);
- Ensure.NotNull(extensionSelector);
+ _ = existingExtensions ?? throw new ArgumentNullException(nameof(existingExtensions));
+ _ = newExtension ?? throw new ArgumentNullException(nameof(newExtension));
+ _ = extensionSelector ?? throw new ArgumentNullException(nameof(extensionSelector));
T[] duplicates = [.. existingExtensions.Where(x => extensionSelector(x).Uid == newExtension.Uid)];
if (duplicates.Length > 0)
diff --git a/src/Platform/Microsoft.Testing.Platform/Helpers/Sha256Hasher.cs b/src/Platform/Microsoft.Testing.Platform/Helpers/Sha256Hasher.cs
index 019ce3a00d..46ed29371a 100644
--- a/src/Platform/Microsoft.Testing.Platform/Helpers/Sha256Hasher.cs
+++ b/src/Platform/Microsoft.Testing.Platform/Helpers/Sha256Hasher.cs
@@ -15,7 +15,62 @@ internal static class Sha256Hasher
public static string HashWithNormalizedCasing(string text)
{
byte[] bytes = Encoding.UTF8.GetBytes(text.ToUpperInvariant());
+#if NETCOREAPP
byte[] hash = SHA256.HashData(bytes);
+#else
+ using var sha256 = SHA256.Create();
+ byte[] hash = sha256.ComputeHash(bytes);
+#endif
+
+#if NET9_0_OR_GREATER
return Convert.ToHexStringLower(hash);
+#else
+ return ToHexStringLower(hash);
+#endif
+ }
+
+#if !NET9_0_OR_GREATER && NETCOREAPP
+ private static string ToHexStringLower(byte[] bytes)
+ => string.Create(bytes.Length * 2, bytes, static (chars, args) => EncodeToUtf16(args, chars));
+
+ private static void EncodeToUtf16(byte[] source, Span destination)
+ {
+ ApplicationStateGuard.Ensure(destination.Length >= (source.Length * 2));
+
+ for (int pos = 0; pos < source.Length; pos++)
+ {
+ ToCharsBuffer(source[pos], destination, pos * 2);
+ }
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static void ToCharsBuffer(byte value, Span buffer, int startingIndex = 0)
+ {
+#pragma warning disable IDE0004 // Remove Unnecessary Cast
+#pragma warning disable IDE0047 // Remove unnecessary parentheses
+ uint difference = (((uint)value & 0xF0U) << 4) + ((uint)value & 0x0FU) - 0x8989U;
+ uint packedResult = ((((uint)(-(int)difference) & 0x7070U) >> 4) + difference + 0xB9B9U) | (uint)0x2020U;
+
+ buffer[startingIndex + 1] = (char)(packedResult & 0xFF);
+ buffer[startingIndex] = (char)(packedResult >> 8);
+#pragma warning restore IDE0047 // Remove unnecessary parentheses
+#pragma warning restore IDE0004 // Remove Unnecessary Cast
+ }
+#elif !NETCOREAPP
+ private static string ToHexStringLower(byte[] bytes)
+ {
+ char[] chars = new char[bytes.Length * 2];
+
+ string hexAlphabet = "0123456789abcdef";
+ int charIndex = 0;
+ for (int i = 0; i < bytes.Length; i++)
+ {
+ byte b = bytes[i];
+ chars[charIndex++] = hexAlphabet[b >> 4];
+ chars[charIndex++] = hexAlphabet[b & 0xF];
+ }
+
+ return new string(chars);
}
+#endif
}
diff --git a/src/Platform/Microsoft.Testing.Platform/Helpers/System/SystemEnvironment.cs b/src/Platform/Microsoft.Testing.Platform/Helpers/System/SystemEnvironment.cs
index 5723b9cfa5..ece5ffc2ad 100644
--- a/src/Platform/Microsoft.Testing.Platform/Helpers/System/SystemEnvironment.cs
+++ b/src/Platform/Microsoft.Testing.Platform/Helpers/System/SystemEnvironment.cs
@@ -12,7 +12,31 @@ internal sealed class SystemEnvironment : IEnvironment
public string NewLine => Environment.NewLine;
+#if !NETCOREAPP
+ public int ProcessId
+ {
+ get
+ {
+ int processId = field;
+ if (processId == 0)
+ {
+ field = processId = GetProcessId();
+ // Assume that process Id zero is invalid for user processes. It holds for all mainstream operating systems.
+ Debug.Assert(processId != 0, "processId is expected to be non-zero.");
+ }
+
+ return processId;
+
+ static int GetProcessId()
+ {
+ using var process = Process.GetCurrentProcess();
+ return process.Id;
+ }
+ }
+ }
+#else
public int ProcessId => Environment.ProcessId;
+#endif
public string OsVersion => Environment.OSVersion.ToString();
diff --git a/src/Platform/Microsoft.Testing.Platform/Helpers/System/SystemFileSystem.cs b/src/Platform/Microsoft.Testing.Platform/Helpers/System/SystemFileSystem.cs
index d88cbf742a..98033e087c 100644
--- a/src/Platform/Microsoft.Testing.Platform/Helpers/System/SystemFileSystem.cs
+++ b/src/Platform/Microsoft.Testing.Platform/Helpers/System/SystemFileSystem.cs
@@ -9,7 +9,22 @@ internal sealed class SystemFileSystem : IFileSystem
public string CreateDirectory(string path) => Directory.CreateDirectory(path).FullName;
+#if NETCOREAPP
public void MoveFile(string sourceFileName, string destFileName, bool overwrite = false) => File.Move(sourceFileName, destFileName, overwrite);
+#else
+ public void MoveFile(string sourceFileName, string destFileName, bool overwrite = false)
+ {
+ if (overwrite)
+ {
+ File.Copy(sourceFileName, destFileName, overwrite: true);
+ File.Delete(sourceFileName);
+ }
+ else
+ {
+ File.Move(sourceFileName, destFileName);
+ }
+ }
+#endif
public IFileStream NewFileStream(string path, FileMode mode) => new SystemFileStream(path, mode);
@@ -17,7 +32,21 @@ internal sealed class SystemFileSystem : IFileSystem
public string ReadAllText(string path) => File.ReadAllText(path);
+#if NETCOREAPP
public Task ReadAllTextAsync(string path) => File.ReadAllTextAsync(path);
+#else
+ public Task ReadAllTextAsync(string path)
+ {
+ using StreamReader reader = AsyncStreamReader(path, Encoding.UTF8);
+ return reader.ReadToEndAsync();
+
+ static StreamReader AsyncStreamReader(string path, Encoding encoding)
+ {
+ var stream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, 4096, FileOptions.Asynchronous | FileOptions.SequentialScan);
+ return new(stream, encoding, detectEncodingFromByteOrderMarks: true);
+ }
+ }
+#endif
public void CopyFile(string sourceFileName, string destFileName, bool overwrite = false) => File.Copy(sourceFileName, destFileName, overwrite);
diff --git a/src/Platform/Microsoft.Testing.Platform/Helpers/System/SystemProcess.cs b/src/Platform/Microsoft.Testing.Platform/Helpers/System/SystemProcess.cs
index c3a680454b..3222589c3f 100644
--- a/src/Platform/Microsoft.Testing.Platform/Helpers/System/SystemProcess.cs
+++ b/src/Platform/Microsoft.Testing.Platform/Helpers/System/SystemProcess.cs
@@ -45,7 +45,11 @@ public Task WaitForExitAsync()
[UnsupportedOSPlatform("ios")]
[UnsupportedOSPlatform("tvos")]
public void Kill()
+#if NETCOREAPP
=> _process.Kill(entireProcessTree: true);
+#else
+ => _process.Kill();
+#endif
public void Dispose() => _process.Dispose();
}
diff --git a/src/Platform/Microsoft.Testing.Platform/Helpers/TaskExtensions.cs b/src/Platform/Microsoft.Testing.Platform/Helpers/TaskExtensions.cs
index ae1ac1c92c..925928da13 100644
--- a/src/Platform/Microsoft.Testing.Platform/Helpers/TaskExtensions.cs
+++ b/src/Platform/Microsoft.Testing.Platform/Helpers/TaskExtensions.cs
@@ -6,6 +6,89 @@ namespace Microsoft.Testing.Platform.Helpers;
// The idea was taken from https://github.com/dotnet/aspnetcore/blob/main/src/Shared/TaskExtensions.cs
internal static class TaskExtensions
{
+#if !NETCOREAPP
+ private const uint MaxSupportedTimeout = 0xfffffffe;
+
+ public static Task WaitAsync(this Task target, CancellationToken cancellationToken) =>
+ target.WaitAsync(Timeout.InfiniteTimeSpan, cancellationToken);
+
+ public static Task WaitAsync(
+ this Task target,
+ TimeSpan timeout) =>
+ target.WaitAsync(timeout, default);
+
+ public static async Task WaitAsync(
+ this Task target,
+ TimeSpan timeout,
+ CancellationToken cancellationToken)
+ {
+ long milliseconds = (long)timeout.TotalMilliseconds;
+ if (milliseconds is < -1 or > MaxSupportedTimeout)
+ {
+ throw new ArgumentOutOfRangeException(nameof(timeout));
+ }
+
+ if (target.IsCompleted ||
+ (!cancellationToken.CanBeCanceled && timeout == Timeout.InfiniteTimeSpan))
+ {
+ await target.ConfigureAwait(false);
+ return;
+ }
+
+ if (cancellationToken.IsCancellationRequested)
+ {
+ await Task.FromCanceled(cancellationToken).ConfigureAwait(false);
+ }
+
+ if (timeout == TimeSpan.Zero)
+ {
+ throw new TimeoutException();
+ }
+
+ using var cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
+ cts.CancelAfter(timeout);
+
+ var cancellationTask = new TaskCompletionSource();
+#pragma warning disable SA1312 // Variable names should begin with lower-case letter
+ using CancellationTokenRegistration _ = cts.Token.Register(tcs => ((TaskCompletionSource)tcs!).TrySetResult(true), cancellationTask);
+#pragma warning restore SA1312 // Variable names should begin with lower-case letter
+ await Task.WhenAny(target, cancellationTask.Task).ConfigureAwait(false);
+
+ if (!target.IsCompleted)
+ {
+ if (cancellationToken.IsCancellationRequested)
+ {
+ await Task.FromCanceled(cancellationToken).ConfigureAwait(false);
+ }
+
+ throw new TimeoutException();
+ }
+
+ await target.ConfigureAwait(false);
+ }
+
+ public static Task WaitAsync(
+ this Task target,
+ CancellationToken cancellationToken) =>
+ target.WaitAsync(Timeout.InfiniteTimeSpan, cancellationToken);
+
+ public static Task WaitAsync(
+ this Task target,
+ TimeSpan timeout) =>
+ target.WaitAsync(timeout, default);
+
+ public static async Task WaitAsync(
+ this Task target,
+ TimeSpan timeout,
+ CancellationToken cancellationToken)
+ {
+ await ((Task)target).WaitAsync(timeout, cancellationToken).ConfigureAwait(false);
+#pragma warning disable VSTHRD103 // Call async methods when in an async method
+ return target.Result;
+#pragma warning restore VSTHRD103 // Call async methods when in an async method
+ }
+#endif
+
// We observe by default because usually we're no more interested in the result of the task
public static async Task WithCancellationAsync(this Task task, CancellationToken cancellationToken, bool observeException = true)
{
diff --git a/src/Platform/Microsoft.Testing.Platform/Helpers/TimeSpanParser.cs b/src/Platform/Microsoft.Testing.Platform/Helpers/TimeSpanParser.cs
index 32a4077998..85108aeaf5 100644
--- a/src/Platform/Microsoft.Testing.Platform/Helpers/TimeSpanParser.cs
+++ b/src/Platform/Microsoft.Testing.Platform/Helpers/TimeSpanParser.cs
@@ -51,25 +51,25 @@ public static bool TryParse(string? time, out TimeSpan result)
return true;
}
- if (suffix.StartsWith('s'))
+ if (suffix.StartsWith("s", StringComparison.Ordinal))
{
result = TimeSpan.FromSeconds(number);
return true;
}
- if (suffix.StartsWith('m'))
+ if (suffix.StartsWith("m", StringComparison.Ordinal))
{
result = TimeSpan.FromMinutes(number);
return true;
}
- if (suffix.StartsWith('h'))
+ if (suffix.StartsWith("h", StringComparison.Ordinal))
{
result = TimeSpan.FromHours(number);
return true;
}
- if (suffix.StartsWith('d'))
+ if (suffix.StartsWith("d", StringComparison.Ordinal))
{
result = TimeSpan.FromDays(number);
return true;
diff --git a/src/Platform/Microsoft.Testing.Platform/Hosts/ServerTestHost.cs b/src/Platform/Microsoft.Testing.Platform/Hosts/ServerTestHost.cs
index 1d849b6ad4..fe2a8d5d96 100644
--- a/src/Platform/Microsoft.Testing.Platform/Hosts/ServerTestHost.cs
+++ b/src/Platform/Microsoft.Testing.Platform/Hosts/ServerTestHost.cs
@@ -205,7 +205,9 @@ private async Task HandleMessagesAsync(CancellationToken cancellationToken)
if (!_serverClosingTokenSource.IsCancellationRequested)
{
await _logger.LogDebugAsync("Server requested to shutdown").ConfigureAwait(false);
- await _serverClosingTokenSource.CancelAsync().ConfigureAwait(false);
+#pragma warning disable VSTHRD103 // Call async methods when in an async method
+ _serverClosingTokenSource.Cancel();
+#pragma warning restore VSTHRD103 // Call async methods when in an async method
}
// Signal the exit call
@@ -214,7 +216,9 @@ private async Task HandleMessagesAsync(CancellationToken cancellationToken)
// If there're no in-flight request we can close the server
if (_clientToServerRequests.IsEmpty)
{
- await _stopMessageHandler.CancelAsync().ConfigureAwait(false);
+#pragma warning disable VSTHRD103 // Call async methods when in an async method
+ _stopMessageHandler.Cancel();
+#pragma warning restore VSTHRD103 // Call async methods when in an async method
}
continue;
@@ -711,7 +715,11 @@ await SendMessageAsync(
private sealed class RpcInvocationState : IDisposable
{
+#if NET9_0_OR_GREATER
private readonly Lock _cancellationTokenSourceLock = new();
+#else
+ private readonly object _cancellationTokenSourceLock = new();
+#endif
private readonly CancellationTokenSource _cancellationTokenSource = new();
private volatile bool _isDisposed;
diff --git a/src/Platform/Microsoft.Testing.Platform/IPC/NamedPipeClient.cs b/src/Platform/Microsoft.Testing.Platform/IPC/NamedPipeClient.cs
index a0bf10606d..61f9b2a93f 100644
--- a/src/Platform/Microsoft.Testing.Platform/IPC/NamedPipeClient.cs
+++ b/src/Platform/Microsoft.Testing.Platform/IPC/NamedPipeClient.cs
@@ -39,7 +39,11 @@ public NamedPipeClient(string name)
public NamedPipeClient(string name, IEnvironment environment)
{
- Ensure.NotNull(name);
+ if (name is null)
+ {
+ throw new ArgumentNullException(nameof(name));
+ }
+
_namedPipeClientStream = new(".", name, PipeDirection.InOut, CurrentUserPipeOptions);
PipeName = name;
_environment = environment;
diff --git a/src/Platform/Microsoft.Testing.Platform/IPC/NamedPipeServer.cs b/src/Platform/Microsoft.Testing.Platform/IPC/NamedPipeServer.cs
index 4b7adb31d3..3ce97de543 100644
--- a/src/Platform/Microsoft.Testing.Platform/IPC/NamedPipeServer.cs
+++ b/src/Platform/Microsoft.Testing.Platform/IPC/NamedPipeServer.cs
@@ -69,7 +69,11 @@ public NamedPipeServer(
int maxNumberOfServerInstances,
CancellationToken cancellationToken)
{
- Ensure.NotNull(pipeNameDescription);
+ if (pipeNameDescription is null)
+ {
+ throw new ArgumentNullException(nameof(pipeNameDescription));
+ }
+
_namedPipeServerStream = new((PipeName = pipeNameDescription).Name, PipeDirection.InOut, maxNumberOfServerInstances, PipeTransmissionMode.Byte, AsyncCurrentUserPipeOptions);
_callback = callback;
_environment = environment;
diff --git a/src/Platform/Microsoft.Testing.Platform/Logging/LoggerFactoryExtensions.cs b/src/Platform/Microsoft.Testing.Platform/Logging/LoggerFactoryExtensions.cs
index 316b19a27d..6cd15ff20d 100644
--- a/src/Platform/Microsoft.Testing.Platform/Logging/LoggerFactoryExtensions.cs
+++ b/src/Platform/Microsoft.Testing.Platform/Logging/LoggerFactoryExtensions.cs
@@ -15,8 +15,5 @@ public static class LoggerFactoryExtensions
/// The logger factory.
/// A logger instance.
public static ILogger CreateLogger(this ILoggerFactory factory)
- {
- Ensure.NotNull(factory);
- return new Logger(factory);
- }
+ => new Logger(factory ?? throw new ArgumentNullException(nameof(factory)));
}
diff --git a/src/Platform/Microsoft.Testing.Platform/Logging/LoggerFactoryProxy.cs b/src/Platform/Microsoft.Testing.Platform/Logging/LoggerFactoryProxy.cs
index 2af77c9caf..3cfda76bb6 100644
--- a/src/Platform/Microsoft.Testing.Platform/Logging/LoggerFactoryProxy.cs
+++ b/src/Platform/Microsoft.Testing.Platform/Logging/LoggerFactoryProxy.cs
@@ -12,8 +12,5 @@ public ILogger CreateLogger(string categoryName) => _loggerFactory is null
: _loggerFactory.CreateLogger(categoryName);
public void SetLoggerFactory(ILoggerFactory loggerFactory)
- {
- Ensure.NotNull(loggerFactory);
- _loggerFactory = loggerFactory;
- }
+ => _loggerFactory = loggerFactory ?? throw new ArgumentNullException(nameof(loggerFactory));
}
diff --git a/src/Platform/Microsoft.Testing.Platform/Logging/LoggingManager.cs b/src/Platform/Microsoft.Testing.Platform/Logging/LoggingManager.cs
index 3e04e4e3cb..294ebde2f5 100644
--- a/src/Platform/Microsoft.Testing.Platform/Logging/LoggingManager.cs
+++ b/src/Platform/Microsoft.Testing.Platform/Logging/LoggingManager.cs
@@ -11,10 +11,7 @@ internal sealed class LoggingManager : ILoggingManager
private readonly List> _loggerProviderFullFactories = [];
public void AddProvider(Func loggerProviderFactory)
- {
- Ensure.NotNull(loggerProviderFactory);
- _loggerProviderFullFactories.Add(loggerProviderFactory);
- }
+ => _loggerProviderFullFactories.Add(loggerProviderFactory ?? throw new ArgumentNullException(nameof(loggerProviderFactory)));
internal async Task BuildAsync(IServiceProvider serviceProvider, LogLevel logLevel, IMonitor monitor)
{
diff --git a/src/Platform/Microsoft.Testing.Platform/Messages/AsynchronousMessageBus.cs b/src/Platform/Microsoft.Testing.Platform/Messages/AsynchronousMessageBus.cs
index 601876c206..c6246bffa4 100644
--- a/src/Platform/Microsoft.Testing.Platform/Messages/AsynchronousMessageBus.cs
+++ b/src/Platform/Microsoft.Testing.Platform/Messages/AsynchronousMessageBus.cs
@@ -149,9 +149,9 @@ public override async Task DrainDataAsync()
StringBuilder builder = new();
builder.Append(CultureInfo.InvariantCulture, $"Publisher/Consumer loop detected during the drain after {stopwatch.Elapsed}.\n{builder}");
- foreach ((IAsyncConsumerDataProcessor key, long value) in consumerToDrain)
+ foreach (KeyValuePair kvp in consumerToDrain)
{
- builder.AppendLine(CultureInfo.InvariantCulture, $"Consumer '{key.DataConsumer}' payload received {value}.");
+ builder.AppendLine(CultureInfo.InvariantCulture, $"Consumer '{kvp.Key.DataConsumer}' payload received {kvp.Value}.");
}
throw new InvalidOperationException(builder.ToString());
@@ -163,8 +163,16 @@ public override async Task DrainDataAsync()
{
foreach (IAsyncConsumerDataProcessor asyncMultiProducerMultiConsumerDataProcessor in dataProcessors)
{
+#if NETCOREAPP
consumerToDrain.TryAdd(asyncMultiProducerMultiConsumerDataProcessor, 0);
-
+#else
+#pragma warning disable CA1854 // Prefer the 'IDictionary.TryGetValue(TKey, out TValue)' method
+ if (!consumerToDrain.ContainsKey(asyncMultiProducerMultiConsumerDataProcessor))
+ {
+ consumerToDrain.Add(asyncMultiProducerMultiConsumerDataProcessor, 0);
+ }
+#pragma warning restore CA1854 // Prefer the 'IDictionary.TryGetValue(TKey, out TValue)' method
+#endif
long totalPayloadReceived = await asyncMultiProducerMultiConsumerDataProcessor.DrainDataAsync().ConfigureAwait(false);
if (consumerToDrain[asyncMultiProducerMultiConsumerDataProcessor] != totalPayloadReceived)
{
diff --git a/src/Platform/Microsoft.Testing.Platform/Messages/MessageBusProxy.cs b/src/Platform/Microsoft.Testing.Platform/Messages/MessageBusProxy.cs
index 0ca1b6732b..ff84a5e799 100644
--- a/src/Platform/Microsoft.Testing.Platform/Messages/MessageBusProxy.cs
+++ b/src/Platform/Microsoft.Testing.Platform/Messages/MessageBusProxy.cs
@@ -20,10 +20,7 @@ public override async Task InitAsync()
}
public void SetBuiltMessageBus(BaseMessageBus messageBus)
- {
- Ensure.NotNull(messageBus);
- _messageBus = messageBus;
- }
+ => _messageBus = messageBus ?? throw new ArgumentNullException(nameof(messageBus));
public override async Task PublishAsync(IDataProducer dataProducer, IData data)
{
diff --git a/src/Platform/Microsoft.Testing.Platform/Messages/PropertyBag.Property.cs b/src/Platform/Microsoft.Testing.Platform/Messages/PropertyBag.Property.cs
index 18a0b9f0cc..7a1b23c628 100644
--- a/src/Platform/Microsoft.Testing.Platform/Messages/PropertyBag.Property.cs
+++ b/src/Platform/Microsoft.Testing.Platform/Messages/PropertyBag.Property.cs
@@ -141,10 +141,7 @@ internal sealed class PropertyDebugView
private readonly Property _property;
public PropertyDebugView(Property property)
- {
- Ensure.NotNull(property);
- _property = property;
- }
+ => _property = property ?? throw new ArgumentNullException(nameof(property));
[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
public IProperty[] Items => [.. _property.AsEnumerable()];
diff --git a/src/Platform/Microsoft.Testing.Platform/Messages/PropertyBag.cs b/src/Platform/Microsoft.Testing.Platform/Messages/PropertyBag.cs
index 7a11f8dbbe..63fe5ccee4 100644
--- a/src/Platform/Microsoft.Testing.Platform/Messages/PropertyBag.cs
+++ b/src/Platform/Microsoft.Testing.Platform/Messages/PropertyBag.cs
@@ -35,7 +35,7 @@ public PropertyBag()
/// The collection of properties.
public PropertyBag(params IProperty[] properties)
{
- Ensure.NotNull(properties);
+ _ = properties ?? throw new ArgumentNullException(nameof(properties));
if (properties.Length == 0)
{
@@ -78,7 +78,7 @@ public PropertyBag(params IProperty[] properties)
/// The collection of properties.
public PropertyBag(IEnumerable properties)
{
- Ensure.NotNull(properties);
+ _ = properties ?? throw new ArgumentNullException(nameof(properties));
foreach (IProperty property in properties)
{
@@ -123,7 +123,7 @@ public PropertyBag(IEnumerable properties)
/// The property to add.
public void Add(IProperty property)
{
- Ensure.NotNull(property);
+ _ = property ?? throw new ArgumentNullException(nameof(property));
// Optimized access to the TestNodeStateProperty, it's one of the most used property.
if (property is TestNodeStateProperty testNodeStateProperty)
diff --git a/src/Platform/Microsoft.Testing.Platform/Messages/TestNodeProperties.cs b/src/Platform/Microsoft.Testing.Platform/Messages/TestNodeProperties.cs
index 38120f4144..f245e6ed87 100644
--- a/src/Platform/Microsoft.Testing.Platform/Messages/TestNodeProperties.cs
+++ b/src/Platform/Microsoft.Testing.Platform/Messages/TestNodeProperties.cs
@@ -681,7 +681,16 @@ public override string ToString()
builder.Append($"{nameof(GlobalTiming)} = ");
builder.Append(GlobalTiming);
builder.Append($", {nameof(StepTimings)} = [");
- builder.AppendJoin(", ", StepTimings.Select(x => x.ToString()));
+
+ for (int i = 0; i < StepTimings.Length; i++)
+ {
+ builder.Append(StepTimings[i].ToString());
+ if (i < StepTimings.Length - 1)
+ {
+ builder.Append(", ");
+ }
+ }
+
builder.Append(']');
builder.Append(" }");
return builder.ToString();
@@ -1013,7 +1022,16 @@ public override string ToString()
builder.Append($", {nameof(MethodArity)} = ");
builder.Append(MethodArity);
builder.Append($", {nameof(ParameterTypeFullNames)} = [");
- builder.AppendJoin(", ", ParameterTypeFullNames);
+
+ for (int i = 0; i < ParameterTypeFullNames.Length; i++)
+ {
+ builder.Append(ParameterTypeFullNames[i]);
+ if (i < ParameterTypeFullNames.Length - 1)
+ {
+ builder.Append(", ");
+ }
+ }
+
builder.Append($"], {nameof(ReturnTypeFullName)} = ");
builder.Append(ReturnTypeFullName);
builder.Append(" }");
diff --git a/src/Platform/Microsoft.Testing.Platform/Microsoft.Testing.Platform.csproj b/src/Platform/Microsoft.Testing.Platform/Microsoft.Testing.Platform.csproj
index 0c69386a00..2beb00ee4a 100644
--- a/src/Platform/Microsoft.Testing.Platform/Microsoft.Testing.Platform.csproj
+++ b/src/Platform/Microsoft.Testing.Platform/Microsoft.Testing.Platform.csproj
@@ -1,4 +1,4 @@
-
+
$(SupportedNetFrameworks);netstandard2.0
@@ -83,7 +83,11 @@ This package provides the core platform and the .NET implementation of the proto
-
+
+
+
+
+
diff --git a/src/Platform/Microsoft.Testing.Platform/OutputDevice/OutputDeviceManager.cs b/src/Platform/Microsoft.Testing.Platform/OutputDevice/OutputDeviceManager.cs
index 192b07b483..b487d11f1c 100644
--- a/src/Platform/Microsoft.Testing.Platform/OutputDevice/OutputDeviceManager.cs
+++ b/src/Platform/Microsoft.Testing.Platform/OutputDevice/OutputDeviceManager.cs
@@ -15,10 +15,7 @@ internal sealed class PlatformOutputDeviceManager
private Func? _platformOutputDeviceFactory;
public void SetPlatformOutputDevice(Func platformOutputDeviceFactory)
- {
- Ensure.NotNull(platformOutputDeviceFactory);
- _platformOutputDeviceFactory = platformOutputDeviceFactory;
- }
+ => _platformOutputDeviceFactory = platformOutputDeviceFactory ?? throw new ArgumentNullException(nameof(platformOutputDeviceFactory));
internal async Task BuildAsync(ServiceProvider serviceProvider, bool useServerModeOutputDevice)
{
diff --git a/src/Platform/Microsoft.Testing.Platform/OutputDevice/Terminal/TerminalTestReporter.cs b/src/Platform/Microsoft.Testing.Platform/OutputDevice/Terminal/TerminalTestReporter.cs
index 21e715888d..cf6782a065 100644
--- a/src/Platform/Microsoft.Testing.Platform/OutputDevice/Terminal/TerminalTestReporter.cs
+++ b/src/Platform/Microsoft.Testing.Platform/OutputDevice/Terminal/TerminalTestReporter.cs
@@ -46,7 +46,12 @@ internal event EventHandler OnProgressStopUpdate
private readonly TerminalTestReporterOptions _options;
private readonly TestProgressStateAwareTerminal _terminalWithProgress;
+
+#if NET9_0_OR_GREATER
private readonly Lock _lock = new();
+#else
+ private readonly object _lock = new();
+#endif
private readonly uint? _originalConsoleMode;
diff --git a/src/Platform/Microsoft.Testing.Platform/OutputDevice/Terminal/TestProgressStateAwareTerminal.cs b/src/Platform/Microsoft.Testing.Platform/OutputDevice/Terminal/TestProgressStateAwareTerminal.cs
index 4167806c4c..23a0a6c773 100644
--- a/src/Platform/Microsoft.Testing.Platform/OutputDevice/Terminal/TestProgressStateAwareTerminal.cs
+++ b/src/Platform/Microsoft.Testing.Platform/OutputDevice/Terminal/TestProgressStateAwareTerminal.cs
@@ -17,7 +17,11 @@ internal sealed partial class TestProgressStateAwareTerminal : IDisposable
///
/// Protects access to state shared between the logger callbacks and the rendering thread.
///
+#if NET9_0_OR_GREATER
private readonly Lock _lock = new();
+#else
+ private readonly object _lock = new();
+#endif
private readonly ITerminal _terminal;
private readonly Func _showProgress;
diff --git a/src/Platform/Microsoft.Testing.Platform/OutputDevice/TerminalOutputDevice.cs b/src/Platform/Microsoft.Testing.Platform/OutputDevice/TerminalOutputDevice.cs
index 326b984aef..af33dc591c 100644
--- a/src/Platform/Microsoft.Testing.Platform/OutputDevice/TerminalOutputDevice.cs
+++ b/src/Platform/Microsoft.Testing.Platform/OutputDevice/TerminalOutputDevice.cs
@@ -195,9 +195,10 @@ string s when TerminalTestReporterCommandLineOptionsProvider.ShowOutputNoneArgum
: OutputShowMode.All;
private static string GetShortArchitecture(string runtimeIdentifier)
- => runtimeIdentifier.Contains(Dash)
- ? runtimeIdentifier.Split(Dash, 2)[1]
- : runtimeIdentifier;
+ {
+ int firstIndexOfDash = runtimeIdentifier.IndexOf(Dash);
+ return firstIndexOfDash < 0 ? runtimeIdentifier : runtimeIdentifier.Substring(firstIndexOfDash + 1);
+ }
public Type[] DataTypesConsumed { get; } =
[
diff --git a/src/Platform/Microsoft.Testing.Platform/Requests/TreeNodeFilter/TreeNodeFilter.cs b/src/Platform/Microsoft.Testing.Platform/Requests/TreeNodeFilter/TreeNodeFilter.cs
index 3bc210353c..736ebbbd91 100644
--- a/src/Platform/Microsoft.Testing.Platform/Requests/TreeNodeFilter/TreeNodeFilter.cs
+++ b/src/Platform/Microsoft.Testing.Platform/Requests/TreeNodeFilter/TreeNodeFilter.cs
@@ -24,7 +24,7 @@ public sealed class TreeNodeFilter : ITestExecutionFilter
internal TreeNodeFilter(string filter)
{
- Filter = Ensure.NotNull(filter);
+ Filter = filter ?? throw new ArgumentNullException(nameof(filter));
_filters = ParseFilter(filter);
}
@@ -482,8 +482,8 @@ private static IEnumerable TokenizeFilter(string filter)
/// The URL encoded node properties.
public bool MatchesFilter(string testNodeFullPath, PropertyBag filterableProperties)
{
- Ensure.NotNullOrEmpty(testNodeFullPath);
- ArgumentGuard.Ensure(testNodeFullPath[0] == PathSeparator, nameof(testNodeFullPath),
+ _ = testNodeFullPath ?? throw new ArgumentNullException(nameof(testNodeFullPath));
+ ArgumentGuard.Ensure(testNodeFullPath.Length > 0 && testNodeFullPath[0] == PathSeparator, nameof(testNodeFullPath),
string.Format(CultureInfo.InvariantCulture, PlatformResources.TreeNodeFilterPathShouldStartWithSlashErrorMessage, PathSeparator));
int currentCharIndex = 1;
diff --git a/src/Platform/Microsoft.Testing.Platform/ServerMode/DotnetTest/IPC/Serializers/DiscoveredTestMessagesSerializer.cs b/src/Platform/Microsoft.Testing.Platform/ServerMode/DotnetTest/IPC/Serializers/DiscoveredTestMessagesSerializer.cs
index 6039c0003e..ee7e88314e 100644
--- a/src/Platform/Microsoft.Testing.Platform/ServerMode/DotnetTest/IPC/Serializers/DiscoveredTestMessagesSerializer.cs
+++ b/src/Platform/Microsoft.Testing.Platform/ServerMode/DotnetTest/IPC/Serializers/DiscoveredTestMessagesSerializer.cs
@@ -2,6 +2,7 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using Microsoft.Testing.Platform.Extensions.Messages;
+using Microsoft.Testing.Platform.Helpers;
using Microsoft.Testing.Platform.IPC.Models;
namespace Microsoft.Testing.Platform.IPC.Serializers;
@@ -234,8 +235,8 @@ private static TestMetadataProperty[] ReadTraitsPayload(Stream stream)
}
}
- Ensure.NotNull(key);
- Ensure.NotNull(value);
+ _ = key ?? throw ApplicationStateGuard.Unreachable();
+ _ = value ?? throw ApplicationStateGuard.Unreachable();
traits[i] = new TestMetadataProperty(key, value);
}
diff --git a/src/Platform/Microsoft.Testing.Platform/ServerMode/DotnetTest/IPC/Serializers/HandshakeMessageSerializer.cs b/src/Platform/Microsoft.Testing.Platform/ServerMode/DotnetTest/IPC/Serializers/HandshakeMessageSerializer.cs
index 554ae3b12d..03ef54774e 100644
--- a/src/Platform/Microsoft.Testing.Platform/ServerMode/DotnetTest/IPC/Serializers/HandshakeMessageSerializer.cs
+++ b/src/Platform/Microsoft.Testing.Platform/ServerMode/DotnetTest/IPC/Serializers/HandshakeMessageSerializer.cs
@@ -38,10 +38,10 @@ public void Serialize(object objectToSerialize, Stream stream)
return;
}
- foreach ((byte key, string value) in handshakeMessage.Properties)
+ foreach (KeyValuePair kvp in handshakeMessage.Properties)
{
- WriteField(stream, key);
- WriteField(stream, value);
+ WriteField(stream, kvp.Key);
+ WriteField(stream, kvp.Value);
}
}
}
diff --git a/src/Platform/Microsoft.Testing.Platform/ServerMode/JsonRpc/PerRequestServerDataConsumerService.cs b/src/Platform/Microsoft.Testing.Platform/ServerMode/JsonRpc/PerRequestServerDataConsumerService.cs
index cce977c3b0..dd6a5ed4a2 100644
--- a/src/Platform/Microsoft.Testing.Platform/ServerMode/JsonRpc/PerRequestServerDataConsumerService.cs
+++ b/src/Platform/Microsoft.Testing.Platform/ServerMode/JsonRpc/PerRequestServerDataConsumerService.cs
@@ -131,7 +131,6 @@ private async Task SendTestNodeUpdatesOnIdleAsync(Guid runId)
using CancellationTokenRegistration registration = cancellationToken.Register(_testSessionEnd.SetCanceled);
// When batch timer expire or we're at the end of the session we can unblock the message drain
- Ensure.NotNull(_task);
await Task.WhenAny(_task.Delay(TimeSpan.FromMilliseconds(TestNodeUpdateDelayInMs), cancellationToken), _testSessionEnd.Task).ConfigureAwait(false);
cancellationToken.ThrowIfCancellationRequested();
diff --git a/src/Platform/Microsoft.Testing.Platform/ServerMode/JsonRpc/SerializerUtilities.cs b/src/Platform/Microsoft.Testing.Platform/ServerMode/JsonRpc/SerializerUtilities.cs
index 7c16ce0d93..0d1a572f86 100644
--- a/src/Platform/Microsoft.Testing.Platform/ServerMode/JsonRpc/SerializerUtilities.cs
+++ b/src/Platform/Microsoft.Testing.Platform/ServerMode/JsonRpc/SerializerUtilities.cs
@@ -224,7 +224,7 @@ static SerializerUtilities()
: $"{testMethodIdentifierProperty.Namespace}.{testMethodIdentifierProperty.TypeName}";
properties["location.method"] = testMethodIdentifierProperty.ParameterTypeFullNames.Length > 0
- ? $"{testMethodIdentifierProperty.MethodName}({string.Join(',', testMethodIdentifierProperty.ParameterTypeFullNames)})"
+ ? $"{testMethodIdentifierProperty.MethodName}({string.Join(",", testMethodIdentifierProperty.ParameterTypeFullNames)})"
: testMethodIdentifierProperty.MethodName;
properties["location.method-arity"] = testMethodIdentifierProperty.MethodArity;
@@ -354,7 +354,14 @@ static SerializerUtilities()
}
}
- properties.TryAdd("node-type", "group");
+#if NETCOREAPP
+ properties.Add("node-type", "group");
+#else
+ if (!properties.ContainsKey("node-type"))
+ {
+ properties.Add("node-type", "group");
+ }
+#endif
return properties;
});
@@ -406,11 +413,11 @@ static SerializerUtilities()
values[JsonRpcStrings.EnvironmentVariables] = ev.EnvironmentVariables;
#else
JsonArray collection = [];
- foreach ((string? key, string? value) in ev.EnvironmentVariables)
+ foreach (KeyValuePair kvp in ev.EnvironmentVariables)
{
JsonObject o = new()
{
- { key, value },
+ { kvp.Key, kvp.Value },
};
collection.Add(o);
}
@@ -610,17 +617,17 @@ static SerializerUtilities()
string displayName = string.Empty;
PropertyBag propertyBag = new();
- foreach ((string? key, object? value) in properties)
+ foreach (KeyValuePair kvp in properties)
{
- if (key == JsonRpcStrings.Uid)
+ if (kvp.Key == JsonRpcStrings.Uid)
{
- uid = value as string ?? string.Empty;
+ uid = kvp.Value as string ?? string.Empty;
continue;
}
- if (key == JsonRpcStrings.DisplayName)
+ if (kvp.Key == JsonRpcStrings.DisplayName)
{
- displayName = value as string ?? string.Empty;
+ displayName = kvp.Value as string ?? string.Empty;
continue;
}
}
diff --git a/src/Platform/Microsoft.Testing.Platform/ServerMode/JsonRpc/ServerModePerCallOutputDevice.cs b/src/Platform/Microsoft.Testing.Platform/ServerMode/JsonRpc/ServerModePerCallOutputDevice.cs
index a2783246a4..5be8024158 100644
--- a/src/Platform/Microsoft.Testing.Platform/ServerMode/JsonRpc/ServerModePerCallOutputDevice.cs
+++ b/src/Platform/Microsoft.Testing.Platform/ServerMode/JsonRpc/ServerModePerCallOutputDevice.cs
@@ -39,12 +39,10 @@ internal async Task InitializeAsync(ServerTestHost serverTestHost)
// messages to Test Explorer as well.
_serverTestHost = serverTestHost;
- foreach (ServerLogMessage message in _messages)
+ while (_messages.TryTake(out ServerLogMessage? message))
{
await LogAsync(message, serverTestHost.ServiceProvider.GetTestApplicationCancellationTokenSource().CancellationToken).ConfigureAwait(false);
}
-
- _messages.Clear();
}
public string Uid => nameof(ServerModePerCallOutputDevice);
diff --git a/src/Platform/Microsoft.Testing.Platform/ServerMode/JsonRpc/TcpMessageHandler.cs b/src/Platform/Microsoft.Testing.Platform/ServerMode/JsonRpc/TcpMessageHandler.cs
index 6267a624ab..542dcd4245 100644
--- a/src/Platform/Microsoft.Testing.Platform/ServerMode/JsonRpc/TcpMessageHandler.cs
+++ b/src/Platform/Microsoft.Testing.Platform/ServerMode/JsonRpc/TcpMessageHandler.cs
@@ -124,7 +124,11 @@ public async Task WriteRequestAsync(RpcMessage message, CancellationToken cancel
await _writer.WriteLineAsync("Content-Type: application/testingplatform").ConfigureAwait(false);
await _writer.WriteLineAsync().ConfigureAwait(false);
await _writer.WriteAsync(messageStr).ConfigureAwait(false);
+#if NETCOREAPP
await _writer.FlushAsync(cancellationToken).ConfigureAwait(false);
+#else
+ await _writer.FlushAsync().ConfigureAwait(false);
+#endif
}
public void Dispose()
diff --git a/src/Platform/Microsoft.Testing.Platform/Services/ExecutableInfo.cs b/src/Platform/Microsoft.Testing.Platform/Services/ExecutableInfo.cs
index 17b6023e2b..80b35d1441 100644
--- a/src/Platform/Microsoft.Testing.Platform/Services/ExecutableInfo.cs
+++ b/src/Platform/Microsoft.Testing.Platform/Services/ExecutableInfo.cs
@@ -12,5 +12,5 @@ internal sealed class ExecutableInfo(string filePath, IEnumerable argume
public string Workspace { get; } = workspace;
public override string ToString()
- => $"Process: {FilePath}, Arguments: {string.Join(' ', Arguments)}, Workspace: {Workspace}";
+ => $"Process: {FilePath}, Arguments: {string.Join(" ", Arguments)}, Workspace: {Workspace}";
}
diff --git a/src/Platform/Microsoft.Testing.Platform/Services/ServiceProviderExtensions.cs b/src/Platform/Microsoft.Testing.Platform/Services/ServiceProviderExtensions.cs
index 0b44510b11..6bea6de92d 100644
--- a/src/Platform/Microsoft.Testing.Platform/Services/ServiceProviderExtensions.cs
+++ b/src/Platform/Microsoft.Testing.Platform/Services/ServiceProviderExtensions.cs
@@ -32,7 +32,7 @@ public static class ServiceProviderExtensions
public static TService GetRequiredService(this IServiceProvider provider)
where TService : notnull
{
- Ensure.NotNull(provider);
+ _ = provider ?? throw new ArgumentNullException(nameof(provider));
object? service = provider.GetService(typeof(TService));
ApplicationStateGuard.Ensure(service is not null, string.Format(CultureInfo.InvariantCulture, PlatformResources.ServiceProviderCannotFindServiceErrorMessage, typeof(TService)));
@@ -50,7 +50,7 @@ public static TService GetRequiredService(this IServiceProvider provid
public static TService? GetService(this IServiceProvider provider)
where TService : class
{
- Ensure.NotNull(provider);
+ _ = provider ?? throw new ArgumentNullException(nameof(provider));
return provider.GetService(typeof(TService)) as TService;
}
@@ -108,7 +108,7 @@ public static IClientInfo GetClientInfo(this IServiceProvider serviceProvider)
internal static TService GetRequiredServiceInternal(this IServiceProvider provider)
where TService : notnull
{
- Ensure.NotNull(provider);
+ _ = provider ?? throw new ArgumentNullException(nameof(provider));
object? service = ((ServiceProvider)provider).GetServiceInternal(typeof(TService));
ApplicationStateGuard.Ensure(service is not null, string.Format(CultureInfo.InvariantCulture, PlatformResources.ServiceProviderCannotFindServiceErrorMessage, typeof(TService)));
@@ -119,7 +119,7 @@ internal static TService GetRequiredServiceInternal(this IServiceProvi
internal static TService? GetServiceInternal(this IServiceProvider provider)
where TService : class
{
- Ensure.NotNull(provider);
+ _ = provider ?? throw new ArgumentNullException(nameof(provider));
return ((ServiceProvider)provider).GetServiceInternal(typeof(TService)) as TService;
}
@@ -127,7 +127,7 @@ internal static TService GetRequiredServiceInternal(this IServiceProvi
internal static IEnumerable GetServicesInternal(this IServiceProvider provider)
where TService : notnull
{
- Ensure.NotNull(provider);
+ _ = provider ?? throw new ArgumentNullException(nameof(provider));
return ((ServiceProvider)provider).GetServicesInternal(typeof(TService)).Cast();
}
diff --git a/src/Platform/Microsoft.Testing.Platform/Telemetry/TelemetryManager.cs b/src/Platform/Microsoft.Testing.Platform/Telemetry/TelemetryManager.cs
index 5f688ea895..4b415a3eb3 100644
--- a/src/Platform/Microsoft.Testing.Platform/Telemetry/TelemetryManager.cs
+++ b/src/Platform/Microsoft.Testing.Platform/Telemetry/TelemetryManager.cs
@@ -26,16 +26,10 @@ internal sealed class TelemetryManager : ITelemetryManager, IOutputDeviceDataPro
public string Description => string.Empty;
public void AddTelemetryCollectorProvider(Func telemetryFactory)
- {
- Ensure.NotNull(telemetryFactory);
- _telemetryFactory = telemetryFactory;
- }
+ => _telemetryFactory = telemetryFactory ?? throw new ArgumentNullException(nameof(telemetryFactory));
public void AddOpenTelemetryProvider(Func openTelemetryProviderFactory)
- {
- Ensure.NotNull(openTelemetryProviderFactory);
- _openTelemetryProviderFactory = openTelemetryProviderFactory;
- }
+ => _openTelemetryProviderFactory = openTelemetryProviderFactory ?? throw new ArgumentNullException(nameof(openTelemetryProviderFactory));
public IOpenTelemetryProvider? BuildOTelProvider(ServiceProvider serviceProvider)
=> _openTelemetryProviderFactory is null
diff --git a/src/Platform/Microsoft.Testing.Platform/TestHost/TestHostManager.cs b/src/Platform/Microsoft.Testing.Platform/TestHost/TestHostManager.cs
index 2c640d3258..e54c1c5f26 100644
--- a/src/Platform/Microsoft.Testing.Platform/TestHost/TestHostManager.cs
+++ b/src/Platform/Microsoft.Testing.Platform/TestHost/TestHostManager.cs
@@ -30,13 +30,12 @@ internal sealed class TestHostManager : ITestHostManager
public void AddTestFrameworkInvoker(Func testFrameworkInvokerFactory)
{
- Ensure.NotNull(testFrameworkInvokerFactory);
if (_testFrameworkInvokerFactory is not null)
{
throw new InvalidOperationException(PlatformResources.TestAdapterInvokerFactoryAlreadySetErrorMessage);
}
- _testFrameworkInvokerFactory = testFrameworkInvokerFactory;
+ _testFrameworkInvokerFactory = testFrameworkInvokerFactory ?? throw new ArgumentNullException(nameof(testFrameworkInvokerFactory));
}
internal async Task> TryBuildTestAdapterInvokerAsync(ServiceProvider serviceProvider)
@@ -61,13 +60,12 @@ internal async Task> TryBuildTestAdapterInvo
public void AddTestExecutionFilterFactory(Func testExecutionFilterFactory)
{
- Ensure.NotNull(testExecutionFilterFactory);
if (_testExecutionFilterFactory is not null)
{
throw new InvalidOperationException(PlatformResources.TEstExecutionFilterFactoryFactoryAlreadySetErrorMessage);
}
- _testExecutionFilterFactory = testExecutionFilterFactory;
+ _testExecutionFilterFactory = testExecutionFilterFactory ?? throw new ArgumentNullException(nameof(testExecutionFilterFactory));
}
internal async Task> TryBuildTestExecutionFilterFactoryAsync(ServiceProvider serviceProvider)
@@ -91,10 +89,7 @@ internal async Task> TryBuildTestExecu
}
public void AddTestHostApplicationLifetime(Func testHostApplicationLifetime)
- {
- Ensure.NotNull(testHostApplicationLifetime);
- _testApplicationLifecycleCallbacksFactories.Add(testHostApplicationLifetime);
- }
+ => _testApplicationLifecycleCallbacksFactories.Add(testHostApplicationLifetime ?? throw new ArgumentNullException(nameof(testHostApplicationLifetime)));
internal async Task BuildTestApplicationLifecycleCallbackAsync(ServiceProvider serviceProvider)
{
@@ -121,16 +116,14 @@ internal async Task BuildTestApplicationLifecycl
public void AddDataConsumer(Func dataConsumerFactory)
{
- Ensure.NotNull(dataConsumerFactory);
- _dataConsumerFactories.Add(dataConsumerFactory);
+ _dataConsumerFactories.Add(dataConsumerFactory ?? throw new ArgumentNullException(nameof(dataConsumerFactory)));
_factoryOrdering.Add(dataConsumerFactory);
}
public void AddDataConsumer(CompositeExtensionFactory compositeServiceFactory)
where T : class, IDataConsumer
{
- Ensure.NotNull(compositeServiceFactory);
- if (_dataConsumersCompositeServiceFactories.Contains(compositeServiceFactory))
+ if (_dataConsumersCompositeServiceFactories.Contains(compositeServiceFactory ?? throw new ArgumentNullException(nameof(compositeServiceFactory))))
{
throw new ArgumentException(PlatformResources.CompositeServiceFactoryInstanceAlreadyRegistered);
}
@@ -218,16 +211,14 @@ public void AddTestSessionLifetimeHandle(CompositeExtensionFactory composi
public void AddTestSessionLifetimeHandler(Func testSessionLifetimeHandleFactory)
{
- Ensure.NotNull(testSessionLifetimeHandleFactory);
- _testSessionLifetimeHandlerFactories.Add(testSessionLifetimeHandleFactory);
+ _testSessionLifetimeHandlerFactories.Add(testSessionLifetimeHandleFactory ?? throw new ArgumentNullException(nameof(testSessionLifetimeHandleFactory)));
_factoryOrdering.Add(testSessionLifetimeHandleFactory);
}
public void AddTestSessionLifetimeHandler(CompositeExtensionFactory compositeServiceFactory)
where T : class, ITestSessionLifetimeHandler
{
- Ensure.NotNull(compositeServiceFactory);
- if (_testSessionLifetimeHandlerCompositeFactories.Contains(compositeServiceFactory))
+ if (_testSessionLifetimeHandlerCompositeFactories.Contains(compositeServiceFactory ?? throw new ArgumentNullException(nameof(compositeServiceFactory))))
{
throw new ArgumentException(PlatformResources.CompositeServiceFactoryInstanceAlreadyRegistered);
}
diff --git a/src/Platform/Microsoft.Testing.Platform/TestHostControllers/TestHostControllersManager.cs b/src/Platform/Microsoft.Testing.Platform/TestHostControllers/TestHostControllersManager.cs
index 7684c596b9..acaa00bfce 100644
--- a/src/Platform/Microsoft.Testing.Platform/TestHostControllers/TestHostControllersManager.cs
+++ b/src/Platform/Microsoft.Testing.Platform/TestHostControllers/TestHostControllersManager.cs
@@ -30,7 +30,7 @@ public void AddEnvironmentVariableProvider(Func(CompositeExtensionFactory compo
throw new PlatformNotSupportedException(PlatformResources.TestHostControllerProcessRestartNotSupportedOnWebAssembly);
}
- Ensure.NotNull(compositeServiceFactory);
+ _ = compositeServiceFactory ?? throw new ArgumentNullException(nameof(compositeServiceFactory));
if (_environmentVariableProviderCompositeFactories.Contains(compositeServiceFactory))
{
throw new ArgumentException(PlatformResources.CompositeServiceFactoryInstanceAlreadyRegistered);
@@ -62,7 +62,7 @@ public void AddProcessLifetimeHandler(Func(CompositeExtensionFactory compositeS
throw new PlatformNotSupportedException(PlatformResources.TestHostControllerProcessRestartNotSupportedOnWebAssembly);
}
- Ensure.NotNull(compositeServiceFactory);
+ _ = compositeServiceFactory ?? throw new ArgumentNullException(nameof(compositeServiceFactory));
if (_lifetimeHandlerCompositeFactories.Contains(compositeServiceFactory))
{
throw new ArgumentException(PlatformResources.CompositeServiceFactoryInstanceAlreadyRegistered);
@@ -95,7 +95,7 @@ public void AddDataConsumer(CompositeExtensionFactory compositeServiceFact
throw new PlatformNotSupportedException(PlatformResources.TestHostControllerProcessRestartNotSupportedOnWebAssembly);
}
- Ensure.NotNull(compositeServiceFactory);
+ _ = compositeServiceFactory ?? throw new ArgumentNullException(nameof(compositeServiceFactory));
if (_dataConsumersCompositeServiceFactories.Contains(compositeServiceFactory))
{
throw new ArgumentException(PlatformResources.CompositeServiceFactoryInstanceAlreadyRegistered);
diff --git a/src/Platform/Microsoft.Testing.Platform/TestHostOrchestrator/TestHostOrchestratorManager.cs b/src/Platform/Microsoft.Testing.Platform/TestHostOrchestrator/TestHostOrchestratorManager.cs
index e76b966f2e..5c8832e445 100644
--- a/src/Platform/Microsoft.Testing.Platform/TestHostOrchestrator/TestHostOrchestratorManager.cs
+++ b/src/Platform/Microsoft.Testing.Platform/TestHostOrchestrator/TestHostOrchestratorManager.cs
@@ -15,14 +15,14 @@ internal class TestHostOrchestratorManager : ITestHostOrchestratorManager, Exten
public void AddTestHostOrchestrator(Func factory)
{
- Ensure.NotNull(factory);
+ _ = factory ?? throw new ArgumentNullException(nameof(factory));
_factories ??= [];
_factories.Add(factory);
}
void Extensions.TestHostOrchestrator.ITestHostOrchestratorManager.AddTestHostOrchestrator(Func factory)
{
- Ensure.NotNull(factory);
+ _ = factory ?? throw new ArgumentNullException(nameof(factory));
_factories ??= [];
_factories.Add(sp => factory(sp));
}
@@ -60,7 +60,7 @@ internal async Task BuildAsync(ServiceProvide
public void AddTestHostOrchestratorApplicationLifetime(Func testHostOrchestratorApplicationLifetimeFactory)
{
- Ensure.NotNull(testHostOrchestratorApplicationLifetimeFactory);
+ _ = testHostOrchestratorApplicationLifetimeFactory ?? throw new ArgumentNullException(nameof(testHostOrchestratorApplicationLifetimeFactory));
_testHostOrchestratorApplicationLifetimeFactories.Add(testHostOrchestratorApplicationLifetimeFactory);
}
diff --git a/src/Platform/Microsoft.Testing.Platform/Tools/ToolsManager.cs b/src/Platform/Microsoft.Testing.Platform/Tools/ToolsManager.cs
index 86b782afe8..843989fff9 100644
--- a/src/Platform/Microsoft.Testing.Platform/Tools/ToolsManager.cs
+++ b/src/Platform/Microsoft.Testing.Platform/Tools/ToolsManager.cs
@@ -10,10 +10,7 @@ internal sealed class ToolsManager : IToolsManager
private readonly List> _toolsFactories = [];
public void AddTool(Func toolFactory)
- {
- Ensure.NotNull(toolFactory);
- _toolsFactories.Add(toolFactory);
- }
+ => _toolsFactories.Add(toolFactory ?? throw new ArgumentNullException(nameof(toolFactory)));
internal async Task> BuildAsync(IServiceProvider serviceProvider)
{
diff --git a/src/Polyfills/CallerArgumentExpressionAttribute.cs b/src/Polyfills/CallerArgumentExpressionAttribute.cs
new file mode 100644
index 0000000000..6b15f3a39a
--- /dev/null
+++ b/src/Polyfills/CallerArgumentExpressionAttribute.cs
@@ -0,0 +1,35 @@
+//
+
+#pragma warning disable
+
+#if !NETCOREAPP
+
+using Microsoft.CodeAnalysis;
+
+namespace System.Runtime.CompilerServices;
+
+///
+/// Indicates that a parameter captures the expression passed for another parameter as a string.
+///
+[ExcludeFromCodeCoverage]
+[DebuggerNonUserCode]
+[AttributeUsage(AttributeTargets.Parameter)]
+[Embedded]
+internal sealed class CallerArgumentExpressionAttribute :
+ Attribute
+{
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public CallerArgumentExpressionAttribute(string parameterName) =>
+ ParameterName = parameterName;
+
+ ///
+ /// Gets the name of the parameter whose expression should be captured as a string.
+ ///
+ public string ParameterName { get; }
+}
+
+#else
+[assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Runtime.CompilerServices.CallerArgumentExpressionAttribute))]
+#endif
diff --git a/src/Polyfills/CompilerFeatureRequiredAttribute.cs b/src/Polyfills/CompilerFeatureRequiredAttribute.cs
new file mode 100644
index 0000000000..d3ecae7cee
--- /dev/null
+++ b/src/Polyfills/CompilerFeatureRequiredAttribute.cs
@@ -0,0 +1,50 @@
+//
+
+#pragma warning disable
+
+#if !NETCOREAPP
+
+using Microsoft.CodeAnalysis;
+
+namespace System.Runtime.CompilerServices;
+
+
+///
+/// Indicates that compiler support for a particular feature is required for the location where this attribute is applied.
+///
+[ExcludeFromCodeCoverage]
+[DebuggerNonUserCode]
+[AttributeUsage(AttributeTargets.All, AllowMultiple = true, Inherited = false)]
+[Embedded]
+internal sealed class CompilerFeatureRequiredAttribute : Attribute
+{
+ ///
+ /// Initialize a new instance of
+ ///
+ public CompilerFeatureRequiredAttribute(string featureName) =>
+ FeatureName = featureName;
+
+ ///
+ /// The name of the compiler feature.
+ ///
+ public string FeatureName { get; }
+
+ ///
+ /// If true, the compiler can choose to allow access to the location where this attribute is applied if it does not understand .
+ ///
+ public bool IsOptional { get; init; }
+
+ ///
+ /// The used for the ref structs C# feature.
+ ///
+ public const string RefStructs = nameof(RefStructs);
+
+ ///
+ /// The used for the required members C# feature.
+ ///
+ public const string RequiredMembers = nameof(RequiredMembers);
+}
+
+#else
+[assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute))]
+#endif
diff --git a/src/Polyfills/CompilerLoweringPreserveAttribute.cs b/src/Polyfills/CompilerLoweringPreserveAttribute.cs
new file mode 100644
index 0000000000..1386db411c
--- /dev/null
+++ b/src/Polyfills/CompilerLoweringPreserveAttribute.cs
@@ -0,0 +1,13 @@
+//
+
+#if !NET10_0_OR_GREATER
+using Microsoft.CodeAnalysis;
+
+namespace System.Runtime.CompilerServices;
+
+[AttributeUsage(AttributeTargets.Class, Inherited = false)]
+[Embedded]
+internal sealed class CompilerLoweringPreserveAttribute : Attribute;
+#else
+[assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Runtime.CompilerServices.CompilerLoweringPreserveAttribute))]
+#endif
diff --git a/src/Polyfills/DynamicallyAccessedMemberTypes.cs b/src/Polyfills/DynamicallyAccessedMemberTypes.cs
new file mode 100644
index 0000000000..fc4c6002ad
--- /dev/null
+++ b/src/Polyfills/DynamicallyAccessedMemberTypes.cs
@@ -0,0 +1,175 @@
+//
+
+#pragma warning disable
+
+#if !NETCOREAPP
+using System.ComponentModel;
+
+using Microsoft.CodeAnalysis;
+
+namespace System.Diagnostics.CodeAnalysis;
+
+///
+/// Specifies the types of members that are dynamically accessed.
+///
+/// This enumeration has a attribute that allows a
+/// bitwise combination of its member values.
+///
+[Flags]
+[Embedded]
+internal enum DynamicallyAccessedMemberTypes
+{
+ ///
+ /// Specifies no members.
+ ///
+ None = 0,
+
+ ///
+ /// Specifies the default, parameterless public constructor.
+ ///
+ PublicParameterlessConstructor = 0x0001,
+
+ ///
+ /// Specifies all public constructors.
+ ///
+ PublicConstructors = 0x0002 | PublicParameterlessConstructor,
+
+ ///
+ /// Specifies all non-public constructors.
+ ///
+ NonPublicConstructors = 0x0004,
+
+ ///
+ /// Specifies all public methods.
+ ///
+ PublicMethods = 0x0008,
+
+ ///
+ /// Specifies all non-public methods.
+ ///
+ NonPublicMethods = 0x0010,
+
+ ///
+ /// Specifies all public fields.
+ ///
+ PublicFields = 0x0020,
+
+ ///
+ /// Specifies all non-public fields.
+ ///
+ NonPublicFields = 0x0040,
+
+ ///
+ /// Specifies all public nested types.
+ ///
+ PublicNestedTypes = 0x0080,
+
+ ///
+ /// Specifies all non-public nested types.
+ ///
+ NonPublicNestedTypes = 0x0100,
+
+ ///
+ /// Specifies all public properties.
+ ///
+ PublicProperties = 0x0200,
+
+ ///
+ /// Specifies all non-public properties.
+ ///
+ NonPublicProperties = 0x0400,
+
+ ///
+ /// Specifies all public events.
+ ///
+ PublicEvents = 0x0800,
+
+ ///
+ /// Specifies all non-public events.
+ ///
+ NonPublicEvents = 0x1000,
+
+ ///
+ /// Specifies all interfaces implemented by the type.
+ ///
+ Interfaces = 0x2000,
+
+ ///
+ /// Specifies all non-public constructors, including those inherited from base classes.
+ ///
+ NonPublicConstructorsWithInherited = NonPublicConstructors | 0x4000,
+
+ ///
+ /// Specifies all non-public methods, including those inherited from base classes.
+ ///
+ NonPublicMethodsWithInherited = NonPublicMethods | 0x8000,
+
+ ///
+ /// Specifies all non-public fields, including those inherited from base classes.
+ ///
+ NonPublicFieldsWithInherited = NonPublicFields | 0x10000,
+
+ ///
+ /// Specifies all non-public nested types, including those inherited from base classes.
+ ///
+ NonPublicNestedTypesWithInherited = NonPublicNestedTypes | 0x20000,
+
+ ///
+ /// Specifies all non-public properties, including those inherited from base classes.
+ ///
+ NonPublicPropertiesWithInherited = NonPublicProperties | 0x40000,
+
+ ///
+ /// Specifies all non-public events, including those inherited from base classes.
+ ///
+ NonPublicEventsWithInherited = NonPublicEvents | 0x80000,
+
+ ///
+ /// Specifies all public constructors, including those inherited from base classes.
+ ///
+ PublicConstructorsWithInherited = PublicConstructors | 0x100000,
+
+ ///
+ /// Specifies all public nested types, including those inherited from base classes.
+ ///
+ PublicNestedTypesWithInherited = PublicNestedTypes | 0x200000,
+
+ ///
+ /// Specifies all constructors, including those inherited from base classes.
+ ///
+ AllConstructors = PublicConstructorsWithInherited | NonPublicConstructorsWithInherited,
+
+ ///
+ /// Specifies all methods, including those inherited from base classes.
+ ///
+ AllMethods = PublicMethods | NonPublicMethodsWithInherited,
+
+ ///
+ /// Specifies all fields, including those inherited from base classes.
+ ///
+ AllFields = PublicFields | NonPublicFieldsWithInherited,
+
+ ///
+ /// Specifies all nested types, including those inherited from base classes.
+ ///
+ AllNestedTypes = PublicNestedTypesWithInherited | NonPublicNestedTypesWithInherited,
+
+ ///
+ /// Specifies all properties, including those inherited from base classes.
+ ///
+ AllProperties = PublicProperties | NonPublicPropertiesWithInherited,
+
+ ///
+ /// Specifies all events, including those inherited from base classes.
+ ///
+ AllEvents = PublicEvents | NonPublicEventsWithInherited,
+
+ ///
+ /// Specifies all members.
+ ///
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ All = ~None
+}
+#else
+[assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes))]
+#endif
diff --git a/src/Polyfills/DynamicallyAccessedMembersAttribute.cs b/src/Polyfills/DynamicallyAccessedMembersAttribute.cs
new file mode 100644
index 0000000000..fa05a7dacf
--- /dev/null
+++ b/src/Polyfills/DynamicallyAccessedMembersAttribute.cs
@@ -0,0 +1,62 @@
+//
+
+#pragma warning disable
+
+#if !NETCOREAPP
+
+using System.Runtime.CompilerServices;
+
+using Microsoft.CodeAnalysis;
+
+namespace System.Diagnostics.CodeAnalysis;
+
+///
+/// Indicates that certain members on a specified are accessed dynamically,
+/// for example through .
+///
+///
+/// This allows tools to understand which members are being accessed during the execution
+/// of a program.
+///
+/// This attribute is valid on members whose type is or .
+///
+/// When this attribute is applied to a location of type , the assumption is
+/// that the string represents a fully qualified type name.
+///
+/// When this attribute is applied to a class, interface, or struct, the members specified
+/// can be accessed dynamically on instances returned from calling
+/// on instances of that class, interface, or struct.
+///
+/// If the attribute is applied to a method it's treated as a special case and it implies
+/// the attribute should be applied to the "this" parameter of the method. As such the attribute
+/// should only be used on instance methods of types assignable to System.Type (or string, but no methods
+/// will use it there).
+///
+[CompilerLoweringPreserve]
+[AttributeUsage(
+ AttributeTargets.Field | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter |
+ AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.Method |
+ AttributeTargets.Class | AttributeTargets.Interface | AttributeTargets.Struct,
+ Inherited = false)]
+[Embedded]
+internal sealed class DynamicallyAccessedMembersAttribute : Attribute
+{
+ ///
+ /// Initializes a new instance of the class
+ /// with the specified member types.
+ ///
+ /// The types of members dynamically accessed.
+ public DynamicallyAccessedMembersAttribute(DynamicallyAccessedMemberTypes memberTypes)
+ {
+ MemberTypes = memberTypes;
+ }
+
+ ///
+ /// Gets the which specifies the type
+ /// of members dynamically accessed.
+ ///
+ public DynamicallyAccessedMemberTypes MemberTypes { get; }
+}
+#else
+[assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute))]
+#endif
diff --git a/src/Polyfills/EmbeddedAttribute.cs b/src/Polyfills/EmbeddedAttribute.cs
new file mode 100644
index 0000000000..87e20d8d22
--- /dev/null
+++ b/src/Polyfills/EmbeddedAttribute.cs
@@ -0,0 +1,7 @@
+//
+
+using System;
+
+namespace Microsoft.CodeAnalysis;
+
+internal sealed partial class EmbeddedAttribute : Attribute;
diff --git a/src/Polyfills/Ensure.cs b/src/Polyfills/Ensure.cs
new file mode 100644
index 0000000000..36ec6711ef
--- /dev/null
+++ b/src/Polyfills/Ensure.cs
@@ -0,0 +1,63 @@
+//
+
+#pragma warning disable
+
+using Microsoft.CodeAnalysis;
+
+namespace Polyfills;
+
+[Embedded]
+internal static class Ensure
+{
+ public static void NotEmpty(IEnumerable value, [CallerArgumentExpression(nameof(value))] string name = "")
+ {
+ const string ArgumentCannotBeEmptyMsg = "Argument cannot be empty.";
+
+ if (value is null)
+ {
+ return;
+ }
+ else if (value is ICollection { Count: 0 })
+ {
+ throw new ArgumentException(ArgumentCannotBeEmptyMsg, name);
+ }
+ else if (value is ICollection { Count: 0 })
+ {
+ throw new ArgumentException(ArgumentCannotBeEmptyMsg, name);
+ }
+ else if (value is IReadOnlyCollection { Count: 0 })
+ {
+ throw new ArgumentException(ArgumentCannotBeEmptyMsg, name);
+ }
+ else if (value is T[] { Length: 0 })
+ {
+ throw new ArgumentException(ArgumentCannotBeEmptyMsg, name);
+ }
+ else if (!value.Any())
+ {
+ throw new ArgumentException(ArgumentCannotBeEmptyMsg, name);
+ }
+ }
+
+ public static string NotNullOrWhiteSpace([NotNull] string value, [CallerArgumentExpression(nameof(value))] string name = "")
+ {
+ if (value is null)
+ {
+ throw new ArgumentNullException(name);
+ }
+ else if (string.IsNullOrWhiteSpace(value))
+ {
+ throw new ArgumentException("Argument cannot be whitespace.", name);
+ }
+
+ return value;
+ }
+
+ public static void NotEmpty(string value, [CallerArgumentExpression(nameof(value))] string name = "")
+ {
+ if (value?.Length == 0)
+ {
+ throw new ArgumentException("Argument cannot be empty.", name);
+ }
+ }
+}
diff --git a/src/Polyfills/ExperimentalAttribute.cs b/src/Polyfills/ExperimentalAttribute.cs
new file mode 100644
index 0000000000..b1215e3e14
--- /dev/null
+++ b/src/Polyfills/ExperimentalAttribute.cs
@@ -0,0 +1,55 @@
+//
+
+#pragma warning disable
+
+#if !NETCOREAPP
+
+using Microsoft.CodeAnalysis;
+
+namespace System.Diagnostics.CodeAnalysis;
+
+///
+/// Indicates that a parameter captures the expression passed for another parameter as a string.
+///
+///
+/// Indicates that an API is experimental and it may change in the future.
+///
+[AttributeUsage(AttributeTargets.Assembly |
+ AttributeTargets.Module |
+ AttributeTargets.Class |
+ AttributeTargets.Struct |
+ AttributeTargets.Enum |
+ AttributeTargets.Constructor |
+ AttributeTargets.Method |
+ AttributeTargets.Property |
+ AttributeTargets.Field |
+ AttributeTargets.Event |
+ AttributeTargets.Interface |
+ AttributeTargets.Delegate, Inherited = false)]
+[ExcludeFromCodeCoverage]
+[DebuggerNonUserCode]
+[Embedded]
+internal sealed class ExperimentalAttribute : Attribute
+{
+ ///
+ /// Initializes a new instance of the class, specifying the ID that the compiler will use
+ /// when reporting a use of the API the attribute applies to.
+ ///
+ public ExperimentalAttribute(string diagnosticId) =>
+ DiagnosticId = diagnosticId;
+
+ ///
+ /// Gets the ID that the compiler will use when reporting a use of the API the attribute applies to.
+ ///
+ public string DiagnosticId { get; }
+
+ ///
+ /// Gets or sets the URL for corresponding documentation.
+ /// The API accepts a format string instead of an actual URL, creating a generic URL that includes the diagnostic ID.
+ ///
+ public string? UrlFormat { get; set; }
+}
+
+#else
+[assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Diagnostics.CodeAnalysis.ExperimentalAttribute))]
+#endif
diff --git a/src/Polyfills/HashHelpers.cs b/src/Polyfills/HashHelpers.cs
new file mode 100644
index 0000000000..b8a6fa0634
--- /dev/null
+++ b/src/Polyfills/HashHelpers.cs
@@ -0,0 +1,19 @@
+//
+
+#if !NETCOREAPP
+using Microsoft.CodeAnalysis;
+
+namespace System.Numerics.Hashing;
+
+[Embedded]
+internal static class HashHelpers
+{
+ public static int Combine(int h1, int h2)
+ {
+ // RyuJIT optimizes this to use the ROL instruction
+ // Related GitHub pull request: https://github.com/dotnet/coreclr/pull/1830
+ uint rol5 = ((uint)h1 << 5) | ((uint)h1 >> 27);
+ return ((int)rol5 + h1) ^ h2;
+ }
+}
+#endif
diff --git a/src/Polyfills/Index.cs b/src/Polyfills/Index.cs
new file mode 100644
index 0000000000..d70d03a106
--- /dev/null
+++ b/src/Polyfills/Index.cs
@@ -0,0 +1,153 @@
+//
+
+#pragma warning disable
+
+#nullable enable
+
+#if !NETCOREAPP && !EXCLUDE_RANGE_INDEX_POLYFILL
+namespace System;
+
+/// Represent a type can be used to index a collection either from the start or the end.
+///
+/// Index is used by the C# compiler to support the new index syntax
+///
+/// int[] someArray = new int[5] { 1, 2, 3, 4, 5 } ;
+/// int lastElement = someArray[^1]; // lastElement = 5
+///
+///
+internal readonly struct Index : IEquatable
+{
+ private readonly int _value;
+
+ /// Construct an Index using a value and indicating if the index is from the start or from the end.
+ /// The index value. it has to be zero or positive number.
+ /// Indicating if the index is from the start or from the end.
+ ///
+ /// If the Index constructed from the end, index value 1 means pointing at the last element and index value 0 means pointing at beyond last element.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public Index(int value, bool fromEnd = false)
+ {
+ if (value < 0)
+ {
+ ThrowValueArgumentOutOfRange_NeedNonNegNumException();
+ }
+
+ if (fromEnd)
+ _value = ~value;
+ else
+ _value = value;
+ }
+
+ // The following private constructors mainly created for perf reason to avoid the checks
+ private Index(int value)
+ {
+ _value = value;
+ }
+
+ /// Create an Index pointing at first element.
+ public static Index Start => new Index(0);
+
+ /// Create an Index pointing at beyond last element.
+ public static Index End => new Index(~0);
+
+ /// Create an Index from the start at the position indicated by the value.
+ /// The index value from the start.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Index FromStart(int value)
+ {
+ if (value < 0)
+ {
+ ThrowValueArgumentOutOfRange_NeedNonNegNumException();
+ }
+
+ return new Index(value);
+ }
+
+ /// Create an Index from the end at the position indicated by the value.
+ /// The index value from the end.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Index FromEnd(int value)
+ {
+ if (value < 0)
+ {
+ ThrowValueArgumentOutOfRange_NeedNonNegNumException();
+ }
+
+ return new Index(~value);
+ }
+
+ /// Returns the index value.
+ public int Value
+ {
+ get
+ {
+ if (_value < 0)
+ return ~_value;
+ else
+ return _value;
+ }
+ }
+
+ /// Indicates whether the index is from the start or the end.
+ public bool IsFromEnd => _value < 0;
+
+ /// Calculate the offset from the start using the giving collection length.
+ /// The length of the collection that the Index will be used with. length has to be a positive value
+ ///
+ /// For performance reason, we don't validate the input length parameter and the returned offset value against negative values.
+ /// we don't validate either the returned offset is greater than the input length.
+ /// It is expected Index will be used with collections which always have non negative length/count. If the returned offset is negative and
+ /// then used to index a collection will get out of range exception which will be same affect as the validation.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public int GetOffset(int length)
+ {
+ int offset = _value;
+ if (IsFromEnd)
+ {
+ // offset = length - (~value)
+ // offset = length + (~(~value) + 1)
+ // offset = length + value + 1
+
+ offset += length + 1;
+ }
+ return offset;
+ }
+
+ /// Indicates whether the current Index object is equal to another object of the same type.
+ /// An object to compare with this object
+ public override bool Equals([NotNullWhen(true)] object? value) => value is Index && _value == ((Index)value)._value;
+
+ /// Indicates whether the current Index object is equal to another Index object.
+ /// An object to compare with this object
+ public bool Equals(Index other) => _value == other._value;
+
+ /// Returns the hash code for this instance.
+ public override int GetHashCode() => _value;
+
+ /// Converts integer number to an Index.
+ public static implicit operator Index(int value) => FromStart(value);
+
+ /// Converts the value of the current Index object to its equivalent string representation.
+ public override string ToString()
+ {
+ if (IsFromEnd)
+ return ToStringFromEnd();
+
+ return ((uint)Value).ToString();
+ }
+
+ private static void ThrowValueArgumentOutOfRange_NeedNonNegNumException()
+ {
+ throw new ArgumentOutOfRangeException("value", "value must be non-negative");
+ }
+
+ private string ToStringFromEnd()
+ {
+ return '^' + Value.ToString();
+ }
+}
+#elif NETCOREAPP
+[assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Index))]
+#endif
diff --git a/src/Polyfills/InterpolatedStringHandlerArgumentAttribute.cs b/src/Polyfills/InterpolatedStringHandlerArgumentAttribute.cs
new file mode 100644
index 0000000000..69357154f8
--- /dev/null
+++ b/src/Polyfills/InterpolatedStringHandlerArgumentAttribute.cs
@@ -0,0 +1,31 @@
+//
+
+#pragma warning disable
+
+#if !NETCOREAPP
+using Microsoft.CodeAnalysis;
+
+namespace System.Runtime.CompilerServices;
+
+/// Indicates which arguments to a method involving an interpolated string handler should be passed to that handler.
+[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)]
+[Embedded]
+internal sealed class InterpolatedStringHandlerArgumentAttribute : Attribute
+{
+ /// Initializes a new instance of the class.
+ /// The name of the argument that should be passed to the handler.
+ /// The empty string may be used as the name of the receiver in an instance method.
+ public InterpolatedStringHandlerArgumentAttribute(string argument) => Arguments = [argument];
+
+ /// Initializes a new instance of the class.
+ /// The names of the arguments that should be passed to the handler.
+ /// The empty string may be used as the name of the receiver in an instance method.
+ public InterpolatedStringHandlerArgumentAttribute(params string[] arguments) => Arguments = arguments;
+
+ /// Gets the names of the arguments that should be passed to the handler.
+ /// The empty string may be used as the name of the receiver in an instance method.
+ public string[] Arguments { get; }
+}
+#else
+[assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Runtime.CompilerServices.InterpolatedStringHandlerArgumentAttribute))]
+#endif
diff --git a/src/Polyfills/InterpolatedStringHandlerAttribute.cs b/src/Polyfills/InterpolatedStringHandlerAttribute.cs
new file mode 100644
index 0000000000..cc992adf5c
--- /dev/null
+++ b/src/Polyfills/InterpolatedStringHandlerAttribute.cs
@@ -0,0 +1,20 @@
+//
+
+#pragma warning disable
+
+#if !NETCOREAPP
+using Microsoft.CodeAnalysis;
+
+namespace System.Runtime.CompilerServices;
+
+/// Indicates the attributed type is to be used as an interpolated string handler.
+[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = false, Inherited = false)]
+[Embedded]
+internal sealed class InterpolatedStringHandlerAttribute : Attribute
+{
+ /// Initializes the .
+ public InterpolatedStringHandlerAttribute() { }
+}
+#else
+[assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Runtime.CompilerServices.InterpolatedStringHandlerAttribute))]
+#endif
diff --git a/src/Polyfills/IsExternalInit.cs b/src/Polyfills/IsExternalInit.cs
new file mode 100644
index 0000000000..9c102b9700
--- /dev/null
+++ b/src/Polyfills/IsExternalInit.cs
@@ -0,0 +1,20 @@
+//
+
+#pragma warning disable
+
+#if !NETCOREAPP
+
+using Microsoft.CodeAnalysis;
+
+namespace System.Runtime.CompilerServices;
+
+///
+/// Reserved to be used by the compiler for tracking metadata. This class should not be used by developers in source code.
+///
+[ExcludeFromCodeCoverage]
+[DebuggerNonUserCode]
+[Embedded]
+internal static class IsExternalInit;
+#else
+[assembly: TypeForwardedTo(typeof(IsExternalInit))]
+#endif
diff --git a/src/Polyfills/ModuleInitializerAttribute.cs b/src/Polyfills/ModuleInitializerAttribute.cs
new file mode 100644
index 0000000000..6b83b52c4c
--- /dev/null
+++ b/src/Polyfills/ModuleInitializerAttribute.cs
@@ -0,0 +1,24 @@
+//
+
+#pragma warning disable
+
+#if !NETCOREAPP
+
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+
+using Microsoft.CodeAnalysis;
+
+namespace System.Runtime.CompilerServices;
+///
+/// Used to indicate to the compiler that a method should be called
+/// in its containing module's initializer.
+///
+[ExcludeFromCodeCoverage]
+[DebuggerNonUserCode]
+[AttributeUsage(AttributeTargets.Method, Inherited = false)]
+[Embedded]
+internal sealed class ModuleInitializerAttribute : Attribute;
+#else
+[assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Runtime.CompilerServices.ModuleInitializerAttribute))]
+#endif
diff --git a/src/Polyfills/NullableAttribtues.cs b/src/Polyfills/NullableAttribtues.cs
new file mode 100644
index 0000000000..0ae5cbd1cb
--- /dev/null
+++ b/src/Polyfills/NullableAttribtues.cs
@@ -0,0 +1,171 @@
+//
+
+#pragma warning disable
+#nullable enable
+
+// This was copied from https://github.com/dotnet/runtime/blob/39b9607807f29e48cae4652cd74735182b31182e/src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis/NullableAttributes.cs
+// and updated to have the scope of the attributes be internal.
+
+#if !NETCOREAPP
+
+using Microsoft.CodeAnalysis;
+
+namespace System.Diagnostics.CodeAnalysis;
+
+/// Specifies that null is allowed as an input even if the corresponding type disallows it.
+[AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property, Inherited = false)]
+[Embedded]
+internal sealed class AllowNullAttribute : Attribute { }
+
+/// Specifies that null is disallowed as an input even if the corresponding type allows it.
+[AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property, Inherited = false)]
+[Embedded]
+internal sealed class DisallowNullAttribute : Attribute { }
+
+/// Specifies that an output may be null even if the corresponding type disallows it.
+[AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, Inherited = false)]
+[Embedded]
+internal sealed class MaybeNullAttribute : Attribute { }
+
+/// Specifies that an output will not be null even if the corresponding type allows it.
+[AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, Inherited = false)]
+[Embedded]
+internal sealed class NotNullAttribute : Attribute { }
+
+/// Specifies that when a method returns , the parameter may be null even if the corresponding type disallows it.
+[AttributeUsage(AttributeTargets.Parameter, Inherited = false)]
+[Embedded]
+internal sealed class MaybeNullWhenAttribute : Attribute
+{
+ /// Initializes the attribute with the specified return value condition.
+ ///
+ /// The return value condition. If the method returns this value, the associated parameter may be null.
+ ///
+ public MaybeNullWhenAttribute(bool returnValue) => ReturnValue = returnValue;
+
+ /// Gets the return value condition.
+ public bool ReturnValue { get; }
+}
+
+/// Specifies that when a method returns , the parameter will not be null even if the corresponding type allows it.
+[AttributeUsage(AttributeTargets.Parameter, Inherited = false)]
+[Embedded]
+internal sealed class NotNullWhenAttribute : Attribute
+{
+ /// Initializes the attribute with the specified return value condition.
+ ///
+ /// The return value condition. If the method returns this value, the associated parameter will not be null.
+ ///
+ public NotNullWhenAttribute(bool returnValue) => ReturnValue = returnValue;
+
+ /// Gets the return value condition.
+ public bool ReturnValue { get; }
+}
+
+/// Specifies that the output will be non-null if the named parameter is non-null.
+[AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, AllowMultiple = true, Inherited = false)]
+[Embedded]
+internal sealed class NotNullIfNotNullAttribute : Attribute
+{
+ /// Initializes the attribute with the associated parameter name.
+ ///
+ /// The associated parameter name. The output will be non-null if the argument to the parameter specified is non-null.
+ ///
+ public NotNullIfNotNullAttribute(string parameterName) => ParameterName = parameterName;
+
+ /// Gets the associated parameter name.
+ public string ParameterName { get; }
+}
+
+/// Applied to a method that will never return under any circumstance.
+[AttributeUsage(AttributeTargets.Method, Inherited = false)]
+[Embedded]
+internal sealed class DoesNotReturnAttribute : Attribute { }
+
+/// Specifies that the method will not return if the associated Boolean parameter is passed the specified value.
+[AttributeUsage(AttributeTargets.Parameter, Inherited = false)]
+[Embedded]
+internal sealed class DoesNotReturnIfAttribute : Attribute
+{
+ /// Initializes the attribute with the specified parameter value.
+ ///
+ /// The condition parameter value. Code after the method will be considered unreachable by diagnostics if the argument to
+ /// the associated parameter matches this value.
+ ///
+ public DoesNotReturnIfAttribute(bool parameterValue) => ParameterValue = parameterValue;
+
+ /// Gets the condition parameter value.
+ public bool ParameterValue { get; }
+}
+
+/// Specifies that the method or property will ensure that the listed field and property members have not-null values.
+[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)]
+[Embedded]
+internal sealed class MemberNotNullAttribute : Attribute
+{
+ /// Initializes the attribute with a field or property member.
+ ///
+ /// The field or property member that is promised to be not-null.
+ ///
+ public MemberNotNullAttribute(string member) => Members = new[] { member };
+
+ /// Initializes the attribute with the list of field and property members.
+ ///
+ /// The list of field and property members that are promised to be not-null.
+ ///
+ public MemberNotNullAttribute(params string[] members) => Members = members;
+
+ /// Gets field or property member names.
+ public string[] Members { get; }
+}
+
+/// Specifies that the method or property will ensure that the listed field and property members have not-null values when returning with the specified return value condition.
+[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)]
+[Embedded]
+internal sealed class MemberNotNullWhenAttribute : Attribute
+{
+ /// Initializes the attribute with the specified return value condition and a field or property member.
+ ///
+ /// The return value condition. If the method returns this value, the associated parameter will not be null.
+ ///
+ ///
+ /// The field or property member that is promised to be not-null.
+ ///
+ public MemberNotNullWhenAttribute(bool returnValue, string member)
+ {
+ ReturnValue = returnValue;
+ Members = new[] { member };
+ }
+
+ /// Initializes the attribute with the specified return value condition and list of field and property members.
+ ///
+ /// The return value condition. If the method returns this value, the associated parameter will not be null.
+ ///
+ ///
+ /// The list of field and property members that are promised to be not-null.
+ ///
+ public MemberNotNullWhenAttribute(bool returnValue, params string[] members)
+ {
+ ReturnValue = returnValue;
+ Members = members;
+ }
+
+ /// Gets the return value condition.
+ public bool ReturnValue { get; }
+
+ /// Gets field or property member names.
+ public string[] Members { get; }
+}
+#else
+[assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Diagnostics.CodeAnalysis.AllowNullAttribute))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Diagnostics.CodeAnalysis.DisallowNullAttribute))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Diagnostics.CodeAnalysis.MaybeNullAttribute))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Diagnostics.CodeAnalysis.NotNullAttribute))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Diagnostics.CodeAnalysis.MaybeNullWhenAttribute))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Diagnostics.CodeAnalysis.NotNullWhenAttribute))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Diagnostics.CodeAnalysis.NotNullIfNotNullAttribute))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Diagnostics.CodeAnalysis.DoesNotReturnAttribute))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Diagnostics.CodeAnalysis.DoesNotReturnIfAttribute))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Diagnostics.CodeAnalysis.MemberNotNullAttribute))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Diagnostics.CodeAnalysis.MemberNotNullWhenAttribute))]
+#endif
diff --git a/src/Polyfills/OperatingSystem.cs b/src/Polyfills/OperatingSystem.cs
new file mode 100644
index 0000000000..610f53f13f
--- /dev/null
+++ b/src/Polyfills/OperatingSystem.cs
@@ -0,0 +1,33 @@
+//
+
+#if !NETCOREAPP && !EXCLUDE_OS_POLYFILL
+
+using System;
+using System.Runtime.InteropServices;
+using System.Runtime.Versioning;
+
+using Microsoft.CodeAnalysis;
+
+namespace Polyfills;
+
+internal static partial class Polyfill
+{
+ extension(OperatingSystem)
+ {
+ public static bool IsWasi()
+ => RuntimeInformation.IsOSPlatform(OSPlatform.Create("WASI"));
+
+ public static bool IsAndroid()
+ => RuntimeInformation.IsOSPlatform(OSPlatform.Create("ANDROID"));
+
+ public static bool IsIOS()
+ => RuntimeInformation.IsOSPlatform(OSPlatform.Create("IOS"));
+
+ public static bool IsTvOS()
+ => RuntimeInformation.IsOSPlatform(OSPlatform.Create("TVOS"));
+
+ public static bool IsBrowser()
+ => RuntimeInformation.IsOSPlatform(OSPlatform.Create("BROWSER"));
+ }
+}
+#endif
diff --git a/src/Polyfills/PlatformAttributes.cs b/src/Polyfills/PlatformAttributes.cs
new file mode 100644
index 0000000000..313a47c53c
--- /dev/null
+++ b/src/Polyfills/PlatformAttributes.cs
@@ -0,0 +1,202 @@
+//
+
+#nullable enable
+
+#pragma warning disable
+
+#if !NETCOREAPP
+using Microsoft.CodeAnalysis;
+
+namespace System.Runtime.Versioning;
+
+///
+/// Base type for all platform-specific API attributes.
+///
+[Embedded]
+internal abstract class OSPlatformAttribute : Attribute
+{
+ private protected OSPlatformAttribute(string platformName)
+ {
+ PlatformName = platformName;
+ }
+
+ public string PlatformName { get; }
+}
+
+///
+/// Records the platform that the project targeted.
+///
+[AttributeUsage(AttributeTargets.Assembly,
+ AllowMultiple = false, Inherited = false)]
+[Embedded]
+internal sealed class TargetPlatformAttribute : OSPlatformAttribute
+{
+ public TargetPlatformAttribute(string platformName) : base(platformName)
+ {
+ }
+}
+
+///
+/// Records the operating system (and minimum version) that supports an API. Multiple attributes can be
+/// applied to indicate support on multiple operating systems.
+///
+///
+/// Callers can apply a
+/// or use guards to prevent calls to APIs on unsupported operating systems.
+///
+/// A given platform should only be specified once.
+///
+[AttributeUsage(AttributeTargets.Assembly |
+ AttributeTargets.Class |
+ AttributeTargets.Constructor |
+ AttributeTargets.Enum |
+ AttributeTargets.Event |
+ AttributeTargets.Field |
+ AttributeTargets.Interface |
+ AttributeTargets.Method |
+ AttributeTargets.Module |
+ AttributeTargets.Property |
+ AttributeTargets.Struct,
+ AllowMultiple = true, Inherited = false)]
+[Embedded]
+internal sealed class SupportedOSPlatformAttribute : OSPlatformAttribute
+{
+ public SupportedOSPlatformAttribute(string platformName) : base(platformName)
+ {
+ }
+}
+
+///
+/// Marks APIs that were removed in a given operating system version.
+///
+///
+/// Primarily used by OS bindings to indicate APIs that are only available in
+/// earlier versions.
+///
+[AttributeUsage(AttributeTargets.Assembly |
+ AttributeTargets.Class |
+ AttributeTargets.Constructor |
+ AttributeTargets.Enum |
+ AttributeTargets.Event |
+ AttributeTargets.Field |
+ AttributeTargets.Interface |
+ AttributeTargets.Method |
+ AttributeTargets.Module |
+ AttributeTargets.Property |
+ AttributeTargets.Struct,
+ AllowMultiple = true, Inherited = false)]
+[Embedded]
+internal sealed class UnsupportedOSPlatformAttribute : OSPlatformAttribute
+{
+ public UnsupportedOSPlatformAttribute(string platformName) : base(platformName)
+ {
+ }
+ public UnsupportedOSPlatformAttribute(string platformName, string? message) : base(platformName)
+ {
+ Message = message;
+ }
+ public string? Message { get; }
+}
+
+///
+/// Marks APIs that were obsoleted in a given operating system version.
+///
+///
+/// Primarily used by OS bindings to indicate APIs that should not be used anymore.
+///
+[AttributeUsage(AttributeTargets.Assembly |
+ AttributeTargets.Class |
+ AttributeTargets.Constructor |
+ AttributeTargets.Enum |
+ AttributeTargets.Event |
+ AttributeTargets.Field |
+ AttributeTargets.Interface |
+ AttributeTargets.Method |
+ AttributeTargets.Module |
+ AttributeTargets.Property |
+ AttributeTargets.Struct,
+ AllowMultiple = true, Inherited = false)]
+[Embedded]
+internal sealed class ObsoletedOSPlatformAttribute : OSPlatformAttribute
+{
+ ///
+ /// Initializes a new instance of the class with the specified platform name.
+ ///
+ /// The name of the platform where the API was obsoleted.
+ public ObsoletedOSPlatformAttribute(string platformName) : base(platformName)
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class with the specified platform name and message.
+ ///
+ /// The name of the platform where the API was obsoleted.
+ /// The message that explains the obsolescence.
+ public ObsoletedOSPlatformAttribute(string platformName, string? message) : base(platformName)
+ {
+ Message = message;
+ }
+
+ ///
+ /// Gets the message that explains the obsolescence.
+ ///
+ public string? Message { get; }
+
+ ///
+ /// Gets or sets the URL that provides more information about the obsolescence.
+ ///
+ public string? Url { get; set; }
+}
+
+///
+/// Annotates a custom guard field, property or method with a supported platform name and optional version.
+/// Multiple attributes can be applied to indicate guard for multiple supported platforms.
+///
+///
+/// Callers can apply a to a field, property or method
+/// and use that field, property or method in a conditional or assert statements in order to safely call platform specific APIs.
+///
+/// The type of the field or property should be boolean, the method return type should be boolean in order to be used as platform guard.
+///
+[AttributeUsage(AttributeTargets.Field |
+ AttributeTargets.Method |
+ AttributeTargets.Property,
+ AllowMultiple = true, Inherited = false)]
+[Embedded]
+internal sealed class SupportedOSPlatformGuardAttribute : OSPlatformAttribute
+{
+ public SupportedOSPlatformGuardAttribute(string platformName) : base(platformName)
+ {
+ }
+}
+
+///
+/// Annotates the custom guard field, property or method with an unsupported platform name and optional version.
+/// Multiple attributes can be applied to indicate guard for multiple unsupported platforms.
+///
+///
+/// Callers can apply a to a field, property or method
+/// and use that field, property or method in a conditional or assert statements as a guard to safely call APIs unsupported on those platforms.
+///
+/// The type of the field or property should be boolean, the method return type should be boolean in order to be used as platform guard.
+///
+[AttributeUsage(AttributeTargets.Field |
+ AttributeTargets.Method |
+ AttributeTargets.Property,
+ AllowMultiple = true, Inherited = false)]
+[Embedded]
+internal sealed class UnsupportedOSPlatformGuardAttribute : OSPlatformAttribute
+{
+ public UnsupportedOSPlatformGuardAttribute(string platformName) : base(platformName)
+ {
+ }
+}
+#else
+[assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Runtime.Versioning.OSPlatformAttribute))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Runtime.Versioning.TargetPlatformAttribute))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Runtime.Versioning.SupportedOSPlatformAttribute))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Runtime.Versioning.UnsupportedOSPlatformAttribute))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Runtime.Versioning.ObsoletedOSPlatformAttribute))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Runtime.Versioning.SupportedOSPlatformGuardAttribute))]
+[assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Runtime.Versioning.UnsupportedOSPlatformGuardAttribute))]
+#endif
diff --git a/src/Polyfills/ProcessExtensions.cs b/src/Polyfills/ProcessExtensions.cs
new file mode 100644
index 0000000000..d8a8da7f25
--- /dev/null
+++ b/src/Polyfills/ProcessExtensions.cs
@@ -0,0 +1,70 @@
+//
+
+#pragma warning disable
+
+using System;
+using System.Diagnostics;
+using System.Runtime.Versioning;
+using System.Threading;
+using System.Threading.Tasks;
+
+using Microsoft.CodeAnalysis;
+
+namespace Polyfills;
+
+[Embedded]
+internal static partial class Polyfill
+{
+#if !NET
+
+ ///
+ /// Instructs the Process component to wait for the associated process to exit, or
+ /// for the to be canceled.
+ ///
+ public static async Task WaitForExitAsync(this Process target, CancellationToken cancellationToken = default)
+ {
+ if (!target.HasExited)
+ {
+ cancellationToken.ThrowIfCancellationRequested();
+ }
+
+ try
+ {
+ target.EnableRaisingEvents = true;
+ }
+ catch (InvalidOperationException)
+ {
+ if (target.HasExited)
+ {
+ // await WaitUntilOutputEOF(cancellationToken).ConfigureAwait(false);
+ return;
+ }
+
+ throw;
+ }
+
+ var tcs = new TaskCompletionSource
-
-
+
+
+
+
diff --git a/src/TestFramework/TestFramework/Assertions/Assert.AreEqual.cs b/src/TestFramework/TestFramework/Assertions/Assert.AreEqual.cs
index 5cd7fe9939..ba9fde5ab9 100644
--- a/src/TestFramework/TestFramework/Assertions/Assert.AreEqual.cs
+++ b/src/TestFramework/TestFramework/Assertions/Assert.AreEqual.cs
@@ -208,7 +208,7 @@ public AssertNonGenericAreEqualInterpolatedStringHandler(int literalLength, int
public AssertNonGenericAreEqualInterpolatedStringHandler(int literalLength, int formattedCount, string? expected, string? actual, bool ignoreCase, CultureInfo culture, out bool shouldAppend)
{
- Ensure.NotNull(culture);
+ _ = culture ?? throw new ArgumentNullException(nameof(culture));
shouldAppend = AreEqualFailing(expected, actual, ignoreCase, culture);
if (shouldAppend)
{
@@ -314,7 +314,7 @@ public AssertNonGenericAreNotEqualInterpolatedStringHandler(int literalLength, i
public AssertNonGenericAreNotEqualInterpolatedStringHandler(int literalLength, int formattedCount, string? notExpected, string? actual, bool ignoreCase, CultureInfo culture, out bool shouldAppend)
{
- Ensure.NotNull(culture);
+ _ = culture ?? throw new ArgumentNullException(nameof(culture));
shouldAppend = AreNotEqualFailing(notExpected, actual, ignoreCase, culture);
if (shouldAppend)
{
diff --git a/src/TestFramework/TestFramework/Assertions/Assert.Contains.cs b/src/TestFramework/TestFramework/Assertions/Assert.Contains.cs
index 19fb68e0a6..846da0a78b 100644
--- a/src/TestFramework/TestFramework/Assertions/Assert.Contains.cs
+++ b/src/TestFramework/TestFramework/Assertions/Assert.Contains.cs
@@ -489,7 +489,11 @@ public static void Contains(string substring, string value, StringComparison com
CheckParameterNotNull(value, "Assert.Contains", "value");
CheckParameterNotNull(substring, "Assert.Contains", "substring");
+#if NETCOREAPP
if (!value.Contains(substring, comparisonType))
+#else
+ if (value.IndexOf(substring, comparisonType) < 0)
+#endif
{
string userMessage = BuildUserMessageForSubstringExpressionAndValueExpression(message, substringExpression, valueExpression);
string finalMessage = string.Format(CultureInfo.CurrentCulture, FrameworkMessages.ContainsFail, value, substring, userMessage);
@@ -728,7 +732,11 @@ public static void DoesNotContain(string substring, string value, StringComparis
CheckParameterNotNull(value, "Assert.DoesNotContain", "value");
CheckParameterNotNull(substring, "Assert.DoesNotContain", "substring");
+#if NETCOREAPP
if (value.Contains(substring, comparisonType))
+#else
+ if (value.IndexOf(substring, comparisonType) >= 0)
+#endif
{
string userMessage = BuildUserMessageForSubstringExpressionAndValueExpression(message, substringExpression, valueExpression);
string finalMessage = string.Format(CultureInfo.CurrentCulture, FrameworkMessages.DoesNotContainFail, value, substring, userMessage);
diff --git a/src/TestFramework/TestFramework/Assertions/Assert.That.cs b/src/TestFramework/TestFramework/Assertions/Assert.That.cs
index e13c803967..cc1338f784 100644
--- a/src/TestFramework/TestFramework/Assertions/Assert.That.cs
+++ b/src/TestFramework/TestFramework/Assertions/Assert.That.cs
@@ -72,12 +72,12 @@ private static string ExtractDetails(Expression expr)
IOrderedEnumerable> sortedDetails = details.OrderBy(kvp => kvp.Key, StringComparer.Ordinal);
var sb = new StringBuilder();
- foreach ((string name, object? value) in sortedDetails)
+ foreach (KeyValuePair kvp in sortedDetails)
{
#if NET
- sb.AppendLine(CultureInfo.InvariantCulture, $" {name} = {FormatValue(value)}");
+ sb.AppendLine(CultureInfo.InvariantCulture, $" {kvp.Key} = {FormatValue(kvp.Value)}");
#else
- sb.AppendLine($" {name} = {FormatValue(value)}");
+ sb.AppendLine($" {kvp.Key} = {FormatValue(kvp.Value)}");
#endif
}
@@ -640,7 +640,7 @@ private static string CleanParentheses(string input)
private static string RemoveOuterParentheses(string input)
{
- if (input.Length < 2 || !input.StartsWith('(') || !input.EndsWith(')'))
+ if (input.Length < 2 || !input.StartsWith("(", StringComparison.Ordinal) || !input.EndsWith(")", StringComparison.Ordinal))
{
return input;
}
diff --git a/src/TestFramework/TestFramework/Assertions/Assert.ThrowsException.cs b/src/TestFramework/TestFramework/Assertions/Assert.ThrowsException.cs
index b5478a28a6..417f12afd4 100644
--- a/src/TestFramework/TestFramework/Assertions/Assert.ThrowsException.cs
+++ b/src/TestFramework/TestFramework/Assertions/Assert.ThrowsException.cs
@@ -321,8 +321,8 @@ public static TException ThrowsExactly(Func
-
+
diff --git a/test/IntegrationTests/MSTest.IntegrationTests/Utilities/TestCaseFilterFactory.cs b/test/IntegrationTests/MSTest.IntegrationTests/Utilities/TestCaseFilterFactory.cs
index 3bccf96779..f4600147b8 100644
--- a/test/IntegrationTests/MSTest.IntegrationTests/Utilities/TestCaseFilterFactory.cs
+++ b/test/IntegrationTests/MSTest.IntegrationTests/Utilities/TestCaseFilterFactory.cs
@@ -7,8 +7,6 @@
using Microsoft.VisualStudio.TestPlatform.ObjectModel.Adapter;
using Microsoft.VisualStudio.TestPlatform.ObjectModel.Utilities;
-using Polyfills;
-
namespace DiscoveryAndExecutionTests.Utilities;
internal static class TestCaseFilterFactory
@@ -19,7 +17,11 @@ internal static class TestCaseFilterFactory
public static ITestCaseFilterExpression ParseTestFilter(string filterString)
{
- Ensure.NotNullOrEmpty(filterString);
+ if (string.IsNullOrEmpty(filterString))
+ {
+ throw new ArgumentException("Filter string cannot be null or empty.", nameof(filterString));
+ }
+
if (Regex.IsMatch(filterString, @"\(\s*\)"))
{
throw new FormatException($"Invalid filter, empty parenthesis: {filterString}");
@@ -119,7 +121,7 @@ public bool MatchTestCase(TestCase testCase, Func propertyValue
private static void MergeExpression(Stack, bool>>> exp, Operator op)
{
- Ensure.NotNull(exp);
+ _ = exp ?? throw new ArgumentNullException(nameof(exp));
if (op is not Operator.And and not Operator.Or)
{
throw new ArgumentException($"Unexpected operator: {op}", nameof(op));
@@ -190,7 +192,6 @@ private static IEnumerable TokenizeFilter(string filterString)
private static IEnumerable TokenizeCondition(string conditionString)
{
- Ensure.NotNullOrEmpty(conditionString);
var token = new StringBuilder(conditionString.Length);
for (int i = 0; i < conditionString.Length; i++)
@@ -286,7 +287,10 @@ private static bool ContainsComparer(string[] values, string value)
private static Expression, bool>> ConditionExpression(string conditionString)
{
- Ensure.NotNull(conditionString);
+ if (string.IsNullOrEmpty(conditionString))
+ {
+ throw new ArgumentException("Condition string cannot be null or empty.", nameof(conditionString));
+ }
string[] condition = [.. TokenizeCondition(conditionString)];
diff --git a/test/IntegrationTests/Microsoft.Testing.Platform.Acceptance.IntegrationTests/ForwardCompatibilityTests.cs b/test/IntegrationTests/Microsoft.Testing.Platform.Acceptance.IntegrationTests/ForwardCompatibilityTests.cs
index c9edc53e61..fad778e23e 100644
--- a/test/IntegrationTests/Microsoft.Testing.Platform.Acceptance.IntegrationTests/ForwardCompatibilityTests.cs
+++ b/test/IntegrationTests/Microsoft.Testing.Platform.Acceptance.IntegrationTests/ForwardCompatibilityTests.cs
@@ -26,7 +26,7 @@ public async Task NewerPlatform_WithPreviousExtensions_ShouldExecuteTests()
public sealed class TestAssetFixture() : TestAssetFixtureBase(AcceptanceFixture.NuGetGlobalPackagesFolder)
{
- private const string PreviousExtensionVersion = "2.0.0";
+ private const string PreviousExtensionVersion = "2.2.1";
private const string ForwardCompatibilityTestCode = """
#file ForwardCompatibilityTest.csproj
@@ -115,7 +115,7 @@ public Task CloseTestSessionAsync(CloseTestSessionContex
public async Task ExecuteRequestAsync(ExecuteRequestContext context)
{
await context.MessageBus.PublishAsync(this, new TestNodeUpdateMessage(context.Request.Session.SessionUid,
- new TestNode() { Uid = "0", DisplayName = "ForwardCompatibilityTest", Properties = new(PassedTestNodeStateProperty.CachedInstance) }));
+ new TestNode() { Uid = "0", DisplayName = "ForwardCompatibilityTest", Properties = new(PassedTestNodeStateProperty.CachedInstance, new TrxFullyQualifiedTypeNameProperty("MyNS.MyTestClass")) }));
context.Complete();
}
}
diff --git a/test/IntegrationTests/Microsoft.Testing.Platform.Acceptance.IntegrationTests/Microsoft.Testing.Platform.Acceptance.IntegrationTests.csproj b/test/IntegrationTests/Microsoft.Testing.Platform.Acceptance.IntegrationTests/Microsoft.Testing.Platform.Acceptance.IntegrationTests.csproj
index a9b216db53..c6846768aa 100644
--- a/test/IntegrationTests/Microsoft.Testing.Platform.Acceptance.IntegrationTests/Microsoft.Testing.Platform.Acceptance.IntegrationTests.csproj
+++ b/test/IntegrationTests/Microsoft.Testing.Platform.Acceptance.IntegrationTests/Microsoft.Testing.Platform.Acceptance.IntegrationTests.csproj
@@ -18,10 +18,13 @@
-
+
+
+
+
diff --git a/test/UnitTests/MSTest.Analyzers.UnitTests/MSTest.Analyzers.UnitTests.csproj b/test/UnitTests/MSTest.Analyzers.UnitTests/MSTest.Analyzers.UnitTests.csproj
index 62237a43c6..e5b7a70cb9 100644
--- a/test/UnitTests/MSTest.Analyzers.UnitTests/MSTest.Analyzers.UnitTests.csproj
+++ b/test/UnitTests/MSTest.Analyzers.UnitTests/MSTest.Analyzers.UnitTests.csproj
@@ -31,8 +31,10 @@
+
-
+
+
diff --git a/test/UnitTests/MSTest.Analyzers.UnitTests/Verifiers/CSharpCodeFixVerifier`2.cs b/test/UnitTests/MSTest.Analyzers.UnitTests/Verifiers/CSharpCodeFixVerifier`2.cs
index 127d42d656..82497d76f3 100644
--- a/test/UnitTests/MSTest.Analyzers.UnitTests/Verifiers/CSharpCodeFixVerifier`2.cs
+++ b/test/UnitTests/MSTest.Analyzers.UnitTests/Verifiers/CSharpCodeFixVerifier`2.cs
@@ -31,7 +31,9 @@ public static DiagnosticResult Diagnostic(DiagnosticDescriptor descriptor)
///
public static async Task VerifyAnalyzerAsync(
+#if NETCOREAPP
[StringSyntax("C#-test")]
+#endif
string source, params DiagnosticResult[] expected)
{
var test = new Test
@@ -45,27 +47,39 @@ public static async Task VerifyAnalyzerAsync(
///
public static async Task VerifyCodeFixAsync(
+#if NETCOREAPP
[StringSyntax("C#-test")]
+#endif
string source,
+#if NETCOREAPP
[StringSyntax("C#-test")]
+#endif
string fixedSource)
=> await VerifyCodeFixAsync(source, DiagnosticResult.EmptyDiagnosticResults, fixedSource);
///
public static async Task VerifyCodeFixAsync(
+#if NETCOREAPP
[StringSyntax("C#-test")]
+#endif
string source,
DiagnosticResult expected,
+#if NETCOREAPP
[StringSyntax("C#-test")]
+#endif
string fixedSource)
=> await VerifyCodeFixAsync(source, [expected], fixedSource);
///
public static async Task VerifyCodeFixAsync(
+#if NETCOREAPP
[StringSyntax("C#-test")]
+#endif
string source,
DiagnosticResult[] expected,
+#if NETCOREAPP
[StringSyntax("C#-test")]
+#endif
string fixedSource)
{
var test = new Test
diff --git a/test/UnitTests/MSTest.Analyzers.UnitTests/Verifiers/VisualBasicCodeFixVerifier`2.cs b/test/UnitTests/MSTest.Analyzers.UnitTests/Verifiers/VisualBasicCodeFixVerifier`2.cs
index bd6fa42d6c..53f6309d60 100644
--- a/test/UnitTests/MSTest.Analyzers.UnitTests/Verifiers/VisualBasicCodeFixVerifier`2.cs
+++ b/test/UnitTests/MSTest.Analyzers.UnitTests/Verifiers/VisualBasicCodeFixVerifier`2.cs
@@ -31,7 +31,9 @@ public static DiagnosticResult Diagnostic(DiagnosticDescriptor descriptor)
///
public static async Task VerifyAnalyzerAsync(
+#if NETCOREAPP
[StringSyntax("VB-test")]
+#endif
string source, params DiagnosticResult[] expected)
{
var test = new Test
@@ -45,27 +47,39 @@ public static async Task VerifyAnalyzerAsync(
///
public static async Task VerifyCodeFixAsync(
+#if NETCOREAPP
[StringSyntax("VB-test")]
+#endif
string source,
+#if NETCOREAPP
[StringSyntax("VB-test")]
+#endif
string fixedSource)
=> await VerifyCodeFixAsync(source, DiagnosticResult.EmptyDiagnosticResults, fixedSource);
///
public static async Task VerifyCodeFixAsync(
+#if NETCOREAPP
[StringSyntax("VB-test")]
+#endif
string source,
DiagnosticResult expected,
+#if NETCOREAPP
[StringSyntax("VB-test")]
+#endif
string fixedSource)
=> await VerifyCodeFixAsync(source, [expected], fixedSource);
///
public static async Task VerifyCodeFixAsync(
+#if NETCOREAPP
[StringSyntax("VB-test")]
+#endif
string source,
DiagnosticResult[] expected,
+#if NETCOREAPP
[StringSyntax("VB-test")]
+#endif
string fixedSource)
{
var test = new Test
diff --git a/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Discovery/TypeEnumeratorTests.MockedMethodInfoWithExtraAttributes.cs b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Discovery/TypeEnumeratorTests.MockedMethodInfoWithExtraAttributes.cs
index a351eada6d..a8c629987d 100644
--- a/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Discovery/TypeEnumeratorTests.MockedMethodInfoWithExtraAttributes.cs
+++ b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Discovery/TypeEnumeratorTests.MockedMethodInfoWithExtraAttributes.cs
@@ -1,10 +1,6 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
-#if !NET6_0_OR_GREATER
-using Polyfills;
-#endif
-
namespace Microsoft.VisualStudio.TestPlatform.MSTestAdapter.UnitTests.Discovery;
public partial class TypeEnumeratorTests
@@ -68,7 +64,7 @@ public MockedMethodInfoWithExtraAttributes(MethodInfo original, params Attribute
public override object[] GetCustomAttributes(bool inherit) => _original.GetCustomAttributes().Concat(_extraAttributes).ToArray();
- public override object[] GetCustomAttributes(Type attributeType, bool inherit) => _original.GetCustomAttributes().Concat(_extraAttributes.Where(a => a.GetType().IsAssignableTo(attributeType))).ToArray();
+ public override object[] GetCustomAttributes(Type attributeType, bool inherit) => _original.GetCustomAttributes().Concat(_extraAttributes.Where(a => attributeType.IsAssignableFrom(a.GetType()))).ToArray();
public override IList GetCustomAttributesData() => _original.GetCustomAttributesData();
@@ -86,7 +82,7 @@ public MockedMethodInfoWithExtraAttributes(MethodInfo original, params Attribute
=> _original.Invoke(obj, invokeAttr, binder, parameters, culture);
public override bool IsDefined(Type attributeType, bool inherit)
- => _original.IsDefined(attributeType, inherit) || _extraAttributes.Any(a => a.GetType().IsAssignableTo(attributeType));
+ => _original.IsDefined(attributeType, inherit) || _extraAttributes.Any(a => attributeType.IsAssignableFrom(a.GetType()));
public override MethodInfo MakeGenericMethod(params Type[] typeArguments) => _original.MakeGenericMethod(typeArguments);
diff --git a/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/MSTestAdapter.PlatformServices.UnitTests.csproj b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/MSTestAdapter.PlatformServices.UnitTests.csproj
index 5cf1911159..f2fa7a0cdd 100644
--- a/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/MSTestAdapter.PlatformServices.UnitTests.csproj
+++ b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/MSTestAdapter.PlatformServices.UnitTests.csproj
@@ -32,7 +32,10 @@
-
+
+
+
+
diff --git a/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/ObjectModel/UnitTestElementTests.cs b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/ObjectModel/UnitTestElementTests.cs
index 370fda5fa7..d7f4967493 100644
--- a/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/ObjectModel/UnitTestElementTests.cs
+++ b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/ObjectModel/UnitTestElementTests.cs
@@ -157,8 +157,11 @@ public void ToTestCaseShouldSetDeploymentItemPropertyIfPresent()
public void ToTestCase_WhenStrategyIsData_DoesNotUseDefaultTestCaseId()
{
-#pragma warning disable CA2263 // Prefer generic overload when type is known
+#if NETCOREAPP
foreach (DynamicDataType dataType in Enum.GetValues())
+#else
+ foreach (DynamicDataType dataType in Enum.GetValues(typeof(DynamicDataType)))
+#endif
{
var testCase = new UnitTestElement(new("MyMethod", "MyProduct.MyNamespace.MyClass", "MyAssembly", null)
{
@@ -172,7 +175,6 @@ public void ToTestCase_WhenStrategyIsData_DoesNotUseDefaultTestCaseId()
Guid.TryParse(dataType == DynamicDataType.None ? "157ad7ac-90d2-8e05-a240-056ef4253f19" : "1834fb10-d2d5-8106-8620-918822cdc63a", out Guid expectedId2).Should().BeTrue();
expectedId.Should().Be(expectedId2);
}
-#pragma warning restore CA2263 // Prefer generic overload when type is known
static Guid GuidFromString(string data)
{
diff --git a/test/UnitTests/MSTestAdapter.UnitTests/MSTestAdapter.UnitTests.csproj b/test/UnitTests/MSTestAdapter.UnitTests/MSTestAdapter.UnitTests.csproj
index 6ca3cab48e..4cd17ec7e7 100644
--- a/test/UnitTests/MSTestAdapter.UnitTests/MSTestAdapter.UnitTests.csproj
+++ b/test/UnitTests/MSTestAdapter.UnitTests/MSTestAdapter.UnitTests.csproj
@@ -31,7 +31,10 @@
-
+
+
+
+
diff --git a/test/UnitTests/Microsoft.Testing.Extensions.UnitTests/Microsoft.Testing.Extensions.UnitTests.csproj b/test/UnitTests/Microsoft.Testing.Extensions.UnitTests/Microsoft.Testing.Extensions.UnitTests.csproj
index 62289d70b7..3ed3a5e269 100644
--- a/test/UnitTests/Microsoft.Testing.Extensions.UnitTests/Microsoft.Testing.Extensions.UnitTests.csproj
+++ b/test/UnitTests/Microsoft.Testing.Extensions.UnitTests/Microsoft.Testing.Extensions.UnitTests.csproj
@@ -34,7 +34,10 @@
-
+
+
+
+
diff --git a/test/UnitTests/Microsoft.Testing.Extensions.UnitTests/TrxTests.cs b/test/UnitTests/Microsoft.Testing.Extensions.UnitTests/TrxTests.cs
index 34729b1a8c..491a882efe 100644
--- a/test/UnitTests/Microsoft.Testing.Extensions.UnitTests/TrxTests.cs
+++ b/test/UnitTests/Microsoft.Testing.Extensions.UnitTests/TrxTests.cs
@@ -537,9 +537,22 @@ public async Task TrxReportEngine_GenerateReportAsync_FileAlreadyExists_WillRetr
_ = _configurationMock.SetupGet(_ => _[It.IsAny()]).Returns(string.Empty);
_ = _environmentMock.SetupGet(_ => _.MachineName).Returns("MachineName");
_ = _testApplicationModuleInfoMock.Setup(_ => _.GetCurrentTestApplicationFullPath()).Returns("TestAppPath");
- var trxReportEngine = new TrxReportEngine(_fileSystem.Object, _testApplicationModuleInfoMock.Object, _environmentMock.Object, _commandLineOptionsMock.Object,
- _configurationMock.Object, _clockMock.Object,
- _artifactsByExtension, _testFrameworkMock.Object, DateTime.UtcNow, 0, CancellationToken.None);
+ var trxReportEngine = new TrxReportEngine(
+ _fileSystem.Object,
+ _testApplicationModuleInfoMock.Object,
+ _environmentMock.Object,
+ _commandLineOptionsMock.Object,
+ _configurationMock.Object,
+ _clockMock.Object,
+ _artifactsByExtension,
+ _testFrameworkMock.Object,
+ DateTime.UtcNow,
+#if NETCOREAPP
+ 0,
+ CancellationToken.None);
+#else
+ 0);
+#endif
// Act
_ = await trxReportEngine.GenerateReportAsync([]);
@@ -693,7 +706,6 @@ private static TestNodeUpdateMessage CreateTestNodeUpdate(string uid, string dis
private TrxReportEngine GenerateTrxReportEngine(MemoryFileStream memoryStream, bool isExplicitFileName = false)
{
DateTime testStartTime = DateTime.Now;
- CancellationToken cancellationToken = CancellationToken.None;
_ = _fileSystem.Setup(x => x.ExistFile(It.IsAny())).Returns(false);
_ = _fileSystem.Setup(x => x.NewFileStream(It.IsAny(), isExplicitFileName ? FileMode.Create : FileMode.CreateNew))
@@ -703,9 +715,22 @@ private TrxReportEngine GenerateTrxReportEngine(MemoryFileStream memoryStream, b
_ = _environmentMock.SetupGet(_ => _.MachineName).Returns("MachineName");
_ = _testApplicationModuleInfoMock.Setup(_ => _.GetCurrentTestApplicationFullPath()).Returns("TestAppPath");
- return new TrxReportEngine(_fileSystem.Object, _testApplicationModuleInfoMock.Object, _environmentMock.Object, _commandLineOptionsMock.Object,
- _configurationMock.Object, _clockMock.Object,
- _artifactsByExtension, _testFrameworkMock.Object, testStartTime, 0, cancellationToken);
+ return new TrxReportEngine(
+ _fileSystem.Object,
+ _testApplicationModuleInfoMock.Object,
+ _environmentMock.Object,
+ _commandLineOptionsMock.Object,
+ _configurationMock.Object,
+ _clockMock.Object,
+ _artifactsByExtension,
+ _testFrameworkMock.Object,
+ testStartTime,
+#if NETCOREAPP
+ 0,
+ CancellationToken.None);
+#else
+ 0);
+#endif
}
private sealed class MemoryFileStream : IFileStream
diff --git a/test/UnitTests/Microsoft.Testing.Extensions.VSTestBridge.UnitTests/Microsoft.Testing.Extensions.VSTestBridge.UnitTests.csproj b/test/UnitTests/Microsoft.Testing.Extensions.VSTestBridge.UnitTests/Microsoft.Testing.Extensions.VSTestBridge.UnitTests.csproj
index 65ac530917..26698caab5 100644
--- a/test/UnitTests/Microsoft.Testing.Extensions.VSTestBridge.UnitTests/Microsoft.Testing.Extensions.VSTestBridge.UnitTests.csproj
+++ b/test/UnitTests/Microsoft.Testing.Extensions.VSTestBridge.UnitTests/Microsoft.Testing.Extensions.VSTestBridge.UnitTests.csproj
@@ -17,7 +17,10 @@
-
+
+
+
+
diff --git a/test/UnitTests/Microsoft.Testing.Platform.UnitTests/Configuration/ConfigurationExtensionsTests.cs b/test/UnitTests/Microsoft.Testing.Platform.UnitTests/Configuration/ConfigurationExtensionsTests.cs
index 104bff4626..67bd0c012a 100644
--- a/test/UnitTests/Microsoft.Testing.Platform.UnitTests/Configuration/ConfigurationExtensionsTests.cs
+++ b/test/UnitTests/Microsoft.Testing.Platform.UnitTests/Configuration/ConfigurationExtensionsTests.cs
@@ -42,6 +42,7 @@ public void ConfigurationExtensions_TestedMethod_ThrowsArgumentNullException(str
.Setup(configuration => configuration[key])
.Returns(value: null);
- Assert.ThrowsExactly(() => GetActualValueFromConfiguration(configuration.Object, key));
+ // This should never happen in practice. We always have AggregatedConfiguration which will ensure non-null values.
+ Assert.ThrowsExactly(() => GetActualValueFromConfiguration(configuration.Object, key));
}
}
diff --git a/test/UnitTests/Microsoft.Testing.Platform.UnitTests/Helpers/CountDownEventTests.cs b/test/UnitTests/Microsoft.Testing.Platform.UnitTests/Helpers/CountDownEventTests.cs
index 49f81499da..fef796da19 100644
--- a/test/UnitTests/Microsoft.Testing.Platform.UnitTests/Helpers/CountDownEventTests.cs
+++ b/test/UnitTests/Microsoft.Testing.Platform.UnitTests/Helpers/CountDownEventTests.cs
@@ -41,7 +41,11 @@ public async Task CountDownEvent_WaitAsyncCanceled_Succeeded()
CancellationTokenSource cts = new();
CancellationToken cancelToken = cts.Token;
Task waiter = Task.Run(() => countdownEvent.WaitAsync(cancelToken), cancelToken);
+#if NETCOREAPP
await cts.CancelAsync();
+#else
+ cts.Cancel();
+#endif
await Assert.ThrowsAsync(async () => await waiter);
}
diff --git a/test/UnitTests/Microsoft.Testing.Platform.UnitTests/Microsoft.Testing.Platform.UnitTests.csproj b/test/UnitTests/Microsoft.Testing.Platform.UnitTests/Microsoft.Testing.Platform.UnitTests.csproj
index 954782fee0..abb6845845 100644
--- a/test/UnitTests/Microsoft.Testing.Platform.UnitTests/Microsoft.Testing.Platform.UnitTests.csproj
+++ b/test/UnitTests/Microsoft.Testing.Platform.UnitTests/Microsoft.Testing.Platform.UnitTests.csproj
@@ -34,7 +34,10 @@
-
+
+
+
+
diff --git a/test/UnitTests/TestFramework.UnitTests/Assertions/AssertTests.AreEqualTests.cs b/test/UnitTests/TestFramework.UnitTests/Assertions/AssertTests.AreEqualTests.cs
index 1ba1daaad9..f7901cfdce 100644
--- a/test/UnitTests/TestFramework.UnitTests/Assertions/AssertTests.AreEqualTests.cs
+++ b/test/UnitTests/TestFramework.UnitTests/Assertions/AssertTests.AreEqualTests.cs
@@ -1649,7 +1649,7 @@ public void CreateStringPreviews_DiffNeverPointsAtEllipsis_Generated()
{
string p = FormatStringPreview(StringPreviewHelper.CreateStringPreviews(DigitString(e, d), DigitString(a, d), diffIndex: d, 11));
- string[] lines = p.Split("\n");
+ string[] lines = p.Split('\n');
int diffIndicator = lines[2].IndexOf('^');
bool line0PointsOnEllipsis = lines[0].Length > diffIndicator && lines[0][diffIndicator] == '.';
bool line1PointsOnEllipsis = lines[1].Length > diffIndicator && lines[1][diffIndicator] == '.';
diff --git a/test/UnitTests/TestFramework.UnitTests/TestFramework.UnitTests.csproj b/test/UnitTests/TestFramework.UnitTests/TestFramework.UnitTests.csproj
index 6b9b4137dc..82d0d6a4f0 100644
--- a/test/UnitTests/TestFramework.UnitTests/TestFramework.UnitTests.csproj
+++ b/test/UnitTests/TestFramework.UnitTests/TestFramework.UnitTests.csproj
@@ -24,7 +24,10 @@
-
+
+
+
+
diff --git a/test/Utilities/Automation.CLI/Automation.CLI.csproj b/test/Utilities/Automation.CLI/Automation.CLI.csproj
index cbb4fe349f..5070065d87 100644
--- a/test/Utilities/Automation.CLI/Automation.CLI.csproj
+++ b/test/Utilities/Automation.CLI/Automation.CLI.csproj
@@ -2,12 +2,16 @@
$(NetFrameworkMinimum)
+ $(DefineConstants);EXCLUDE_RANGE_INDEX_POLYFILL;EXCLUDE_OS_POLYFILL
-
+
+
+
+
diff --git a/test/Utilities/Microsoft.Testing.TestInfrastructure/Microsoft.Testing.TestInfrastructure.csproj b/test/Utilities/Microsoft.Testing.TestInfrastructure/Microsoft.Testing.TestInfrastructure.csproj
index 73bb77b1b6..e83f1d866d 100644
--- a/test/Utilities/Microsoft.Testing.TestInfrastructure/Microsoft.Testing.TestInfrastructure.csproj
+++ b/test/Utilities/Microsoft.Testing.TestInfrastructure/Microsoft.Testing.TestInfrastructure.csproj
@@ -9,7 +9,10 @@
-
+
+
+
+
diff --git a/test/Utilities/Microsoft.Testing.TestInfrastructure/ProjectSystem.cs b/test/Utilities/Microsoft.Testing.TestInfrastructure/ProjectSystem.cs
index 8c1c12b0fb..104c42b4e8 100644
--- a/test/Utilities/Microsoft.Testing.TestInfrastructure/ProjectSystem.cs
+++ b/test/Utilities/Microsoft.Testing.TestInfrastructure/ProjectSystem.cs
@@ -79,12 +79,16 @@ public class CSharpProject : Project
private readonly string _projectFileName;
private XElement _projectContent = new("Project", new XAttribute("Sdk", "Microsoft.NET.Sdk"), new XElement("PropertyGroup"), new XElement("ItemGroup"));
- public CSharpProject(string solutionFolder, string projectName, params string[]? tfms)
+ public CSharpProject(string solutionFolder, string projectName, params string[] tfms)
: base(Path.Combine(solutionFolder, projectName))
{
Ensure.NotNullOrWhiteSpace(solutionFolder);
Ensure.NotNullOrWhiteSpace(projectName);
- Ensure.NotNullOrEmpty(tfms);
+
+ if (tfms is null || tfms.Length == 0)
+ {
+ throw new InvalidOperationException("tfms must have at least one element.");
+ }
_projectFileName = $"{projectName}.csproj";
ProjectFile = Path.Combine(FolderPath, _projectFileName);
diff --git a/test/Utilities/TestFramework.ForTestingMSTest/TestFramework.ForTestingMSTest.csproj b/test/Utilities/TestFramework.ForTestingMSTest/TestFramework.ForTestingMSTest.csproj
index 23bdfc6d46..34e87a0e16 100644
--- a/test/Utilities/TestFramework.ForTestingMSTest/TestFramework.ForTestingMSTest.csproj
+++ b/test/Utilities/TestFramework.ForTestingMSTest/TestFramework.ForTestingMSTest.csproj
@@ -16,7 +16,7 @@
-
+