Skip to content

Commit

Permalink
Fix constructors of AssertionScope (#1119)
Browse files Browse the repository at this point in the history
Fix constructors of AssertionScope
  • Loading branch information
jnyrup authored Aug 20, 2019
2 parents d55545a + 07d0882 commit d5ec77f
Show file tree
Hide file tree
Showing 2 changed files with 99 additions and 9 deletions.
28 changes: 19 additions & 9 deletions Src/FluentAssertions/Execution/AssertionScope.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,25 +40,26 @@ public class AssertionScope : IAssertionScope
#endregion

/// <summary>
/// Starts a new scope based on the given assertion strategy.
/// Starts a new scope based on the given assertion strategy and parent assertion scope
/// </summary>
/// <param name="assertionStrategy">The assertion strategy for this scope.</param>
/// <param name="parent">The parent assertion scope for this scope.</param>
/// <exception cref="ArgumentNullException">Thrown when trying to use a null strategy.</exception>
public AssertionScope(IAssertionStrategy assertionStrategy)
internal AssertionScope(IAssertionStrategy assertionStrategy, AssertionScope parent)
{
this.assertionStrategy = assertionStrategy
?? throw new ArgumentNullException(nameof(assertionStrategy));
parent = null;
this.parent = parent;
}

/// <summary>
/// Starts an unnamed scope within which multiple assertions can be executed
/// and which will not throw until the scope is disposed.
/// Starts a new scope based on the given assertion strategy.
/// </summary>
public AssertionScope()
: this(new CollectingAssertionStrategy())
/// <param name="assertionStrategy">The assertion strategy for this scope.</param>
/// <exception cref="ArgumentNullException">Thrown when trying to use a null strategy.</exception>
public AssertionScope(IAssertionStrategy assertionStrategy)
: this(assertionStrategy, GetCurrentAssertionScope())
{
parent = GetCurrentAssertionScope();
SetCurrentAssertionScope(this);

if (parent != null)
Expand All @@ -68,6 +69,15 @@ public AssertionScope()
}
}

/// <summary>
/// Starts an unnamed scope within which multiple assertions can be executed
/// and which will not throw until the scope is disposed.
/// </summary>
public AssertionScope()
: this(new CollectingAssertionStrategy())
{
}

/// <summary>
/// Starts a named scope within which multiple assertions can be executed and which will not throw until the scope is disposed.
/// </summary>
Expand All @@ -89,7 +99,7 @@ public AssertionScope(string context)
public static AssertionScope Current
{
#pragma warning disable CA2000 // AssertionScope should not be disposed here
get => GetCurrentAssertionScope() ?? new AssertionScope(new DefaultAssertionStrategy());
get => GetCurrentAssertionScope() ?? new AssertionScope(new DefaultAssertionStrategy(), parent: null);
#pragma warning restore CA2000
private set => SetCurrentAssertionScope(value);
}
Expand Down
80 changes: 80 additions & 0 deletions Tests/Shared.Specs/AssertionScopeSpecs.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
Expand Down Expand Up @@ -766,6 +768,84 @@ public void When_custom_strategy_is_null_it_should_throw()
.Which.ParamName.Should().Be("assertionStrategy");
}

[Fact]
public void When_using_a_custom_strategy_it_should_include_failure_messages_of_all_failing_assertions()
{
//-----------------------------------------------------------------------------------------------------------
// Arrange
//-----------------------------------------------------------------------------------------------------------
var scope = new AssertionScope(new CustomAssertionStrategy());
false.Should().BeTrue();
true.Should().BeFalse();

//-----------------------------------------------------------------------------------------------------------
// Act
//-----------------------------------------------------------------------------------------------------------
Action act = scope.Dispose;

//-----------------------------------------------------------------------------------------------------------
// Assert
//-----------------------------------------------------------------------------------------------------------
act.Should().ThrowExactly<XunitException>()
.WithMessage("*but found false*but found true*");
}

#if NET45
[Serializable]
#endif
public class CustomAssertionStrategy : IAssertionStrategy
{
private readonly List<string> failureMessages = new List<string>();

/// <summary>
/// Returns the messages for the assertion failures that happened until now.
/// </summary>
public IEnumerable<string> FailureMessages => failureMessages;

/// <summary>
/// Discards and returns the failure messages that happened up to now.
/// </summary>
public IEnumerable<string> DiscardFailures()
{
var discardedFailures = failureMessages.ToArray();
failureMessages.Clear();
return discardedFailures;
}

/// <summary>
/// Will throw a combined exception for any failures have been collected since <see cref="StartCollecting"/> was called.
/// </summary>
public void ThrowIfAny(IDictionary<string, object> context)
{
if (failureMessages.Any())
{
var builder = new StringBuilder();
builder.AppendLine(string.Join(Environment.NewLine, failureMessages));

if (context.Any())
{
foreach (KeyValuePair<string, object> pair in context)
{
builder.AppendFormat("\nWith {0}:\n{1}", pair.Key, pair.Value);
}
}

Services.ThrowException(builder.ToString());
}
}

/// <summary>
/// Instructs the strategy to handle a assertion failure.
/// </summary>
public void HandleFailure(string message)
{
failureMessages.Add(message);
}
}

#if NET45
[Serializable]
#endif
internal class FailWithStupidMessageAssertionStrategy : IAssertionStrategy
{
public IEnumerable<string> FailureMessages => new string[0];
Expand Down

0 comments on commit d5ec77f

Please sign in to comment.