diff --git a/Directory.Build.props b/Directory.Build.props index c52560a235..10c3dd0e46 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -75,16 +75,6 @@ Microsoft.Testing.Platform - - - true - - true - true - true - @@ -103,4 +93,14 @@ + + + $(NoWarn);CS0436 + + + + + diff --git a/Directory.Packages.props b/Directory.Packages.props index 200a555f01..77b88f4e70 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -58,7 +58,6 @@ - diff --git a/eng/Polyfills.cs b/eng/Polyfills.cs new file mode 100644 index 0000000000..fbddb3f60e --- /dev/null +++ b/eng/Polyfills.cs @@ -0,0 +1,971 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +// This file provides polyfills for types that are not available on older target frameworks (netstandard2.0, .NET Framework). +#pragma warning disable SA1201 // Elements should appear in the correct order +#pragma warning disable SA1403 // File may only contain a single namespace +#pragma warning disable SA1502 // Element should not be on a single line +#pragma warning disable SA1649 // File name should match first type name +#pragma warning disable SA1405 // Debug.Assert should provide message text +#pragma warning disable SA1407 // Arithmetic expressions should declare precedence +#pragma warning disable SA1513 // Closing brace should be followed by blank line +#pragma warning disable SA1516 // Elements should be separated by blank line +#pragma warning disable CA1305 // Specify IFormatProvider +#pragma warning disable IDE0007 // Use 'var' instead of explicit type +#pragma warning disable IDE0046 // If statement can be simplified +#pragma warning disable IDE0065 // Misplaced using directive +#pragma warning disable IDE0280 // Use 'nameof' +#pragma warning disable SA1512 // Single-line comments should not be followed by blank line + +// On TFMs where IsExternalInit is provided by the BCL, add a TypeForwardedTo so that +// assemblies compiled against the netstandard2.0 version (which had the polyfill type) +// can resolve the type at runtime on net5+. +// See https://github.com/SimonCropp/Polyfill/issues/290 +#if NET5_0_OR_GREATER +#pragma warning disable RS0016 // Symbol is not part of the declared public API - compiler support type forwarding +[assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Runtime.CompilerServices.IsExternalInit))] +#pragma warning restore RS0016 +#else + +namespace System.Runtime.CompilerServices +{ + internal static class IsExternalInit; + + [global::System.AttributeUsage(global::System.AttributeTargets.Module | global::System.AttributeTargets.Class | global::System.AttributeTargets.Struct | global::System.AttributeTargets.Constructor | global::System.AttributeTargets.Method | global::System.AttributeTargets.Property | global::System.AttributeTargets.Event | global::System.AttributeTargets.Interface, Inherited = false)] + internal sealed class RequiredMemberAttribute : Attribute { } + + [global::System.AttributeUsage(global::System.AttributeTargets.All, AllowMultiple = true, Inherited = false)] + internal sealed class CompilerFeatureRequiredAttribute : Attribute + { + public CompilerFeatureRequiredAttribute(string featureName) => FeatureName = featureName; + + public string FeatureName { get; } + + public bool IsOptional { get; init; } + } +} + +namespace System.Diagnostics.CodeAnalysis +{ + [global::System.AttributeUsage(global::System.AttributeTargets.Method, Inherited = false)] + internal sealed class DoesNotReturnAttribute : Attribute { } + + [global::System.AttributeUsage(global::System.AttributeTargets.Parameter, Inherited = false)] + internal sealed class DoesNotReturnIfAttribute : Attribute + { + public DoesNotReturnIfAttribute(bool parameterValue) => ParameterValue = parameterValue; + + public bool ParameterValue { get; } + } + + [global::System.AttributeUsage(global::System.AttributeTargets.Method | global::System.AttributeTargets.Property, AllowMultiple = true, Inherited = false)] + internal sealed class MemberNotNullAttribute : Attribute + { + public MemberNotNullAttribute(string member) => Members = [member]; + + public MemberNotNullAttribute(params string[] members) => Members = members; + + public string[] Members { get; } + } + + [global::System.AttributeUsage(global::System.AttributeTargets.Method | global::System.AttributeTargets.Property, AllowMultiple = true, Inherited = false)] + internal sealed class MemberNotNullWhenAttribute : Attribute + { + public MemberNotNullWhenAttribute(bool returnValue, string member) + { + ReturnValue = returnValue; + Members = [member]; + } + + public MemberNotNullWhenAttribute(bool returnValue, params string[] members) + { + ReturnValue = returnValue; + Members = members; + } + + public bool ReturnValue { get; } + + public string[] Members { get; } + } + + [global::System.AttributeUsage(global::System.AttributeTargets.Property | global::System.AttributeTargets.Parameter | global::System.AttributeTargets.ReturnValue, AllowMultiple = true, Inherited = false)] + internal sealed class NotNullIfNotNullAttribute : Attribute + { + public NotNullIfNotNullAttribute(string parameterName) => ParameterName = parameterName; + + public string ParameterName { get; } + } + + [global::System.AttributeUsage(global::System.AttributeTargets.Parameter, Inherited = false)] + internal sealed class NotNullWhenAttribute : Attribute + { + public NotNullWhenAttribute(bool returnValue) => ReturnValue = returnValue; + + public bool ReturnValue { get; } + } + + [global::System.AttributeUsage(global::System.AttributeTargets.Property | global::System.AttributeTargets.Field | global::System.AttributeTargets.Parameter | global::System.AttributeTargets.ReturnValue, Inherited = false)] + internal sealed class NotNullAttribute : Attribute { } + + [global::System.AttributeUsage(global::System.AttributeTargets.Property | global::System.AttributeTargets.Field | global::System.AttributeTargets.Parameter, Inherited = false)] + internal sealed class AllowNullAttribute : Attribute { } + + [global::System.AttributeUsage(global::System.AttributeTargets.Property | global::System.AttributeTargets.Field | global::System.AttributeTargets.Parameter, Inherited = false)] + internal sealed class DisallowNullAttribute : Attribute { } + + [global::System.AttributeUsage(global::System.AttributeTargets.Property | global::System.AttributeTargets.Field | global::System.AttributeTargets.Parameter | global::System.AttributeTargets.ReturnValue, Inherited = false)] + internal sealed class MaybeNullAttribute : Attribute { } + + [global::System.AttributeUsage(global::System.AttributeTargets.Parameter | global::System.AttributeTargets.Property | global::System.AttributeTargets.ReturnValue, AllowMultiple = true, Inherited = false)] + internal sealed class StringSyntaxAttribute : Attribute + { + public const string Regex = nameof(Regex); + public const string Uri = nameof(Uri); + public const string Xml = nameof(Xml); + + public StringSyntaxAttribute(string syntax, params object?[] arguments) + { + Syntax = syntax; + Arguments = arguments; + } + + public string Syntax { get; } + + public object?[] Arguments { get; } + } + + [global::System.AttributeUsage(global::System.AttributeTargets.Field | global::System.AttributeTargets.ReturnValue | global::System.AttributeTargets.GenericParameter | global::System.AttributeTargets.Parameter | global::System.AttributeTargets.Property | global::System.AttributeTargets.Method | global::System.AttributeTargets.Class | global::System.AttributeTargets.Interface | global::System.AttributeTargets.Struct, Inherited = false)] + internal sealed class DynamicallyAccessedMembersAttribute : Attribute + { + public DynamicallyAccessedMembersAttribute(DynamicallyAccessedMemberTypes memberTypes) => MemberTypes = memberTypes; + + public DynamicallyAccessedMemberTypes MemberTypes { get; } + } + + [global::System.Flags] + internal enum DynamicallyAccessedMemberTypes + { + None = 0, + PublicParameterlessConstructor = 0x0001, + PublicConstructors = 0x0003, + NonPublicConstructors = 0x0004, + PublicMethods = 0x0008, + NonPublicMethods = 0x0010, + PublicFields = 0x0020, + NonPublicFields = 0x0040, + PublicNestedTypes = 0x0080, + NonPublicNestedTypes = 0x0100, + PublicProperties = 0x0200, + NonPublicProperties = 0x0400, + PublicEvents = 0x0800, + NonPublicEvents = 0x1000, + Interfaces = 0x2000, + All = ~None, + } + + [global::System.AttributeUsage(global::System.AttributeTargets.Method | global::System.AttributeTargets.Constructor | global::System.AttributeTargets.Class, Inherited = false, AllowMultiple = true)] + internal sealed class UnconditionalSuppressMessageAttribute : Attribute + { + public UnconditionalSuppressMessageAttribute(string category, string checkId) + { + Category = category; + CheckId = checkId; + } + + public string Category { get; } + + public string CheckId { get; } + + public string? Scope { get; set; } + + public string? Target { get; set; } + + public string? MessageId { get; set; } + + public string? Justification { get; set; } + } +} + +namespace System.Runtime.Versioning +{ + [global::System.AttributeUsage(global::System.AttributeTargets.Assembly | global::System.AttributeTargets.Module | global::System.AttributeTargets.Class | global::System.AttributeTargets.Struct | global::System.AttributeTargets.Enum | global::System.AttributeTargets.Constructor | global::System.AttributeTargets.Method | global::System.AttributeTargets.Property | global::System.AttributeTargets.Field | global::System.AttributeTargets.Event | global::System.AttributeTargets.Interface, AllowMultiple = true, Inherited = false)] + internal sealed class SupportedOSPlatformAttribute : Attribute + { + public SupportedOSPlatformAttribute(string platformName) => PlatformName = platformName; + + public string PlatformName { get; } + } + + [global::System.AttributeUsage(global::System.AttributeTargets.Method | global::System.AttributeTargets.Property | global::System.AttributeTargets.Field, AllowMultiple = true, Inherited = false)] + internal sealed class SupportedOSPlatformGuardAttribute : Attribute + { + public SupportedOSPlatformGuardAttribute(string platformName) => PlatformName = platformName; + + public string PlatformName { get; } + } + + [global::System.AttributeUsage(global::System.AttributeTargets.Assembly | global::System.AttributeTargets.Module | global::System.AttributeTargets.Class | global::System.AttributeTargets.Struct | global::System.AttributeTargets.Enum | global::System.AttributeTargets.Constructor | global::System.AttributeTargets.Method | global::System.AttributeTargets.Property | global::System.AttributeTargets.Field | global::System.AttributeTargets.Event | global::System.AttributeTargets.Interface, AllowMultiple = true, Inherited = false)] + internal sealed class UnsupportedOSPlatformAttribute : Attribute + { + public UnsupportedOSPlatformAttribute(string platformName) => PlatformName = platformName; + + public string PlatformName { get; } + } + + [global::System.AttributeUsage(global::System.AttributeTargets.Method | global::System.AttributeTargets.Property | global::System.AttributeTargets.Field, AllowMultiple = true, Inherited = false)] + internal sealed class UnsupportedOSPlatformGuardAttribute : Attribute + { + public UnsupportedOSPlatformGuardAttribute(string platformName) => PlatformName = platformName; + + public string PlatformName { get; } + } +} + +#endif + +#if !NET6_0_OR_GREATER + +namespace System.Runtime.CompilerServices +{ + [global::System.AttributeUsage(global::System.AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)] + internal sealed class CallerArgumentExpressionAttribute : Attribute + { + public CallerArgumentExpressionAttribute(string parameterName) => ParameterName = parameterName; + + public string ParameterName { get; } + } + + [global::System.AttributeUsage(global::System.AttributeTargets.Class | global::System.AttributeTargets.Struct, AllowMultiple = false, Inherited = false)] + internal sealed class InterpolatedStringHandlerAttribute : Attribute { } + + [global::System.AttributeUsage(global::System.AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)] + internal sealed class InterpolatedStringHandlerArgumentAttribute : Attribute + { + public InterpolatedStringHandlerArgumentAttribute(string argument) => Arguments = [argument]; + + public InterpolatedStringHandlerArgumentAttribute(params string[] arguments) => Arguments = arguments; + + public string[] Arguments { get; } + } +} + +namespace System.Diagnostics +{ + [global::System.AttributeUsage(global::System.AttributeTargets.Class | global::System.AttributeTargets.Method | global::System.AttributeTargets.Constructor | global::System.AttributeTargets.Struct, Inherited = false)] + internal sealed class StackTraceHiddenAttribute : Attribute { } +} +namespace System.Runtime.CompilerServices +{ + [global::System.AttributeUsage(global::System.AttributeTargets.Method, Inherited = false)] + internal sealed class ModuleInitializerAttribute : Attribute { } +} +#endif + +#if !NET8_0_OR_GREATER + +namespace System.Diagnostics.CodeAnalysis +{ + [global::System.AttributeUsage(global::System.AttributeTargets.Assembly | global::System.AttributeTargets.Module | global::System.AttributeTargets.Class | global::System.AttributeTargets.Struct | global::System.AttributeTargets.Enum | global::System.AttributeTargets.Constructor | global::System.AttributeTargets.Method | global::System.AttributeTargets.Property | global::System.AttributeTargets.Field | global::System.AttributeTargets.Event | global::System.AttributeTargets.Interface | global::System.AttributeTargets.Delegate, Inherited = false)] + internal sealed class ExperimentalAttribute : Attribute + { + public ExperimentalAttribute(string diagnosticId) => DiagnosticId = diagnosticId; + + public string DiagnosticId { get; } + + public string? UrlFormat { get; set; } + } +} + +#endif + +#if !NET9_0_OR_GREATER + +namespace System.Runtime.CompilerServices +{ + [global::System.AttributeUsage(global::System.AttributeTargets.Parameter, Inherited = false, AllowMultiple = false)] + internal sealed class ParamCollectionAttribute : Attribute { } +} + +#endif + +#if !NET9_0_OR_GREATER + +namespace System.Threading +{ +#pragma warning disable CS9216 // A value of type 'Lock' converted to a different type will use likely unintended monitor-based locking + internal sealed class Lock + { + public void Enter() => Monitor.Enter(this); + + public void Exit() => Monitor.Exit(this); + + public Scope EnterScope() + { + Monitor.Enter(this); + return new Scope(this); + } + + public ref struct Scope + { + private Lock? _lock; + + internal Scope(Lock @lock) => _lock = @lock; + + public void Dispose() + { + Lock? lockObj = _lock; + if (lockObj is not null) + { + _lock = null; + lockObj.Exit(); + } + } + } + } +} + +#endif + +#if !NET5_0_OR_GREATER + +namespace System +{ + internal readonly struct Index : IEquatable + { + private readonly int _value; + + public Index(int value, bool fromEnd = false) + { + if (value < 0) + { + throw new ArgumentOutOfRangeException(nameof(value), "Index must not be negative."); + } + + _value = fromEnd ? ~value : value; + } + + private Index(int value) => _value = value; + + public static Index Start => new(0); + + public static Index End => new(~0); + + public int Value => _value < 0 ? ~_value : _value; + + public bool IsFromEnd => _value < 0; + + public static Index FromStart(int value) => value >= 0 ? new Index(value) : throw new ArgumentOutOfRangeException(nameof(value), "Index must not be negative."); + + public static Index FromEnd(int value) => value >= 0 ? new Index(~value) : throw new ArgumentOutOfRangeException(nameof(value), "Index must not be negative."); + + public static implicit operator Index(int value) => FromStart(value); + + public int GetOffset(int length) + { + int offset = _value; + if (IsFromEnd) + { + offset += length + 1; + } + + return offset; + } + + public override bool Equals(object? value) => value is Index index && _value == index._value; + + public bool Equals(Index other) => _value == other._value; + + public override int GetHashCode() => _value; + + public override string ToString() => IsFromEnd ? $"^{(uint)Value}" : ((uint)Value).ToString(); + } + + internal readonly struct Range : IEquatable + { + public Index Start { get; } + + public Index End { get; } + + public Range(Index start, Index end) + { + Start = start; + End = end; + } + + public static Range StartAt(Index start) => new(start, Index.End); + + public static Range EndAt(Index end) => new(Index.Start, end); + + public static Range All => new(Index.Start, Index.End); + + public override bool Equals(object? value) => value is Range r && r.Start.Equals(Start) && r.End.Equals(End); + + public bool Equals(Range other) => other.Start.Equals(Start) && other.End.Equals(End); + + public override int GetHashCode() => Start.GetHashCode() * 31 + End.GetHashCode(); + + public override string ToString() => $"{Start}..{End}"; + + public void GetOffsetAndLength(int length, out int offset, out int len) + { + int start = Start.GetOffset(length); + int end = End.GetOffset(length); + if ((uint)end > (uint)length || (uint)start > (uint)end) + { + throw new ArgumentOutOfRangeException(nameof(length)); + } + + offset = start; + len = end - start; + } + } +} + +namespace System.Runtime.CompilerServices +{ + internal static class RuntimeHelpers + { + /// Slices the specified array using the specified range. + /// The type of the array elements. + public static T[] GetSubArray(T[] array, Range range) + { + range.GetOffsetAndLength(array.Length, out int offset, out int length); + T[] dest = new T[length]; + Array.Copy(array, offset, dest, 0, length); + return dest; + } + } +} + +#endif + +namespace Microsoft.CodeAnalysis +{ + [global::System.AttributeUsage(global::System.AttributeTargets.All, AllowMultiple = false, Inherited = false)] + internal sealed partial class EmbeddedAttribute : global::System.Attribute { } +} + +#pragma warning disable CS8603 // Possible null reference return +#pragma warning disable CS8777 // Parameter must have a non-null value when exiting +#pragma warning disable RS0030 // Banned API - Ensure is the guard implementation itself +internal static class Ensure +{ + [return: global::System.Diagnostics.CodeAnalysis.NotNull] + public static T NotNull([global::System.Diagnostics.CodeAnalysis.NotNull] T? argument, [global::System.Runtime.CompilerServices.CallerArgumentExpression("argument")] string? paramName = null) + { + if (argument is null) + { + throw new global::System.ArgumentNullException(paramName); + } + + return argument; + } + + public static string NotNullOrEmpty([global::System.Diagnostics.CodeAnalysis.NotNull] string? argument, [global::System.Runtime.CompilerServices.CallerArgumentExpression("argument")] string? paramName = null) + { + if (argument is null) + { + throw new global::System.ArgumentNullException(paramName); + } + + if (argument.Length == 0) + { + throw new global::System.ArgumentException("Value cannot be null or empty.", paramName); + } + + return argument; + } + + public static void NotNullOrEmpty([global::System.Diagnostics.CodeAnalysis.NotNull] global::System.Collections.Generic.IEnumerable? argument, [global::System.Runtime.CompilerServices.CallerArgumentExpression("argument")] string? paramName = null) + { + if (argument is null) + { + throw new global::System.ArgumentNullException(paramName); + } + + if (argument is global::System.Collections.Generic.ICollection collection) + { + if (collection.Count == 0) + { + throw new global::System.ArgumentException("Value cannot be empty.", paramName); + } + + return; + } + + using global::System.Collections.Generic.IEnumerator enumerator = argument.GetEnumerator(); + if (!enumerator.MoveNext()) + { + throw new global::System.ArgumentException("Value cannot be empty.", paramName); + } + } + + public static string NotNullOrWhiteSpace([global::System.Diagnostics.CodeAnalysis.NotNull] string? argument, [global::System.Runtime.CompilerServices.CallerArgumentExpression("argument")] string? paramName = null) + { + if (argument is null) + { + throw new global::System.ArgumentNullException(paramName); + } + + if (argument.Trim().Length == 0) + { + throw new global::System.ArgumentException("Value cannot be null or whitespace.", paramName); + } + + return argument; + } +} + +// Backward-compatible stubs for Polyfills.Guard and Polyfills.Ensure types. +// The old Polyfill NuGet package generated these types into the Microsoft.Testing.Platform assembly; +// old extension packages (compiled against the previous platform version with InternalsVisibleTo) +// may reference these types at runtime. Providing them here prevents TypeLoadExceptions. +#if IS_CORE_MTP +namespace Polyfills +{ + [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] + [global::System.Diagnostics.DebuggerNonUserCode] + internal static class Guard + { + [return: global::System.Diagnostics.CodeAnalysis.NotNull] + public static T NotNull([global::System.Diagnostics.CodeAnalysis.NotNull] T? argument, [global::System.Runtime.CompilerServices.CallerArgumentExpression("argument")] string? name = null) + where T : class + { + if (argument is null) + { + throw new global::System.ArgumentNullException(name); + } + + return argument; + } + + [return: global::System.Diagnostics.CodeAnalysis.NotNull] + public static string NotNull([global::System.Diagnostics.CodeAnalysis.NotNull] string? argument, [global::System.Runtime.CompilerServices.CallerArgumentExpression("argument")] string? name = null) + { + if (argument is null) + { + throw new global::System.ArgumentNullException(name); + } + + return argument; + } + + public static string NotNullOrEmpty([global::System.Diagnostics.CodeAnalysis.NotNull] string? value, [global::System.Runtime.CompilerServices.CallerArgumentExpression("value")] string? name = null) + => Ensure.NotNullOrEmpty(value, name); + + public static T NotNullOrEmpty([global::System.Diagnostics.CodeAnalysis.NotNull] T? value, [global::System.Runtime.CompilerServices.CallerArgumentExpression("value")] string? name = null) + where T : global::System.Collections.IEnumerable + => Ensure.NotNullOrEmpty(value, name); + + public static string NotNullOrWhiteSpace([global::System.Diagnostics.CodeAnalysis.NotNull] string? value, [global::System.Runtime.CompilerServices.CallerArgumentExpression("value")] string? name = null) + => Ensure.NotNullOrWhiteSpace(value, name); + + public static void FileExists(string path, [global::System.Runtime.CompilerServices.CallerArgumentExpression("path")] string? name = null) + => Ensure.FileExists(path, name); + + public static void DirectoryExists(string path, [global::System.Runtime.CompilerServices.CallerArgumentExpression("path")] string? name = null) + => Ensure.DirectoryExists(path, name); + } + + [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] + [global::System.Diagnostics.DebuggerNonUserCode] + internal static class Ensure + { + [return: global::System.Diagnostics.CodeAnalysis.NotNull] + public static T NotNull([global::System.Diagnostics.CodeAnalysis.NotNull] T? argument, [global::System.Runtime.CompilerServices.CallerArgumentExpression("argument")] string? name = null) + where T : class + { + if (argument is null) + { + throw new global::System.ArgumentNullException(name); + } + + return argument; + } + + [return: global::System.Diagnostics.CodeAnalysis.NotNull] + public static string NotNull([global::System.Diagnostics.CodeAnalysis.NotNull] string? argument, [global::System.Runtime.CompilerServices.CallerArgumentExpression("argument")] string? name = null) + { + if (argument is null) + { + throw new global::System.ArgumentNullException(name); + } + + return argument; + } + + public static string NotNullOrEmpty([global::System.Diagnostics.CodeAnalysis.NotNull] string? value, [global::System.Runtime.CompilerServices.CallerArgumentExpression("value")] string? name = null) + { + if (string.IsNullOrEmpty(value)) + { + throw new global::System.ArgumentException("Must not be null or empty.", name); + } + + return value; + } + + [return: global::System.Diagnostics.CodeAnalysis.NotNull] + public static T NotNullOrEmpty([global::System.Diagnostics.CodeAnalysis.NotNull] T? value, [global::System.Runtime.CompilerServices.CallerArgumentExpression("value")] string? name = null) + where T : global::System.Collections.IEnumerable + { + if (value is null) + { + throw new global::System.ArgumentNullException(name); + } + + global::System.Collections.IEnumerator enumerator = value.GetEnumerator(); + try + { + if (!enumerator.MoveNext()) + { + throw new global::System.ArgumentException("Must not be empty.", name); + } + } + finally + { + (enumerator as global::System.IDisposable)?.Dispose(); + } + + return value; + } + + public static string NotNullOrWhiteSpace([global::System.Diagnostics.CodeAnalysis.NotNull] string? value, [global::System.Runtime.CompilerServices.CallerArgumentExpression("value")] string? name = null) + { + if (string.IsNullOrWhiteSpace(value)) + { + throw new global::System.ArgumentException("Must not be null or whitespace.", name); + } + + return value; + } + + public static void FileExists(string path, [global::System.Runtime.CompilerServices.CallerArgumentExpression("path")] string? name = null) + { + if (!global::System.IO.File.Exists(path)) + { + throw new global::System.ArgumentException($"File not found. Path: {path}", name); + } + } + + public static void DirectoryExists(string path, [global::System.Runtime.CompilerServices.CallerArgumentExpression("path")] string? name = null) + { + if (!global::System.IO.Directory.Exists(path)) + { + throw new global::System.ArgumentException($"Directory not found. Path: {path}", name); + } + } + } + + // Polyfills.Polyfill stub: The old Polyfill NuGet package generated this type into every assembly. + // Old extensions (compiled with InternalsVisibleTo to the platform) may reference methods on + // this type from the platform assembly. We need to provide it for backward compatibility. + [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] + [global::System.Diagnostics.DebuggerNonUserCode] + internal static class Polyfill + { +#if NETCOREAPP + public static bool Contains(global::System.ReadOnlySpan span, T value, global::System.Collections.Generic.IEqualityComparer? comparer = null) + { + comparer ??= global::System.Collections.Generic.EqualityComparer.Default; + foreach (T item in span) + { + if (comparer.Equals(item, value)) + { + return true; + } + } + + return false; + } +#endif + } +} +#endif + +// All extension method polyfills are guarded with IS_CORE_MTP to avoid ambiguity when +// projects reference Microsoft.Testing.Platform with InternalsVisibleTo. Projects that +// do not reference Platform and need these extensions should provide their own copies. +#if IS_CORE_MTP + +#if !NET8_0_OR_GREATER + +internal static class CancellationTokenSourceExtensions +{ + public static global::System.Threading.Tasks.Task CancelAsync(this global::System.Threading.CancellationTokenSource cancellationTokenSource) + { + cancellationTokenSource.Cancel(); + return global::System.Threading.Tasks.Task.CompletedTask; + } +} + +#endif // !NET8_0_OR_GREATER + +#if !NET5_0_OR_GREATER + +internal static class PolyfillStringExtensions +{ + public static bool Contains(this string s, char c) => s.IndexOf(c) >= 0; + + public static bool StartsWith(this string s, char c) => s.Length > 0 && s[0] == c; + + public static bool EndsWith(this string s, char c) => s.Length > 0 && s[s.Length - 1] == c; + + public static string[] Split(this string s, char separator, global::System.StringSplitOptions options = global::System.StringSplitOptions.None) => + s.Split([separator], options); + + public static string[] Split(this string s, char separator, int count, global::System.StringSplitOptions options = global::System.StringSplitOptions.None) => + s.Split([separator], count, options); + + public static string Replace(this string s, string oldValue, string? newValue, global::System.StringComparison comparisonType) + { + if (comparisonType == global::System.StringComparison.Ordinal) + { + return s.Replace(oldValue, newValue); + } + + var sb = new global::System.Text.StringBuilder(); + int previousIndex = 0; + int index = s.IndexOf(oldValue, comparisonType); + while (index != -1) + { + sb.Append(s, previousIndex, index - previousIndex); + sb.Append(newValue); + index += oldValue.Length; + previousIndex = index; + index = s.IndexOf(oldValue, index, comparisonType); + } + + sb.Append(s, previousIndex, s.Length - previousIndex); + return sb.ToString(); + } + + public static bool Contains(this string s, string value, global::System.StringComparison comparisonType) => + s.IndexOf(value, comparisonType) >= 0; + + public static int GetHashCode(this string s, global::System.StringComparison comparisonType) => + comparisonType switch + { + global::System.StringComparison.Ordinal => global::System.StringComparer.Ordinal.GetHashCode(s), + global::System.StringComparison.OrdinalIgnoreCase => global::System.StringComparer.OrdinalIgnoreCase.GetHashCode(s), + _ => global::System.StringComparer.OrdinalIgnoreCase.GetHashCode(s), + }; +} + +internal static class PolyfillEnumExtensions +{ + public static TEnum Parse(string value) + where TEnum : struct => + (TEnum)global::System.Enum.Parse(typeof(TEnum), value); + + public static TEnum Parse(string value, bool ignoreCase) + where TEnum : struct => + (TEnum)global::System.Enum.Parse(typeof(TEnum), value, ignoreCase); +} + +// Note: Deconstruct for KeyValuePair is intentionally NOT provided here because it causes +// ambiguity errors when projects reference each other with InternalsVisibleTo and both +// compile this file. It is provided in Microsoft.Testing.Platform project's own source. + +internal static class PolyfillDictionaryExtensions +{ + public static bool TryAdd(this global::System.Collections.Generic.Dictionary dictionary, TKey key, TValue value) + where TKey : notnull + { + if (!dictionary.ContainsKey(key)) + { + dictionary.Add(key, value); + return true; + } + + return false; + } +} + +internal static class PolyfillStringBuilderExtensions +{ + public static global::System.Text.StringBuilder AppendJoin(this global::System.Text.StringBuilder sb, string separator, global::System.Collections.Generic.IEnumerable values) + { + bool first = true; + foreach (string value in values) + { + if (!first) + { + sb.Append(separator); + } + + sb.Append(value); + first = false; + } + + return sb; + } + + public static global::System.Text.StringBuilder AppendJoin(this global::System.Text.StringBuilder sb, string separator, global::System.Collections.Generic.IEnumerable values) + { + bool first = true; + foreach (T value in values) + { + if (!first) + { + sb.Append(separator); + } + + sb.Append(value); + first = false; + } + + return sb; + } + + public static global::System.Text.StringBuilder AppendJoin(this global::System.Text.StringBuilder sb, char separator, global::System.Collections.Generic.IEnumerable values) => + sb.AppendJoin(separator.ToString(), values); +} + +internal static class PolyfillTaskExtensions +{ + public static async global::System.Threading.Tasks.Task WaitAsync(this global::System.Threading.Tasks.Task task, global::System.Threading.CancellationToken cancellationToken) + { + var tcs = new global::System.Threading.Tasks.TaskCompletionSource(global::System.Threading.Tasks.TaskCreationOptions.RunContinuationsAsynchronously); + using (cancellationToken.Register(s => ((global::System.Threading.Tasks.TaskCompletionSource)s!).TrySetCanceled(cancellationToken), tcs)) + { + if (task != await global::System.Threading.Tasks.Task.WhenAny(task, tcs.Task).ConfigureAwait(false)) + { + throw new global::System.OperationCanceledException(cancellationToken); + } + } + + await task.ConfigureAwait(false); + } + + public static async global::System.Threading.Tasks.Task WaitAsync(this global::System.Threading.Tasks.Task task, global::System.TimeSpan timeout, global::System.Threading.CancellationToken cancellationToken = default) + { + using var cts = global::System.Threading.CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); + cts.CancelAfter(timeout); + try + { + await task.WaitAsync(cts.Token).ConfigureAwait(false); + } + catch (global::System.OperationCanceledException) when (!cancellationToken.IsCancellationRequested) + { + throw new global::System.TimeoutException(); + } + } + + public static async global::System.Threading.Tasks.Task WaitAsync(this global::System.Threading.Tasks.Task task, global::System.Threading.CancellationToken cancellationToken) + { + var tcs = new global::System.Threading.Tasks.TaskCompletionSource(global::System.Threading.Tasks.TaskCreationOptions.RunContinuationsAsynchronously); + using (cancellationToken.Register(s => ((global::System.Threading.Tasks.TaskCompletionSource)s!).TrySetCanceled(cancellationToken), tcs)) + { + if (task != await global::System.Threading.Tasks.Task.WhenAny(task, tcs.Task).ConfigureAwait(false)) + { + throw new global::System.OperationCanceledException(cancellationToken); + } + } + + return await task.ConfigureAwait(false); + } +} + +internal static class PolyfillProcessExtensions +{ + public static global::System.Threading.Tasks.Task WaitForExitAsync(this global::System.Diagnostics.Process process, global::System.Threading.CancellationToken cancellationToken = default) + { + if (process.HasExited) + { + return global::System.Threading.Tasks.Task.CompletedTask; + } + + var tcs = new global::System.Threading.Tasks.TaskCompletionSource(global::System.Threading.Tasks.TaskCreationOptions.RunContinuationsAsynchronously); + process.EnableRaisingEvents = true; + + global::System.EventHandler handler = (_, _) => tcs.TrySetResult(true); + process.Exited += handler; + + global::System.Threading.CancellationTokenRegistration cancellationRegistration = default; + if (cancellationToken.CanBeCanceled) + { + cancellationRegistration = cancellationToken.Register(() => tcs.TrySetCanceled(cancellationToken)); + } + + if (process.HasExited) + { + process.Exited -= handler; + cancellationRegistration.Dispose(); + return global::System.Threading.Tasks.Task.CompletedTask; + } + + return tcs.Task.ContinueWith( + _ => + { + process.Exited -= handler; + cancellationRegistration.Dispose(); + }, + global::System.Threading.CancellationToken.None, + global::System.Threading.Tasks.TaskContinuationOptions.ExecuteSynchronously, + global::System.Threading.Tasks.TaskScheduler.Default); + } + + public static void Kill(this global::System.Diagnostics.Process process, bool entireProcessTree) => + // entireProcessTree not supported on netstandard2.0 - just kill the process + process.Kill(); +} + +#endif // !NET5_0_OR_GREATER + +#endif // IS_CORE_MTP + +#if !NET5_0_OR_GREATER + +internal static class OperatingSystem +{ + public static bool IsBrowser() => false; + + public static bool IsWasi() => false; + + public static bool IsAndroid() => false; + + public static bool IsIOS() => false; + + public static bool IsTvOS() => false; + +#if NETFRAMEWORK + public static bool IsWindows() => global::System.Environment.OSVersion.Platform == global::System.PlatformID.Win32NT; + + public static bool IsLinux() => false; + + public static bool IsMacOS() => false; +#else + public static bool IsWindows() => global::System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform(global::System.Runtime.InteropServices.OSPlatform.Windows); + + public static bool IsLinux() => global::System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform(global::System.Runtime.InteropServices.OSPlatform.Linux); + + public static bool IsMacOS() => global::System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform(global::System.Runtime.InteropServices.OSPlatform.OSX); +#endif +} + +#endif + +#if !NET7_0_OR_GREATER + +namespace System.Diagnostics +{ + internal sealed class UnreachableException : Exception + { + public UnreachableException() + : base("The program executed an instruction that was thought to be unreachable.") + { + } + + public UnreachableException(string? message) + : base(message) + { + } + + public UnreachableException(string? message, Exception? innerException) + : base(message, innerException) + { + } + } +} + +#endif diff --git a/src/Adapter/MSTest.Engine/MSTest.Engine.csproj b/src/Adapter/MSTest.Engine/MSTest.Engine.csproj index d9d5992e1e..d995eb4dd5 100644 --- a/src/Adapter/MSTest.Engine/MSTest.Engine.csproj +++ b/src/Adapter/MSTest.Engine/MSTest.Engine.csproj @@ -59,10 +59,6 @@ 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..e2c8fd7767 100644 --- a/src/Adapter/MSTest.TestAdapter/MSTest.TestAdapter.csproj +++ b/src/Adapter/MSTest.TestAdapter/MSTest.TestAdapter.csproj @@ -65,10 +65,6 @@ - - - - @@ -90,7 +86,6 @@ - diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Execution/Polyfills/EmbeddedAttribute.cs b/src/Adapter/MSTestAdapter.PlatformServices/Execution/Polyfills/EmbeddedAttribute.cs index 2665ce0bb4..b3c7f40add 100644 --- a/src/Adapter/MSTestAdapter.PlatformServices/Execution/Polyfills/EmbeddedAttribute.cs +++ b/src/Adapter/MSTestAdapter.PlatformServices/Execution/Polyfills/EmbeddedAttribute.cs @@ -1,10 +1,4 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. -#if NETFRAMEWORK -namespace Microsoft.CodeAnalysis; - -internal sealed partial class EmbeddedAttribute : Attribute -{ -} -#endif +// EmbeddedAttribute is now provided by eng/Polyfills.cs. diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Extensions/MethodInfoExtensions.cs b/src/Adapter/MSTestAdapter.PlatformServices/Extensions/MethodInfoExtensions.cs index 933ab3a2f3..e5073fcb0b 100644 --- a/src/Adapter/MSTestAdapter.PlatformServices/Extensions/MethodInfoExtensions.cs +++ b/src/Adapter/MSTestAdapter.PlatformServices/Extensions/MethodInfoExtensions.cs @@ -199,7 +199,11 @@ 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 NET5_0_OR_GREATER + if (parameterType.IsGenericMethodParameter) +#else + if (parameterType.IsGenericParameter && parameterType.DeclaringMethod is not null) +#endif { // 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/MSTestAdapter.PlatformServices.csproj b/src/Adapter/MSTestAdapter.PlatformServices/MSTestAdapter.PlatformServices.csproj index 3393d8818c..3b6cac444f 100644 --- a/src/Adapter/MSTestAdapter.PlatformServices/MSTestAdapter.PlatformServices.csproj +++ b/src/Adapter/MSTestAdapter.PlatformServices/MSTestAdapter.PlatformServices.csproj @@ -35,7 +35,6 @@ - @@ -55,7 +54,6 @@ - diff --git a/src/Adapter/MSTestAdapter.PlatformServices/MSTestSettings.cs b/src/Adapter/MSTestAdapter.PlatformServices/MSTestSettings.cs index 501d5559cd..26b3d84634 100644 --- a/src/Adapter/MSTestAdapter.PlatformServices/MSTestSettings.cs +++ b/src/Adapter/MSTestAdapter.PlatformServices/MSTestSettings.cs @@ -713,7 +713,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; } @@ -740,7 +740,7 @@ 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) - && Enum.IsDefined(result); + && Enum.IsDefined(typeof(T), result); private static void SetGlobalSettings( [StringSyntax(StringSyntaxAttribute.Xml, nameof(runsettingsXml))] string runsettingsXml, @@ -902,7 +902,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/PolyfillExtensions.cs b/src/Adapter/MSTestAdapter.PlatformServices/PolyfillExtensions.cs new file mode 100644 index 0000000000..59eff40e52 --- /dev/null +++ b/src/Adapter/MSTestAdapter.PlatformServices/PolyfillExtensions.cs @@ -0,0 +1,72 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +// Polyfill extension methods for the Adapter projects which target +// net462 and need APIs not available on .NET Framework. +#if !NET5_0_OR_GREATER + +internal static class AdapterPolyfillExtensions +{ + public static bool Contains(this string s, char c) => s.IndexOf(c) >= 0; + + public static bool StartsWith(this string s, char c) => s.Length > 0 && s[0] == c; + + public static bool EndsWith(this string s, char c) => s.Length > 0 && s[s.Length - 1] == c; + + public static bool IsAssignableTo(this System.Type type, System.Type? targetType) + => targetType?.IsAssignableFrom(type) ?? false; + + public static bool TryAdd(this System.Collections.Generic.Dictionary dictionary, TKey key, TValue value) + where TKey : notnull + { + if (!dictionary.ContainsKey(key)) + { + dictionary.Add(key, value); + return true; + } + + return false; + } + + public static System.Text.StringBuilder AppendJoin(this System.Text.StringBuilder sb, string separator, System.Collections.Generic.IEnumerable values) + { + bool first = true; + foreach (string value in values) + { + if (!first) + { + sb.Append(separator); + } + + sb.Append(value); + first = false; + } + + return sb; + } + + public static System.Text.StringBuilder AppendJoin(this System.Text.StringBuilder sb, char separator, System.Collections.Generic.IEnumerable values) => + sb.AppendJoin(separator.ToString(), values); + + public static TValue GetOrAdd(this System.Collections.Concurrent.ConcurrentDictionary dictionary, TKey key, System.Func valueFactory, TArg factoryArgument) + where TKey : notnull + => dictionary.GetOrAdd(key, k => valueFactory(k, factoryArgument)); + + public static string[] Split(this string s, char separator, System.StringSplitOptions options) => + s.Split([separator], options); +} + +#endif + +#if !NET8_0_OR_GREATER + +internal static class AdapterCancellationTokenSourcePolyfill +{ + public static System.Threading.Tasks.Task CancelAsync(this System.Threading.CancellationTokenSource cts) + { + cts.Cancel(); + return System.Threading.Tasks.Task.CompletedTask; + } +} + +#endif diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Services/TestDataSource.cs b/src/Adapter/MSTestAdapter.PlatformServices/Services/TestDataSource.cs index 2fea97032a..db8fd73992 100644 --- a/src/Adapter/MSTestAdapter.PlatformServices/Services/TestDataSource.cs +++ b/src/Adapter/MSTestAdapter.PlatformServices/Services/TestDataSource.cs @@ -142,7 +142,7 @@ private static void GetConnectionProperties(DataSourceAttribute dataSourceAttrib providerNameInvariant = ConfigurationManager.ConnectionStrings[element.ConnectionString].ProviderName; connectionString = ConfigurationManager.ConnectionStrings[element.ConnectionString].ConnectionString; tableName = element.DataTableName; - dataAccessMethod = Enum.Parse(element.DataAccessMethod); + dataAccessMethod = (DataAccessMethod)Enum.Parse(typeof(DataAccessMethod), element.DataAccessMethod); } #endif } diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Services/TestSourceHost.cs b/src/Adapter/MSTestAdapter.PlatformServices/Services/TestSourceHost.cs index a36cdb5b98..feedd430c8 100644 --- a/src/Adapter/MSTestAdapter.PlatformServices/Services/TestSourceHost.cs +++ b/src/Adapter/MSTestAdapter.PlatformServices/Services/TestSourceHost.cs @@ -136,7 +136,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/DeploymentUtility.cs b/src/Adapter/MSTestAdapter.PlatformServices/Utilities/DeploymentUtility.cs index 00aaac90be..1003d3ad9d 100644 --- a/src/Adapter/MSTestAdapter.PlatformServices/Utilities/DeploymentUtility.cs +++ b/src/Adapter/MSTestAdapter.PlatformServices/Utilities/DeploymentUtility.cs @@ -64,7 +64,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}"; + using var currentProcess = Process.GetCurrentProcess(); + string dateTimeSuffix = $"{DateTime.Now.ToString("yyyyMMddTHHmmss", DateTimeFormatInfo.InvariantInfo)}_{currentProcess.Id}"; string directoryName = string.Format(CultureInfo.InvariantCulture, Resource.TestRunName, DeploymentFolderPrefix, #if NETFRAMEWORK Environment.UserName, diff --git a/src/Analyzers/MSTest.Analyzers.CodeFixes/MSTest.Analyzers.CodeFixes.csproj b/src/Analyzers/MSTest.Analyzers.CodeFixes/MSTest.Analyzers.CodeFixes.csproj index ad9bdcf545..525d079c19 100644 --- a/src/Analyzers/MSTest.Analyzers.CodeFixes/MSTest.Analyzers.CodeFixes.csproj +++ b/src/Analyzers/MSTest.Analyzers.CodeFixes/MSTest.Analyzers.CodeFixes.csproj @@ -8,7 +8,6 @@ - diff --git a/src/Analyzers/MSTest.Analyzers/MSTest.Analyzers.csproj b/src/Analyzers/MSTest.Analyzers/MSTest.Analyzers.csproj index 77efce2f98..cc4f02058b 100644 --- a/src/Analyzers/MSTest.Analyzers/MSTest.Analyzers.csproj +++ b/src/Analyzers/MSTest.Analyzers/MSTest.Analyzers.csproj @@ -20,7 +20,6 @@ - diff --git a/src/Analyzers/MSTest.Analyzers/RoslynAnalyzerHelpers/AnalyzerPolyfillExtensions.cs b/src/Analyzers/MSTest.Analyzers/RoslynAnalyzerHelpers/AnalyzerPolyfillExtensions.cs new file mode 100644 index 0000000000..d1145b8dc1 --- /dev/null +++ b/src/Analyzers/MSTest.Analyzers/RoslynAnalyzerHelpers/AnalyzerPolyfillExtensions.cs @@ -0,0 +1,31 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +// Polyfill extension methods specific to the Analyzers project (which targets netstandard2.0 +// only and does not reference Microsoft.Testing.Platform). + +internal static class AnalyzerPolyfillExtensions +{ + public static bool IsAssignableTo(this System.Type type, System.Type? targetType) + => targetType?.IsAssignableFrom(type) ?? false; + + public static void Deconstruct(this System.Collections.Generic.KeyValuePair pair, out TKey key, out TValue value) + { + key = pair.Key; + value = pair.Value; + } + + public static TValue GetValueOrDefault(this System.Collections.Generic.IDictionary dictionary, TKey key, TValue defaultValue) + where TKey : notnull + => dictionary.TryGetValue(key, out TValue? value) ? value : defaultValue; + + public static TValue GetValueOrDefault(this System.Collections.Immutable.IImmutableDictionary dictionary, TKey key, TValue defaultValue) + where TKey : notnull + => dictionary.TryGetValue(key, out TValue? value) ? value : defaultValue; + + public static bool Contains(this string s, char c) => s.IndexOf(c) >= 0; + + public static bool StartsWith(this string s, char c) => s.Length > 0 && s[0] == c; + + public static bool EndsWith(this string s, char c) => s.Length > 0 && s[s.Length - 1] == c; +} diff --git a/src/Analyzers/MSTest.SourceGeneration/Helpers/SystemPolyfills.cs b/src/Analyzers/MSTest.SourceGeneration/Helpers/SystemPolyfills.cs index 6a80a1ca13..ec5303962d 100644 --- a/src/Analyzers/MSTest.SourceGeneration/Helpers/SystemPolyfills.cs +++ b/src/Analyzers/MSTest.SourceGeneration/Helpers/SystemPolyfills.cs @@ -1,36 +1,5 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under dual-license. See LICENSE.PLATFORMTOOLS.txt file in the project root for full license information. -#if !NETCOREAPP -#pragma warning disable SA1403 // File may only contain a single namespace -#pragma warning disable SA1642 // Constructor summary documentation should begin with standard text -#pragma warning disable SA1623 // Property summary documentation should match accessors - -using System.ComponentModel; - -namespace System.Runtime.CompilerServices -{ - [EditorBrowsable(EditorBrowsableState.Never)] - internal static class IsExternalInit; -} - -// This was copied from https://github.com/dotnet/coreclr/blob/60f1e6265bd1039f023a82e0643b524d6aaf7845/src/System.Private.CoreLib/shared/System/Diagnostics/CodeAnalysis/NullableAttributes.cs -// and updated to have the scope of the attributes be internal. -namespace System.Diagnostics.CodeAnalysis -{ - /// Specifies that when a method returns , the parameter will not be null even if the corresponding type allows it. - [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] - 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; } - } -} - -#endif +// Polyfills for IsExternalInit and NotNullWhenAttribute are provided by eng/Polyfills.cs. +// This file is kept for reference but no longer defines those types. 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..dbd6a9a032 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 @@ -44,10 +44,6 @@ 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..a278941d93 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,6 @@ - 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..b390f369c4 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 @@ -46,10 +46,6 @@ This package extends Microsoft Testing Platform to provide a crash dump function - - - - 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..7eb4a0e532 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 @@ -5,10 +5,6 @@ Microsoft.Testing.Extensions.Diagnostics - - - - 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..4f2ce83683 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 @@ -28,10 +28,6 @@ This package extends Microsoft Testing Platform to provide Hot Reload support.]] - - - - 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..5048302f7b 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 @@ -27,10 +27,6 @@ - - - - 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..5901d27eb1 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,6 @@ This package provides Open Telemetry for the platform.]]> - - - - - 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..d88978beb0 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 @@ -39,10 +39,6 @@ This package extends Microsoft Testing Platform to provide a retry policy system - - - - 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..76d4457432 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.]]> - @@ -59,8 +58,4 @@ This package provides telemetry for the platform.]]> - - - - diff --git a/src/Platform/Microsoft.Testing.Extensions.TrxReport.Abstractions/GlobalSuppressions.cs b/src/Platform/Microsoft.Testing.Extensions.TrxReport.Abstractions/GlobalSuppressions.cs index c51ba7e88d..69b7059cf8 100644 --- a/src/Platform/Microsoft.Testing.Extensions.TrxReport.Abstractions/GlobalSuppressions.cs +++ b/src/Platform/Microsoft.Testing.Extensions.TrxReport.Abstractions/GlobalSuppressions.cs @@ -4,7 +4,6 @@ // We usually do not want to suppress issues through GlobalSuppressions file but in this case we have to do it because // we are not able to suppress the issue differently. #pragma warning disable IDE0076 -[assembly: SuppressMessage("ApiDesign", "RS0030:Do not use banned APIs", Justification = "Source-generated file that cannot match analyzers requirements", Scope = "member", Target = "~M:Polyfill.CancelAsync(System.Threading.CancellationTokenSource)~System.Threading.Tasks.Task")] [assembly: SuppressMessage("ApiDesign", "RS0030:Do not use banned APIs", Justification = "Source-generated file that cannot match analyzers requirements", Scope = "member", Target = "~M:System.Reflection.NullabilityInfoContext.CheckParameterMetadataType(System.Reflection.ParameterInfo,System.Reflection.NullabilityInfo)")] [assembly: SuppressMessage("ApiDesign", "RS0030:Do not use banned APIs", Justification = "Source-generated file that cannot match analyzers requirements", Scope = "member", Target = "~M:System.Reflection.NullabilityInfoContext.Create(System.Reflection.EventInfo)~System.Reflection.NullabilityInfo")] [assembly: SuppressMessage("ApiDesign", "RS0030:Do not use banned APIs", Justification = "Source-generated file that cannot match analyzers requirements", Scope = "member", Target = "~M:System.Reflection.NullabilityInfoContext.Create(System.Reflection.FieldInfo)~System.Reflection.NullabilityInfo")] 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..45d6175289 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 @@ -15,12 +15,6 @@ - - - - - - diff --git a/src/Platform/Microsoft.Testing.Extensions.TrxReport.Abstractions/PolyfillExtensions.cs b/src/Platform/Microsoft.Testing.Extensions.TrxReport.Abstractions/PolyfillExtensions.cs new file mode 100644 index 0000000000..c0b8aa44a4 --- /dev/null +++ b/src/Platform/Microsoft.Testing.Extensions.TrxReport.Abstractions/PolyfillExtensions.cs @@ -0,0 +1,26 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#if !NET5_0_OR_GREATER + +internal static class TrxReportAbstractionsPolyfillExtensions +{ + public static global::System.Text.StringBuilder AppendJoin(this global::System.Text.StringBuilder sb, string separator, global::System.Collections.Generic.IEnumerable values) + { + bool first = true; + foreach (string value in values) + { + if (!first) + { + sb.Append(separator); + } + + sb.Append(value); + first = false; + } + + return sb; + } +} + +#endif diff --git a/src/Platform/Microsoft.Testing.Extensions.TrxReport/Hashing/EmbeddedAttribute.cs b/src/Platform/Microsoft.Testing.Extensions.TrxReport/Hashing/EmbeddedAttribute.cs index 35fa4519ac..b3c7f40add 100644 --- a/src/Platform/Microsoft.Testing.Extensions.TrxReport/Hashing/EmbeddedAttribute.cs +++ b/src/Platform/Microsoft.Testing.Extensions.TrxReport/Hashing/EmbeddedAttribute.cs @@ -1,9 +1,4 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. -namespace Microsoft.CodeAnalysis; - -[AttributeUsage(AttributeTargets.All)] -internal sealed partial class EmbeddedAttribute : Attribute -{ -} +// EmbeddedAttribute is now provided by eng/Polyfills.cs. 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..80a5bef8fe 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 @@ -63,10 +63,6 @@ This package extends Microsoft Testing Platform to provide TRX test reports.]]> - - - - @@ -74,9 +70,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..f78207c99e 100644 --- a/src/Platform/Microsoft.Testing.Extensions.TrxReport/TrxCompareTool.cs +++ b/src/Platform/Microsoft.Testing.Extensions.TrxReport/TrxCompareTool.cs @@ -180,7 +180,11 @@ 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 + XElement trxTestRun = await Task.FromResult(XElement.Load(stream, LoadOptions.None)).ConfigureAwait(false); +#endif int testResultIndex = 0; foreach (XElement testResult in trxTestRun.Elements(ns + "Results").Elements(ns + "UnitTestResult")) { diff --git a/src/Platform/Microsoft.Testing.Extensions.TrxReport/TrxReportEngine.cs b/src/Platform/Microsoft.Testing.Extensions.TrxReport/TrxReportEngine.cs index 5ea30af31c..74e1302757 100644 --- a/src/Platform/Microsoft.Testing.Extensions.TrxReport/TrxReportEngine.cs +++ b/src/Platform/Microsoft.Testing.Extensions.TrxReport/TrxReportEngine.cs @@ -83,7 +83,9 @@ 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; @@ -97,7 +99,11 @@ public TrxReportEngine(IFileSystem fileSystem, ITestApplicationModuleInfo testAp _artifactsByExtension = artifactsByExtension; _testFrameworkAdapter = testFrameworkAdapter; _testStartTime = testStartTime; +#if NETCOREAPP _cancellationToken = cancellationToken; +#else + _ = cancellationToken; +#endif _exitCode = exitCode; _fileSystem = fileSystem; } @@ -174,7 +180,12 @@ 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); + await Task.CompletedTask.ConfigureAwait(false); +#endif return isFileNameExplicitlyProvidedAndFileExists ? (finalFileName, string.Format(CultureInfo.InvariantCulture, ExtensionResources.TrxFileExistsAndWillBeOverwritten, finalFileName)) : (finalFileName, null); @@ -228,7 +239,12 @@ public async Task AddArtifactsAsync(FileInfo trxFile, Dictionary> artifacts, XElement collectorDataEntries, string runDeploymentRoot) 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 e1022bd0bd..b99991e3c4 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,7 +17,6 @@ - @@ -41,8 +40,4 @@ This package provides a bridge integration for test adapters wanting to target b - - - - 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..59516d0b3d 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,6 @@ - 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..d8ca1f9f98 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,6 @@ - @@ -104,9 +103,6 @@ This package provides MSBuild integration of the platform, its extensions and co - - - diff --git a/src/Platform/Microsoft.Testing.Platform.MSBuild/Tasks/InvokeTestingPlatformTask.cs b/src/Platform/Microsoft.Testing.Platform.MSBuild/Tasks/InvokeTestingPlatformTask.cs index 544781520b..90deea4b64 100644 --- a/src/Platform/Microsoft.Testing.Platform.MSBuild/Tasks/InvokeTestingPlatformTask.cs +++ b/src/Platform/Microsoft.Testing.Platform.MSBuild/Tasks/InvokeTestingPlatformTask.cs @@ -208,7 +208,7 @@ protected override string ToolName } Log.LogMessage(MessageImportance.Low, $"Current process architecture '{_currentProcessArchitecture}'. Requested test architecture '{TestArchitecture.ItemSpec}'"); - PlatformArchitecture targetArchitecture = Enum.Parse(TestArchitecture.ItemSpec, ignoreCase: true); + var targetArchitecture = (PlatformArchitecture)Enum.Parse(typeof(PlatformArchitecture), TestArchitecture.ItemSpec, ignoreCase: true); StringBuilder resolutionLog = new(); DotnetMuxerLocator dotnetMuxerLocator = new(log => resolutionLog.AppendLine(log)); if (dotnetMuxerLocator.TryGetDotnetPathByArchitecture(targetArchitecture, out string? dotnetPath)) @@ -242,7 +242,7 @@ protected override string ToolName } private bool IsCurrentProcessArchitectureCompatible() => - _currentProcessArchitecture == Enum.Parse(TestArchitecture.ItemSpec, ignoreCase: true); + _currentProcessArchitecture == (Architecture)Enum.Parse(typeof(Architecture), TestArchitecture.ItemSpec, ignoreCase: true); private string? TryGetRunCommand() { diff --git a/src/Platform/Microsoft.Testing.Platform/Builder/TestApplication.cs b/src/Platform/Microsoft.Testing.Platform/Builder/TestApplication.cs index b0b5f331e0..88391e8118 100644 --- a/src/Platform/Microsoft.Testing.Platform/Builder/TestApplication.cs +++ b/src/Platform/Microsoft.Testing.Platform/Builder/TestApplication.cs @@ -294,7 +294,11 @@ private static ApplicationLoggingState CreateFileLoggerIfDiagnosticIsEnabled( if (result.TryGetOptionArgumentList(PlatformCommandLineProvider.DiagnosticVerbosityOptionKey, out string[]? verbosity)) { +#if NET5_0_OR_GREATER 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/Helpers/KeyValuePairDeconstruct.cs b/src/Platform/Microsoft.Testing.Platform/Helpers/KeyValuePairDeconstruct.cs new file mode 100644 index 0000000000..88dd5c0c05 --- /dev/null +++ b/src/Platform/Microsoft.Testing.Platform/Helpers/KeyValuePairDeconstruct.cs @@ -0,0 +1,15 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#if !NET5_0_OR_GREATER + +internal static class PolyfillKeyValuePairExtensions +{ + public static void Deconstruct(this System.Collections.Generic.KeyValuePair pair, out TKey key, out TValue value) + { + key = pair.Key; + value = pair.Value; + } +} + +#endif diff --git a/src/Platform/Microsoft.Testing.Platform/Helpers/Sha256Hasher.cs b/src/Platform/Microsoft.Testing.Platform/Helpers/Sha256Hasher.cs index 019ce3a00d..bff08d361b 100644 --- a/src/Platform/Microsoft.Testing.Platform/Helpers/Sha256Hasher.cs +++ b/src/Platform/Microsoft.Testing.Platform/Helpers/Sha256Hasher.cs @@ -15,7 +15,16 @@ internal static class Sha256Hasher public static string HashWithNormalizedCasing(string text) { byte[] bytes = Encoding.UTF8.GetBytes(text.ToUpperInvariant()); +#if NET9_0_OR_GREATER byte[] hash = SHA256.HashData(bytes); return Convert.ToHexStringLower(hash); +#elif NETCOREAPP + byte[] hash = SHA256.HashData(bytes); + return Convert.ToHexString(hash).ToLowerInvariant(); +#else + using var sha256 = SHA256.Create(); + byte[] hash = sha256.ComputeHash(bytes); + return BitConverter.ToString(hash).Replace("-", string.Empty).ToLowerInvariant(); +#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..a1ce8c6ee7 100644 --- a/src/Platform/Microsoft.Testing.Platform/Helpers/System/SystemEnvironment.cs +++ b/src/Platform/Microsoft.Testing.Platform/Helpers/System/SystemEnvironment.cs @@ -12,7 +12,18 @@ internal sealed class SystemEnvironment : IEnvironment public string NewLine => Environment.NewLine; +#if NET5_0_OR_GREATER public int ProcessId => Environment.ProcessId; +#else + public int ProcessId + { + get + { + using var process = Process.GetCurrentProcess(); + return process.Id; + } + } +#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..9336052fcc 100644 --- a/src/Platform/Microsoft.Testing.Platform/Helpers/System/SystemFileSystem.cs +++ b/src/Platform/Microsoft.Testing.Platform/Helpers/System/SystemFileSystem.cs @@ -9,7 +9,19 @@ internal sealed class SystemFileSystem : IFileSystem public string CreateDirectory(string path) => Directory.CreateDirectory(path).FullName; +#if NET5_0_OR_GREATER 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.Exists(destFileName)) + { + File.Delete(destFileName); + } + + File.Move(sourceFileName, destFileName); + } +#endif public IFileStream NewFileStream(string path, FileMode mode) => new SystemFileStream(path, mode); @@ -17,7 +29,11 @@ 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) => Task.FromResult(File.ReadAllText(path)); +#endif public void CopyFile(string sourceFileName, string destFileName, bool overwrite = false) => File.Copy(sourceFileName, destFileName, overwrite); diff --git a/src/Platform/Microsoft.Testing.Platform/Microsoft.Testing.Platform.csproj b/src/Platform/Microsoft.Testing.Platform/Microsoft.Testing.Platform.csproj index 0c69386a00..c46f63bbb3 100644 --- a/src/Platform/Microsoft.Testing.Platform/Microsoft.Testing.Platform.csproj +++ b/src/Platform/Microsoft.Testing.Platform/Microsoft.Testing.Platform.csproj @@ -82,10 +82,6 @@ This package provides the core platform and the .NET implementation of the proto - - - - diff --git a/src/Platform/Microsoft.Testing.Platform/ServerMode/JsonRpc/SerializerUtilities.cs b/src/Platform/Microsoft.Testing.Platform/ServerMode/JsonRpc/SerializerUtilities.cs index 7c16ce0d93..ab042aca3f 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; diff --git a/src/Platform/Microsoft.Testing.Platform/ServerMode/JsonRpc/ServerModePerCallOutputDevice.cs b/src/Platform/Microsoft.Testing.Platform/ServerMode/JsonRpc/ServerModePerCallOutputDevice.cs index a2783246a4..73a21a1d5e 100644 --- a/src/Platform/Microsoft.Testing.Platform/ServerMode/JsonRpc/ServerModePerCallOutputDevice.cs +++ b/src/Platform/Microsoft.Testing.Platform/ServerMode/JsonRpc/ServerModePerCallOutputDevice.cs @@ -44,7 +44,13 @@ internal async Task InitializeAsync(ServerTestHost serverTestHost) await LogAsync(message, serverTestHost.ServiceProvider.GetTestApplicationCancellationTokenSource().CancellationToken).ConfigureAwait(false); } +#if NETCOREAPP _messages.Clear(); +#else + while (_messages.TryTake(out _)) + { + } +#endif } 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..61c4fe3c45 100644 --- a/src/Platform/Microsoft.Testing.Platform/ServerMode/JsonRpc/TcpMessageHandler.cs +++ b/src/Platform/Microsoft.Testing.Platform/ServerMode/JsonRpc/TcpMessageHandler.cs @@ -124,7 +124,12 @@ 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 NET8_0_OR_GREATER await _writer.FlushAsync(cancellationToken).ConfigureAwait(false); +#else + cancellationToken.ThrowIfCancellationRequested(); + 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/TestFramework/TestFramework.Extensions/TestFramework.Extensions.csproj b/src/TestFramework/TestFramework.Extensions/TestFramework.Extensions.csproj index 7bd66d65a3..c7541f6f4f 100644 --- a/src/TestFramework/TestFramework.Extensions/TestFramework.Extensions.csproj +++ b/src/TestFramework/TestFramework.Extensions/TestFramework.Extensions.csproj @@ -56,8 +56,6 @@ - - @@ -81,7 +79,6 @@ - diff --git a/src/TestFramework/TestFramework/Internal/PolyfillExtensions.cs b/src/TestFramework/TestFramework/Internal/PolyfillExtensions.cs new file mode 100644 index 0000000000..bdf2464ea7 --- /dev/null +++ b/src/TestFramework/TestFramework/Internal/PolyfillExtensions.cs @@ -0,0 +1,38 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +// Polyfill extension methods for the TestFramework project which targets +// netstandard2.0, net462, and does not have IVT from Microsoft.Testing.Platform. +#if !NET5_0_OR_GREATER + +internal static class TestFrameworkPolyfillExtensions +{ + public static bool Contains(this string s, char c) => s.IndexOf(c) >= 0; + + public static bool Contains(this string s, string value, System.StringComparison comparisonType) => + s.IndexOf(value, comparisonType) >= 0; + + public static bool StartsWith(this string s, char c) => s.Length > 0 && s[0] == c; + + public static bool EndsWith(this string s, char c) => s.Length > 0 && s[s.Length - 1] == c; + + public static void Deconstruct(this System.Collections.Generic.KeyValuePair pair, out TKey key, out TValue value) + { + key = pair.Key; + value = pair.Value; + } + + public static bool TryAdd(this System.Collections.Generic.Dictionary dictionary, TKey key, TValue value) + where TKey : notnull + { + if (!dictionary.ContainsKey(key)) + { + dictionary.Add(key, value); + return true; + } + + return false; + } +} + +#endif diff --git a/src/TestFramework/TestFramework/Internal/TestDataSourceUtilities.cs b/src/TestFramework/TestFramework/Internal/TestDataSourceUtilities.cs index 7ebca153fd..60a1609a0b 100644 --- a/src/TestFramework/TestFramework/Internal/TestDataSourceUtilities.cs +++ b/src/TestFramework/TestFramework/Internal/TestDataSourceUtilities.cs @@ -29,7 +29,7 @@ internal static class TestDataSourceUtilities CultureInfo.CurrentCulture, FrameworkMessages.DataDrivenResultDisplayName, methodDisplayName, - string.Join(',', displayData.Select(GetHumanizedArguments))); + string.Join(",", displayData.Select(GetHumanizedArguments))); } /// @@ -57,6 +57,6 @@ internal static class TestDataSourceUtilities // We need to box the object here so that we can support value types IEnumerable boxedObjectEnumerable = ((IEnumerable)data).Cast(); IEnumerable elementStrings = boxedObjectEnumerable.Select(GetHumanizedArguments); - return $"[{string.Join(',', elementStrings)}]"; + return $"[{string.Join(",", elementStrings)}]"; } } diff --git a/src/TestFramework/TestFramework/TestFramework.csproj b/src/TestFramework/TestFramework/TestFramework.csproj index 3bb3e7339b..55213c94c4 100644 --- a/src/TestFramework/TestFramework/TestFramework.csproj +++ b/src/TestFramework/TestFramework/TestFramework.csproj @@ -27,10 +27,6 @@ - - - - $(EnableAotAnalyzers) @@ -47,7 +43,6 @@ - diff --git a/test/IntegrationTests/MSTest.Acceptance.IntegrationTests/MSTest.Acceptance.IntegrationTests.csproj b/test/IntegrationTests/MSTest.Acceptance.IntegrationTests/MSTest.Acceptance.IntegrationTests.csproj index add7413e38..785fd9be29 100644 --- a/test/IntegrationTests/MSTest.Acceptance.IntegrationTests/MSTest.Acceptance.IntegrationTests.csproj +++ b/test/IntegrationTests/MSTest.Acceptance.IntegrationTests/MSTest.Acceptance.IntegrationTests.csproj @@ -25,7 +25,6 @@ - diff --git a/test/IntegrationTests/MSTest.IntegrationTests/MSTest.IntegrationTests.csproj b/test/IntegrationTests/MSTest.IntegrationTests/MSTest.IntegrationTests.csproj index 5347699911..bca215eca9 100644 --- a/test/IntegrationTests/MSTest.IntegrationTests/MSTest.IntegrationTests.csproj +++ b/test/IntegrationTests/MSTest.IntegrationTests/MSTest.IntegrationTests.csproj @@ -27,8 +27,4 @@ - - - - diff --git a/test/IntegrationTests/MSTest.IntegrationTests/Utilities/TestCaseFilterFactory.cs b/test/IntegrationTests/MSTest.IntegrationTests/Utilities/TestCaseFilterFactory.cs index 3bccf96779..42781b7aa2 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 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..b346049c4c 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,7 +18,6 @@ - diff --git a/test/UnitTests/MSTest.Analyzers.UnitTests/MSTest.Analyzers.UnitTests.csproj b/test/UnitTests/MSTest.Analyzers.UnitTests/MSTest.Analyzers.UnitTests.csproj index 62237a43c6..e8eacb0909 100644 --- a/test/UnitTests/MSTest.Analyzers.UnitTests/MSTest.Analyzers.UnitTests.csproj +++ b/test/UnitTests/MSTest.Analyzers.UnitTests/MSTest.Analyzers.UnitTests.csproj @@ -31,8 +31,6 @@ - - diff --git a/test/UnitTests/MSTest.SourceGeneration.UnitTests/Generators/TestNodesGeneratorTests.cs b/test/UnitTests/MSTest.SourceGeneration.UnitTests/Generators/TestNodesGeneratorTests.cs index 6ceb1a9ed4..36b1880807 100644 --- a/test/UnitTests/MSTest.SourceGeneration.UnitTests/Generators/TestNodesGeneratorTests.cs +++ b/test/UnitTests/MSTest.SourceGeneration.UnitTests/Generators/TestNodesGeneratorTests.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. +extern alias SourceGen; + using AwesomeAssertions; using Microsoft.CodeAnalysis; @@ -8,6 +10,8 @@ using Microsoft.Testing.Framework.SourceGeneration.UnitTests.Helpers; using Microsoft.Testing.Framework.SourceGeneration.UnitTests.TestUtilities; +using TestNodesGenerator = SourceGen::Microsoft.Testing.Framework.SourceGeneration.TestNodesGenerator; + namespace Microsoft.Testing.Framework.SourceGeneration.UnitTests.Generators; [TestClass] diff --git a/test/UnitTests/MSTest.SourceGeneration.UnitTests/Helpers/ConstantsTests.cs b/test/UnitTests/MSTest.SourceGeneration.UnitTests/Helpers/ConstantsTests.cs index 1944f5b664..45422e30dc 100644 --- a/test/UnitTests/MSTest.SourceGeneration.UnitTests/Helpers/ConstantsTests.cs +++ b/test/UnitTests/MSTest.SourceGeneration.UnitTests/Helpers/ConstantsTests.cs @@ -1,8 +1,12 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. +extern alias SourceGen; + using AwesomeAssertions; +using Constants = SourceGen::Microsoft.Testing.Framework.SourceGeneration.Constants; + namespace Microsoft.Testing.Framework.SourceGeneration.UnitTests; [TestClass] diff --git a/test/UnitTests/MSTest.SourceGeneration.UnitTests/MSTest.SourceGeneration.UnitTests.csproj b/test/UnitTests/MSTest.SourceGeneration.UnitTests/MSTest.SourceGeneration.UnitTests.csproj index 014e756668..d762c2661e 100644 --- a/test/UnitTests/MSTest.SourceGeneration.UnitTests/MSTest.SourceGeneration.UnitTests.csproj +++ b/test/UnitTests/MSTest.SourceGeneration.UnitTests/MSTest.SourceGeneration.UnitTests.csproj @@ -8,6 +8,13 @@ Exe + + + + + + @@ -29,6 +36,7 @@ Analyzer true + SourceGen diff --git a/test/UnitTests/MSTest.SourceGeneration.UnitTests/ObjectModels/InlineTestMethodArgumentsInfoTests.cs b/test/UnitTests/MSTest.SourceGeneration.UnitTests/ObjectModels/InlineTestMethodArgumentsInfoTests.cs index 9c34e23745..f3a23712ea 100644 --- a/test/UnitTests/MSTest.SourceGeneration.UnitTests/ObjectModels/InlineTestMethodArgumentsInfoTests.cs +++ b/test/UnitTests/MSTest.SourceGeneration.UnitTests/ObjectModels/InlineTestMethodArgumentsInfoTests.cs @@ -1,7 +1,9 @@ // 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.Framework.SourceGeneration.ObjectModels; +extern alias SourceGen; + +using SourceGen::Microsoft.Testing.Framework.SourceGeneration.ObjectModels; namespace Microsoft.Testing.Framework.SourceGeneration.UnitTests; diff --git a/test/UnitTests/MSTest.SourceGeneration.UnitTests/TestUtilities/GeneratorTester.cs b/test/UnitTests/MSTest.SourceGeneration.UnitTests/TestUtilities/GeneratorTester.cs index 87f1705900..0d7bdbae60 100644 --- a/test/UnitTests/MSTest.SourceGeneration.UnitTests/TestUtilities/GeneratorTester.cs +++ b/test/UnitTests/MSTest.SourceGeneration.UnitTests/TestUtilities/GeneratorTester.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. +extern alias SourceGen; + using System.Collections.Immutable; using AwesomeAssertions; @@ -13,6 +15,8 @@ using Microsoft.Testing.Extensions.TrxReport.Abstractions; using Microsoft.Testing.Platform.Extensions.Messages; +using TestNodesGenerator = SourceGen::Microsoft.Testing.Framework.SourceGeneration.TestNodesGenerator; + namespace Microsoft.Testing.Framework.SourceGeneration.UnitTests.TestUtilities; internal sealed class GeneratorTester diff --git a/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Discovery/TypeEnumeratorTests.MockedMethodInfoWithExtraAttributes.cs b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Discovery/TypeEnumeratorTests.MockedMethodInfoWithExtraAttributes.cs index a351eada6d..9dce9a4179 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 diff --git a/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/MSTestAdapter.PlatformServices.UnitTests.csproj b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/MSTestAdapter.PlatformServices.UnitTests.csproj index 5cf1911159..eacb41952d 100644 --- a/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/MSTestAdapter.PlatformServices.UnitTests.csproj +++ b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/MSTestAdapter.PlatformServices.UnitTests.csproj @@ -32,7 +32,6 @@ - diff --git a/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/ObjectModel/UnitTestElementTests.cs b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/ObjectModel/UnitTestElementTests.cs index c71f23c72b..b0fbc6612f 100644 --- a/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/ObjectModel/UnitTestElementTests.cs +++ b/test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/ObjectModel/UnitTestElementTests.cs @@ -158,7 +158,7 @@ public void ToTestCaseShouldSetDeploymentItemPropertyIfPresent() public void ToTestCase_WhenStrategyIsData_DoesNotUseDefaultTestCaseId() { #pragma warning disable CA2263 // Prefer generic overload when type is known - foreach (DynamicDataType dataType in Enum.GetValues()) + foreach (DynamicDataType dataType in Enum.GetValues(typeof(DynamicDataType))) { var testCase = new UnitTestElement(new("MyMethod", "MyProduct.MyNamespace.MyClass", "MyAssembly", null) { diff --git a/test/UnitTests/MSTestAdapter.UnitTests/MSTestAdapter.UnitTests.csproj b/test/UnitTests/MSTestAdapter.UnitTests/MSTestAdapter.UnitTests.csproj index 6ca3cab48e..430e00aca3 100644 --- a/test/UnitTests/MSTestAdapter.UnitTests/MSTestAdapter.UnitTests.csproj +++ b/test/UnitTests/MSTestAdapter.UnitTests/MSTestAdapter.UnitTests.csproj @@ -31,7 +31,6 @@ - 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..c9d3c403b3 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,6 @@ - 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..d91be2a25e 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,6 @@ - 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..bbe88bba2a 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,16 +34,12 @@ - - - - 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..e5266ccc69 100644 --- a/test/UnitTests/TestFramework.UnitTests/TestFramework.UnitTests.csproj +++ b/test/UnitTests/TestFramework.UnitTests/TestFramework.UnitTests.csproj @@ -24,7 +24,6 @@ - diff --git a/test/Utilities/Automation.CLI/Automation.CLI.csproj b/test/Utilities/Automation.CLI/Automation.CLI.csproj index cbb4fe349f..85328da591 100644 --- a/test/Utilities/Automation.CLI/Automation.CLI.csproj +++ b/test/Utilities/Automation.CLI/Automation.CLI.csproj @@ -7,7 +7,6 @@ - diff --git a/test/Utilities/Microsoft.Testing.TestInfrastructure/Microsoft.Testing.TestInfrastructure.csproj b/test/Utilities/Microsoft.Testing.TestInfrastructure/Microsoft.Testing.TestInfrastructure.csproj index 73bb77b1b6..497f5dd6ff 100644 --- a/test/Utilities/Microsoft.Testing.TestInfrastructure/Microsoft.Testing.TestInfrastructure.csproj +++ b/test/Utilities/Microsoft.Testing.TestInfrastructure/Microsoft.Testing.TestInfrastructure.csproj @@ -9,7 +9,6 @@ - @@ -17,8 +16,4 @@ - - - - diff --git a/test/Utilities/TestFramework.ForTestingMSTest/TestFramework.ForTestingMSTest.csproj b/test/Utilities/TestFramework.ForTestingMSTest/TestFramework.ForTestingMSTest.csproj index 23bdfc6d46..49ac091178 100644 --- a/test/Utilities/TestFramework.ForTestingMSTest/TestFramework.ForTestingMSTest.csproj +++ b/test/Utilities/TestFramework.ForTestingMSTest/TestFramework.ForTestingMSTest.csproj @@ -15,8 +15,4 @@ - - - -