Conversation
| @@ -37,8 +37,19 @@ private Assert() | |||
| [DoesNotReturn] | |||
| [StackTraceHidden] | |||
| internal static void ThrowAssertFailed(string assertionName, string? message) | |||
There was a problem hiding this comment.
Given this PR and #2033, I think it'd be good to expose a "ReportFailure" method that could be used by devs extending MSTest assertions so they would benefits from the various features (launch debugger, soft assertions....). I am not doing it here because we can decide not to go with it for now.
| if (scope is not null) | ||
| { | ||
| scope.AddError(assertionFailedException); | ||
| #pragma warning disable CS8763 // A method marked [DoesNotReturn] should not return. |
There was a problem hiding this comment.
@Youssef1313 I don't know what we prefer but it feels better for me to say we continue to help compiler with the default behavior and we know we may have some FPs when code is used under assertion scope. It would otherwise be a breaking change for many people if we had to update all assertion APIs to no longer respect some of these DoesNotReturn compilation indication.
| /// // AssertFailedException is thrown here with all collected failures. | ||
| /// </code> | ||
| /// </example> | ||
| public static IDisposable Scope() => new AssertScope(); |
There was a problem hiding this comment.
Public API is quite limited, do we want to make it experimental still?
There was a problem hiding this comment.
Fine for me (and probably best) to be experimental, but curious what exactly do you think is limited.
|
|
||
| internal AssertScope() | ||
| { | ||
| _previousScope = CurrentScope.Value; |
There was a problem hiding this comment.
Do we want to allow nested scopes? I don't personally see a good use case.
| /// Adds an assertion failure message to the current scope. | ||
| /// </summary> | ||
| /// <param name="error">The assertion failure message.</param> | ||
| internal void AddError(AssertFailedException error) => _errors.Add(error); |
There was a problem hiding this comment.
Consider throwing ObjectDisposedException here if _disposed is true.
| _disposed = true; | ||
| CurrentScope.Value = _previousScope; | ||
|
|
||
| if (_errors.Count > 0) |
There was a problem hiding this comment.
Can we special case when _errors.Count == 1 so we don't create AggregateException?
| { | ||
| private static readonly AsyncLocal<AssertScope?> CurrentScope = new(); | ||
|
|
||
| private readonly List<AssertFailedException> _errors = []; |
There was a problem hiding this comment.
Should we use a thread-safe collection here?
For example, in theory user can create a scope, then create X threads and starts them, then each thread does some piece of work and asserts some result. Then waits for all those threads to finish before disposing the scope.
Fixes #571