Skip to content
261 changes: 261 additions & 0 deletions docs/RFCs/011-Soft-Assertions-Nullability-Design.md

Large diffs are not rendered by default.

12 changes: 6 additions & 6 deletions src/TestFramework/TestFramework/Assertions/Assert.AreEqual.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System.ComponentModel;
Expand Down Expand Up @@ -662,7 +662,7 @@ private static void ThrowAssertAreEqualFailed(object? expected, object? actual,
userMessage,
ReplaceNulls(expected),
ReplaceNulls(actual));
ThrowAssertFailed("Assert.AreEqual", finalMessage);
ReportAssertFailed("Assert.AreEqual", finalMessage);
}

[DoesNotReturn]
Expand All @@ -676,7 +676,7 @@ private static void ThrowAssertAreEqualFailed<T>(T expected, T actual, T delta,
expected.ToString(CultureInfo.CurrentCulture.NumberFormat),
actual.ToString(CultureInfo.CurrentCulture.NumberFormat),
delta.ToString(CultureInfo.CurrentCulture.NumberFormat));
ThrowAssertFailed("Assert.AreEqual", finalMessage);
ReportAssertFailed("Assert.AreEqual", finalMessage);
}

[DoesNotReturn]
Expand All @@ -700,7 +700,7 @@ private static void ThrowAssertAreEqualFailed(string? expected, string? actual,
finalMessage = FormatStringComparisonMessage(expected, actual, userMessage);
}

ThrowAssertFailed("Assert.AreEqual", finalMessage);
ReportAssertFailed("Assert.AreEqual", finalMessage);
}

/// <summary>
Expand Down Expand Up @@ -1229,7 +1229,7 @@ private static void ThrowAssertAreNotEqualFailed<T>(T notExpected, T actual, T d
notExpected.ToString(CultureInfo.CurrentCulture.NumberFormat),
actual.ToString(CultureInfo.CurrentCulture.NumberFormat),
delta.ToString(CultureInfo.CurrentCulture.NumberFormat));
ThrowAssertFailed("Assert.AreNotEqual", finalMessage);
ReportAssertFailed("Assert.AreNotEqual", finalMessage);
}

/// <summary>
Expand Down Expand Up @@ -1437,7 +1437,7 @@ private static void ThrowAssertAreNotEqualFailed(object? notExpected, object? ac
userMessage,
ReplaceNulls(notExpected),
ReplaceNulls(actual));
ThrowAssertFailed("Assert.AreNotEqual", finalMessage);
ReportAssertFailed("Assert.AreNotEqual", finalMessage);
}
}

Expand Down
6 changes: 3 additions & 3 deletions src/TestFramework/TestFramework/Assertions/Assert.AreSame.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System.ComponentModel;
Expand Down Expand Up @@ -196,7 +196,7 @@ private static void ThrowAssertAreSameFailed<T>(T? expected, T? actual, string u
userMessage);
}

ThrowAssertFailed("Assert.AreSame", finalMessage);
ReportAssertFailed("Assert.AreSame", finalMessage);
}

/// <inheritdoc cref="AreNotSame{T}(T, T, string?, string, string)" />
Expand Down Expand Up @@ -249,5 +249,5 @@ private static bool IsAreNotSameFailing<T>(T? notExpected, T? actual)

[DoesNotReturn]
private static void ThrowAssertAreNotSameFailed(string userMessage)
=> ThrowAssertFailed("Assert.AreNotSame", userMessage);
=> ReportAssertFailed("Assert.AreNotSame", userMessage);
}
18 changes: 9 additions & 9 deletions src/TestFramework/TestFramework/Assertions/Assert.Contains.cs
Original file line number Diff line number Diff line change
Expand Up @@ -478,7 +478,7 @@ public static void Contains(string substring, string value, StringComparison com
{
string userMessage = BuildUserMessageForSubstringExpressionAndValueExpression(message, substringExpression, valueExpression);
string finalMessage = string.Format(CultureInfo.CurrentCulture, FrameworkMessages.ContainsFail, value, substring, userMessage);
ThrowAssertFailed("Assert.Contains", finalMessage);
ReportAssertFailed("Assert.Contains", finalMessage);
}
}

Expand Down Expand Up @@ -717,7 +717,7 @@ public static void DoesNotContain(string substring, string value, StringComparis
{
string userMessage = BuildUserMessageForSubstringExpressionAndValueExpression(message, substringExpression, valueExpression);
string finalMessage = string.Format(CultureInfo.CurrentCulture, FrameworkMessages.DoesNotContainFail, value, substring, userMessage);
ThrowAssertFailed("Assert.DoesNotContain", finalMessage);
ReportAssertFailed("Assert.DoesNotContain", finalMessage);
}
}

Expand Down Expand Up @@ -758,7 +758,7 @@ public static void IsInRange<T>(T minValue, T maxValue, T value, string? message
{
string userMessage = BuildUserMessageForMinValueExpressionAndMaxValueExpressionAndValueExpression(message, minValueExpression, maxValueExpression, valueExpression);
string finalMessage = string.Format(CultureInfo.CurrentCulture, FrameworkMessages.IsInRangeFail, value, minValue, maxValue, userMessage);
ThrowAssertFailed("IsInRange", finalMessage);
ReportAssertFailed("IsInRange", finalMessage);
}
}

Expand All @@ -772,7 +772,7 @@ private static void ThrowAssertSingleMatchFailed(int actualCount, string userMes
FrameworkMessages.ContainsSingleMatchFailMsg,
userMessage,
actualCount);
ThrowAssertFailed("Assert.ContainsSingle", finalMessage);
ReportAssertFailed("Assert.ContainsSingle", finalMessage);
}

[DoesNotReturn]
Expand All @@ -783,7 +783,7 @@ private static void ThrowAssertContainsSingleFailed(int actualCount, string user
FrameworkMessages.ContainsSingleFailMsg,
userMessage,
actualCount);
ThrowAssertFailed("Assert.ContainsSingle", finalMessage);
ReportAssertFailed("Assert.ContainsSingle", finalMessage);
}

[DoesNotReturn]
Expand All @@ -793,7 +793,7 @@ private static void ThrowAssertContainsItemFailed(string userMessage)
CultureInfo.CurrentCulture,
FrameworkMessages.ContainsItemFailMsg,
userMessage);
ThrowAssertFailed("Assert.Contains", finalMessage);
ReportAssertFailed("Assert.Contains", finalMessage);
}

[DoesNotReturn]
Expand All @@ -803,7 +803,7 @@ private static void ThrowAssertContainsPredicateFailed(string userMessage)
CultureInfo.CurrentCulture,
FrameworkMessages.ContainsPredicateFailMsg,
userMessage);
ThrowAssertFailed("Assert.Contains", finalMessage);
ReportAssertFailed("Assert.Contains", finalMessage);
}

[DoesNotReturn]
Expand All @@ -813,7 +813,7 @@ private static void ThrowAssertDoesNotContainItemFailed(string userMessage)
CultureInfo.CurrentCulture,
FrameworkMessages.DoesNotContainItemFailMsg,
userMessage);
ThrowAssertFailed("Assert.DoesNotContain", finalMessage);
ReportAssertFailed("Assert.DoesNotContain", finalMessage);
}

[DoesNotReturn]
Expand All @@ -823,6 +823,6 @@ private static void ThrowAssertDoesNotContainPredicateFailed(string userMessage)
CultureInfo.CurrentCulture,
FrameworkMessages.DoesNotContainPredicateFailMsg,
userMessage);
ThrowAssertFailed("Assert.DoesNotContain", finalMessage);
ReportAssertFailed("Assert.DoesNotContain", finalMessage);
}
}
6 changes: 3 additions & 3 deletions src/TestFramework/TestFramework/Assertions/Assert.Count.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System.ComponentModel;
Expand Down Expand Up @@ -342,7 +342,7 @@
userMessage,
expectedCount,
actualCount);
ThrowAssertFailed($"Assert.{assertionName}", finalMessage);
ReportAssertFailed($"Assert.{assertionName}", finalMessage);

Check failure on line 345 in src/TestFramework/TestFramework/Assertions/Assert.Count.cs

View check run for this annotation

Azure Pipelines / microsoft.testfx (Build Windows Release)

src/TestFramework/TestFramework/Assertions/Assert.Count.cs#L345

src/TestFramework/TestFramework/Assertions/Assert.Count.cs(345,1): error : [GenerateCSharpEntryPointAndVerifyTheCacheUsage ("net10.0",Release,build)] Assert.HasCount failed. Expected collection of size 1. Actual: 0. 'collection' expression: 'generateTestingPlatformEntryPointTargets'. Expected exactly one _GenerateTestingPlatformEntryPoint target
}

[DoesNotReturn]
Expand All @@ -352,6 +352,6 @@
CultureInfo.CurrentCulture,
FrameworkMessages.IsNotEmptyFailMsg,
userMessage);
ThrowAssertFailed("Assert.IsNotEmpty", finalMessage);
ReportAssertFailed("Assert.IsNotEmpty", finalMessage);
}
}
6 changes: 3 additions & 3 deletions src/TestFramework/TestFramework/Assertions/Assert.EndsWith.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// 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.VisualStudio.TestTools.UnitTesting;
Expand Down Expand Up @@ -78,7 +78,7 @@ public static void EndsWith([NotNull] string? expectedSuffix, [NotNull] string?
{
string userMessage = BuildUserMessageForExpectedSuffixExpressionAndValueExpression(message, expectedSuffixExpression, valueExpression);
string finalMessage = string.Format(CultureInfo.CurrentCulture, FrameworkMessages.EndsWithFail, value, expectedSuffix, userMessage);
ThrowAssertFailed("Assert.EndsWith", finalMessage);
ReportAssertFailed("Assert.EndsWith", finalMessage);
}
}

Expand Down Expand Up @@ -152,7 +152,7 @@ public static void DoesNotEndWith([NotNull] string? notExpectedSuffix, [NotNull]
{
string userMessage = BuildUserMessageForNotExpectedSuffixExpressionAndValueExpression(message, notExpectedSuffixExpression, valueExpression);
string finalMessage = string.Format(CultureInfo.CurrentCulture, FrameworkMessages.DoesNotEndWithFail, value, notExpectedSuffix, userMessage);
ThrowAssertFailed("Assert.DoesNotEndWith", finalMessage);
ReportAssertFailed("Assert.DoesNotEndWith", finalMessage);
}
}
}
2 changes: 1 addition & 1 deletion src/TestFramework/TestFramework/Assertions/Assert.Fail.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,5 @@ public sealed partial class Assert
/// </exception>
[DoesNotReturn]
public static void Fail(string message = "")
=> ThrowAssertFailed("Assert.Fail", BuildUserMessage(message));
=> ReportAssertFailed("Assert.Fail", BuildUserMessage(message), forceThrow: true);
}
14 changes: 7 additions & 7 deletions src/TestFramework/TestFramework/Assertions/Assert.IComparable.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// 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.VisualStudio.TestTools.UnitTesting;
Expand Down Expand Up @@ -307,7 +307,7 @@ private static void ThrowAssertIsGreaterThanFailed<T>(T lowerBound, T value, str
userMessage,
ReplaceNulls(lowerBound),
ReplaceNulls(value));
ThrowAssertFailed("Assert.IsGreaterThan", finalMessage);
ReportAssertFailed("Assert.IsGreaterThan", finalMessage);
}

[DoesNotReturn]
Expand All @@ -319,7 +319,7 @@ private static void ThrowAssertIsGreaterThanOrEqualToFailed<T>(T lowerBound, T v
userMessage,
ReplaceNulls(lowerBound),
ReplaceNulls(value));
ThrowAssertFailed("Assert.IsGreaterThanOrEqualTo", finalMessage);
ReportAssertFailed("Assert.IsGreaterThanOrEqualTo", finalMessage);
}

[DoesNotReturn]
Expand All @@ -331,7 +331,7 @@ private static void ThrowAssertIsLessThanFailed<T>(T upperBound, T value, string
userMessage,
ReplaceNulls(upperBound),
ReplaceNulls(value));
ThrowAssertFailed("Assert.IsLessThan", finalMessage);
ReportAssertFailed("Assert.IsLessThan", finalMessage);
}

[DoesNotReturn]
Expand All @@ -343,7 +343,7 @@ private static void ThrowAssertIsLessThanOrEqualToFailed<T>(T upperBound, T valu
userMessage,
ReplaceNulls(upperBound),
ReplaceNulls(value));
ThrowAssertFailed("Assert.IsLessThanOrEqualTo", finalMessage);
ReportAssertFailed("Assert.IsLessThanOrEqualTo", finalMessage);
}

[DoesNotReturn]
Expand All @@ -354,7 +354,7 @@ private static void ThrowAssertIsPositiveFailed<T>(T value, string userMessage)
FrameworkMessages.IsPositiveFailMsg,
userMessage,
ReplaceNulls(value));
ThrowAssertFailed("Assert.IsPositive", finalMessage);
ReportAssertFailed("Assert.IsPositive", finalMessage);
}

[DoesNotReturn]
Expand All @@ -365,6 +365,6 @@ private static void ThrowAssertIsNegativeFailed<T>(T value, string userMessage)
FrameworkMessages.IsNegativeFailMsg,
userMessage,
ReplaceNulls(value));
ThrowAssertFailed("Assert.IsNegative", finalMessage);
ReportAssertFailed("Assert.IsNegative", finalMessage);
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// 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.VisualStudio.TestTools.UnitTesting;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,7 @@ public static void IsExactInstanceOfType([NotNull] object? value, [NotNull] Type
#pragma warning disable IDE0060 // Remove unused parameter - https://github.com/dotnet/roslyn/issues/76578
public static void IsExactInstanceOfType([NotNull] object? value, [NotNull] Type? expectedType, [InterpolatedStringHandlerArgument(nameof(value), nameof(expectedType))] ref AssertIsExactInstanceOfTypeInterpolatedStringHandler message, [CallerArgumentExpression(nameof(value))] string valueExpression = "")
#pragma warning restore IDE0060 // Remove unused parameter
#pragma warning disable CS8777 // Parameter must have a non-null value when exiting. - Not sure how to express the semantics to the compiler, but the implementation guarantees that.
#pragma warning disable CS8777 // Parameter must have a non-null value when exiting. - Deliberately keeping [NotNull] annotation while using soft assertions. Within an AssertScope, the postcondition is not enforced (same as all other assertion postconditions in scoped mode).
=> message.ComputeAssertion(valueExpression);
#pragma warning restore CS8777 // Parameter must have a non-null value when exiting.

Expand All @@ -318,7 +318,7 @@ public static T IsExactInstanceOfType<T>([NotNull] object? value, string? messag
#pragma warning disable IDE0060 // Remove unused parameter - https://github.com/dotnet/roslyn/issues/76578
public static T IsExactInstanceOfType<T>([NotNull] object? value, [InterpolatedStringHandlerArgument(nameof(value))] ref AssertGenericIsExactInstanceOfTypeInterpolatedStringHandler<T> message, [CallerArgumentExpression(nameof(value))] string valueExpression = "")
#pragma warning restore IDE0060 // Remove unused parameter
#pragma warning disable CS8777 // Parameter must have a non-null value when exiting. - Not sure how to express the semantics to the compiler, but the implementation guarantees that.
#pragma warning disable CS8777 // Parameter must have a non-null value when exiting. - Deliberately keeping [NotNull] annotation while using soft assertions. Within an AssertScope, the postcondition is not enforced (same as all other assertion postconditions in scoped mode).
{
message.ComputeAssertion(valueExpression);
return (T)value!;
Expand All @@ -342,7 +342,7 @@ private static void ThrowAssertIsExactInstanceOfTypeFailed(object? value, Type?
value.GetType().ToString());
}

ThrowAssertFailed("Assert.IsExactInstanceOfType", finalMessage);
ReportAssertFailed("Assert.IsExactInstanceOfType", finalMessage);
}

/// <summary>
Expand Down Expand Up @@ -418,6 +418,6 @@ private static void ThrowAssertIsNotExactInstanceOfTypeFailed(object? value, Typ
value!.GetType().ToString());
}

ThrowAssertFailed("Assert.IsNotExactInstanceOfType", finalMessage);
ReportAssertFailed("Assert.IsNotExactInstanceOfType", finalMessage);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -300,7 +300,7 @@ public static void IsInstanceOfType([NotNull] object? value, [NotNull] Type? exp
#pragma warning disable IDE0060 // Remove unused parameter - https://github.com/dotnet/roslyn/issues/76578
public static void IsInstanceOfType([NotNull] object? value, [NotNull] Type? expectedType, [InterpolatedStringHandlerArgument(nameof(value), nameof(expectedType))] ref AssertIsInstanceOfTypeInterpolatedStringHandler message, [CallerArgumentExpression(nameof(value))] string valueExpression = "")
#pragma warning restore IDE0060 // Remove unused parameter
#pragma warning disable CS8777 // Parameter must have a non-null value when exiting. - Not sure how to express the semantics to the compiler, but the implementation guarantees that.
#pragma warning disable CS8777 // Parameter must have a non-null value when exiting. - Deliberately keeping [NotNull] annotation while using soft assertions. Within an AssertScope, the postcondition is not enforced (same as all other assertion postconditions in scoped mode).
=> message.ComputeAssertion(valueExpression);
#pragma warning restore CS8777 // Parameter must have a non-null value when exiting.

Expand All @@ -320,7 +320,7 @@ public static T IsInstanceOfType<T>([NotNull] object? value, string? message = "
#pragma warning disable IDE0060 // Remove unused parameter - https://github.com/dotnet/roslyn/issues/76578
public static T IsInstanceOfType<T>([NotNull] object? value, [InterpolatedStringHandlerArgument(nameof(value))] ref AssertGenericIsInstanceOfTypeInterpolatedStringHandler<T> message, [CallerArgumentExpression(nameof(value))] string valueExpression = "")
#pragma warning restore IDE0060 // Remove unused parameter
#pragma warning disable CS8777 // Parameter must have a non-null value when exiting. - Not sure how to express the semantics to the compiler, but the implementation guarantees that.
#pragma warning disable CS8777 // Parameter must have a non-null value when exiting. - Deliberately keeping [NotNull] annotation while using soft assertions. Within an AssertScope, the postcondition is not enforced (same as all other assertion postconditions in scoped mode).
{
message.ComputeAssertion(valueExpression);
return (T)value!;
Expand All @@ -344,7 +344,7 @@ private static void ThrowAssertIsInstanceOfTypeFailed(object? value, Type? expec
value.GetType().ToString());
}

ThrowAssertFailed("Assert.IsInstanceOfType", finalMessage);
ReportAssertFailed("Assert.IsInstanceOfType", finalMessage);
}

/// <summary>
Expand Down Expand Up @@ -422,6 +422,6 @@ private static void ThrowAssertIsNotInstanceOfTypeFailed(object? value, Type? wr
value!.GetType().ToString());
}

ThrowAssertFailed("Assert.IsNotInstanceOfType", finalMessage);
ReportAssertFailed("Assert.IsNotInstanceOfType", finalMessage);
}
}
6 changes: 3 additions & 3 deletions src/TestFramework/TestFramework/Assertions/Assert.IsNull.cs
Original file line number Diff line number Diff line change
Expand Up @@ -159,13 +159,13 @@ public static void IsNull(object? value, string? message = "", [CallerArgumentEx
private static bool IsNullFailing(object? value) => value is not null;

private static void ThrowAssertIsNullFailed(string? message)
=> ThrowAssertFailed("Assert.IsNull", message);
=> ReportAssertFailed("Assert.IsNull", message);

/// <inheritdoc cref="IsNull(object?, string, string)" />
#pragma warning disable IDE0060 // Remove unused parameter - https://github.com/dotnet/roslyn/issues/76578
public static void IsNotNull([NotNull] object? value, [InterpolatedStringHandlerArgument(nameof(value))] ref AssertIsNotNullInterpolatedStringHandler message, [CallerArgumentExpression(nameof(value))] string valueExpression = "")
#pragma warning restore IDE0060 // Remove unused parameter
#pragma warning disable CS8777 // Parameter must have a non-null value when exiting. - Not sure how to express the semantics to the compiler, but the implementation guarantees that.
#pragma warning disable CS8777 // Parameter must have a non-null value when exiting. - Deliberately keeping [NotNull] annotation while using soft assertions. Within an AssertScope, the postcondition is not enforced (same as all other assertion postconditions in scoped mode).
=> message.ComputeAssertion(valueExpression);
#pragma warning restore CS8777 // Parameter must have a non-null value when exiting.

Expand Down Expand Up @@ -199,5 +199,5 @@ public static void IsNotNull([NotNull] object? value, string? message = "", [Cal

[DoesNotReturn]
private static void ThrowAssertIsNotNullFailed(string? message)
=> ThrowAssertFailed("Assert.IsNotNull", message);
=> ReportAssertFailed("Assert.IsNotNull", message);
}
Loading
Loading