Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ namespace aweXpect;
public static partial class ThatDelegateThrows
{
/// <summary>
/// Verifies that the thrown exception has a message equal to <paramref name="expected" />
/// Verifies that the thrown exception has a message equal to <paramref name="expected" />.
/// </summary>
public static StringEqualityTypeResult<TException, ThatDelegateThrows<TException>> WithMessage<TException>(
this ThatDelegateThrows<TException> source,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
using System;
using aweXpect.Core;
using aweXpect.Delegates;
using aweXpect.Options;
using aweXpect.Results;

namespace aweXpect;

public static partial class ThatDelegateThrows
{
/// <summary>
/// Verifies that the thrown exception has a message that contains the <paramref name="expected" /> pattern.
/// </summary>
public static StringEqualityResult<TException, ThatDelegateThrows<TException>> WithMessageContaining<TException>(
this ThatDelegateThrows<TException> source,
string? expected)
where TException : Exception?
{
StringEqualityOptions options = new();
return new StringEqualityResult<TException, ThatDelegateThrows<TException>>(
source.ExpectationBuilder.AddConstraint((it, grammars)
=> new ThatException.HasMessageContainingConstraint(
source.ExpectationBuilder,
it,
grammars | ExpectationGrammars.Active | ExpectationGrammars.Nested,
expected,
options)),
source,
options);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ namespace aweXpect;
public static partial class ThatException
{
/// <summary>
/// Verifies that the actual exception has a message equal to <paramref name="expected" />
/// Verifies that the actual exception has a message equal to <paramref name="expected" />.
/// </summary>
public static StringEqualityTypeResult<Exception?, IThat<Exception?>> HasMessage(
this IThat<Exception?> source,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
using System;
using aweXpect.Core;
using aweXpect.Core.Constraints;
using aweXpect.Helpers;
using aweXpect.Options;
using aweXpect.Results;

namespace aweXpect;

public static partial class ThatException
{
/// <summary>
/// Verifies that the actual exception has a message containing the <paramref name="expected" /> pattern.
/// </summary>
public static StringEqualityTypeResult<Exception?, IThat<Exception?>> HasMessageContaining(
this IThat<Exception?> source,
string? expected)
{
StringEqualityOptions options = new();
return new StringEqualityTypeResult<Exception?, IThat<Exception?>>(
source.Get().ExpectationBuilder.AddConstraint((expectationBuilder, it, grammars)
=> new HasMessageContainingConstraint(
expectationBuilder, it, grammars, expected, options)),
source,
options);
}

internal class HasMessageContainingConstraint(
ExpectationBuilder expectationBuilder,
string it,
ExpectationGrammars grammars,
string? expected,
StringEqualityOptions options)
: ConstraintResult.WithValue<Exception?>(grammars),
IValueConstraint<Exception?>
{
public ConstraintResult IsMetBy(Exception? actual)
{
Actual = actual;
options.AsWildcard();
Outcome = expected is null || options.AreConsideredEqual(actual?.Message, $"*{expected}*")
? Outcome.Success
: Outcome.Failure;
if (Outcome == Outcome.Failure)
{
expectationBuilder.UpdateContexts(contexts => contexts
.Add(new ResultContext("Message", actual?.Message)));
}

return this;
}

protected override void AppendNormalExpectation(StringBuilder stringBuilder, string? indentation = null)
Comment thread
vbreuss marked this conversation as resolved.
{
ExpectationGrammars equalityGrammars = Grammars;
if (Grammars.HasFlag(ExpectationGrammars.Active))
{
stringBuilder.Append("with Message containing ");
equalityGrammars &= ~ExpectationGrammars.Active;
}
else if (Grammars.HasFlag(ExpectationGrammars.Nested))
{
stringBuilder.Append("Message contains ");
}
else
{
stringBuilder.Append("contains Message ");
}

stringBuilder.Append(options.GetExpectation(expected, equalityGrammars));
}

protected override void AppendNormalResult(StringBuilder stringBuilder, string? indentation = null)
Comment thread
vbreuss marked this conversation as resolved.
=> stringBuilder.Append(options.GetExtendedFailure(it, Grammars, Actual?.Message, expected));

protected override void AppendNegatedExpectation(StringBuilder stringBuilder, string? indentation = null)
Comment thread
vbreuss marked this conversation as resolved.
{
ExpectationGrammars equalityGrammars = Grammars;
if (Grammars.HasFlag(ExpectationGrammars.Active))
{
stringBuilder.Append("with Message containing ");
equalityGrammars &= ~ExpectationGrammars.Active;
}
else if (Grammars.HasFlag(ExpectationGrammars.Nested))
{
stringBuilder.Append("Message contains ");
}
else
{
stringBuilder.Append("contains Message ");
}

stringBuilder.Append(options.GetExpectation(expected, equalityGrammars));
}

protected override void AppendNegatedResult(StringBuilder stringBuilder, string? indentation = null)
Comment thread
vbreuss marked this conversation as resolved.
=> AppendNormalResult(stringBuilder, indentation);
}
}
3 changes: 3 additions & 0 deletions Tests/aweXpect.Api.Tests/Expected/aweXpect_net8.0.txt
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,8 @@ namespace aweXpect
where TException : System.Exception? { }
public static aweXpect.Results.StringEqualityTypeResult<TException, aweXpect.Delegates.ThatDelegateThrows<TException>> WithMessage<TException>(this aweXpect.Delegates.ThatDelegateThrows<TException> source, string expected)
where TException : System.Exception? { }
public static aweXpect.Results.StringEqualityResult<TException, aweXpect.Delegates.ThatDelegateThrows<TException>> WithMessageContaining<TException>(this aweXpect.Delegates.ThatDelegateThrows<TException> source, string? expected)
where TException : System.Exception? { }
public static aweXpect.Results.AndOrResult<TException, aweXpect.Delegates.ThatDelegateThrows<TException>> WithParamName<TException>(this aweXpect.Delegates.ThatDelegateThrows<TException> source, string? expected)
where TException : System.ArgumentException? { }
public static aweXpect.Results.AndOrResult<TException?, aweXpect.Delegates.ThatDelegateThrows<TException>> WithRecursiveInnerExceptions<TException>(this aweXpect.Delegates.ThatDelegateThrows<TException> source, System.Action<aweXpect.Core.IThat<System.Collections.Generic.IEnumerable<System.Exception>>> expectations)
Expand Down Expand Up @@ -669,6 +671,7 @@ namespace aweXpect
public static aweXpect.Results.AndOrResult<System.Exception?, aweXpect.Core.IThat<System.Exception?>> HasInnerException(this aweXpect.Core.IThat<System.Exception?> source) { }
public static aweXpect.Results.AndOrResult<System.Exception?, aweXpect.Core.IThat<System.Exception?>> HasInnerException(this aweXpect.Core.IThat<System.Exception?> source, System.Action<aweXpect.Core.IThat<System.Exception?>> expectations) { }
public static aweXpect.Results.StringEqualityTypeResult<System.Exception?, aweXpect.Core.IThat<System.Exception?>> HasMessage(this aweXpect.Core.IThat<System.Exception?> source, string expected) { }
public static aweXpect.Results.StringEqualityTypeResult<System.Exception?, aweXpect.Core.IThat<System.Exception?>> HasMessageContaining(this aweXpect.Core.IThat<System.Exception?> source, string? expected) { }
public static aweXpect.Results.AndOrResult<TException, aweXpect.Core.IThat<TException>> HasParamName<TException>(this aweXpect.Core.IThat<TException> source, string? expected)
where TException : System.ArgumentException? { }
public static aweXpect.Results.AndOrResult<System.Exception?, aweXpect.Core.IThat<System.Exception?>> HasRecursiveInnerExceptions(this aweXpect.Core.IThat<System.Exception?> source, System.Action<aweXpect.Core.IThat<System.Collections.Generic.IEnumerable<System.Exception>>> expectations) { }
Expand Down
3 changes: 3 additions & 0 deletions Tests/aweXpect.Api.Tests/Expected/aweXpect_netstandard2.0.txt
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,8 @@ namespace aweXpect
where TException : System.Exception? { }
public static aweXpect.Results.StringEqualityTypeResult<TException, aweXpect.Delegates.ThatDelegateThrows<TException>> WithMessage<TException>(this aweXpect.Delegates.ThatDelegateThrows<TException> source, string expected)
where TException : System.Exception? { }
public static aweXpect.Results.StringEqualityResult<TException, aweXpect.Delegates.ThatDelegateThrows<TException>> WithMessageContaining<TException>(this aweXpect.Delegates.ThatDelegateThrows<TException> source, string? expected)
where TException : System.Exception? { }
public static aweXpect.Results.AndOrResult<TException, aweXpect.Delegates.ThatDelegateThrows<TException>> WithParamName<TException>(this aweXpect.Delegates.ThatDelegateThrows<TException> source, string? expected)
where TException : System.ArgumentException? { }
public static aweXpect.Results.AndOrResult<TException?, aweXpect.Delegates.ThatDelegateThrows<TException>> WithRecursiveInnerExceptions<TException>(this aweXpect.Delegates.ThatDelegateThrows<TException> source, System.Action<aweXpect.Core.IThat<System.Collections.Generic.IEnumerable<System.Exception>>> expectations)
Expand Down Expand Up @@ -454,6 +456,7 @@ namespace aweXpect
public static aweXpect.Results.AndOrResult<System.Exception?, aweXpect.Core.IThat<System.Exception?>> HasInnerException(this aweXpect.Core.IThat<System.Exception?> source) { }
public static aweXpect.Results.AndOrResult<System.Exception?, aweXpect.Core.IThat<System.Exception?>> HasInnerException(this aweXpect.Core.IThat<System.Exception?> source, System.Action<aweXpect.Core.IThat<System.Exception?>> expectations) { }
public static aweXpect.Results.StringEqualityTypeResult<System.Exception?, aweXpect.Core.IThat<System.Exception?>> HasMessage(this aweXpect.Core.IThat<System.Exception?> source, string expected) { }
public static aweXpect.Results.StringEqualityTypeResult<System.Exception?, aweXpect.Core.IThat<System.Exception?>> HasMessageContaining(this aweXpect.Core.IThat<System.Exception?> source, string? expected) { }
public static aweXpect.Results.AndOrResult<TException, aweXpect.Core.IThat<TException>> HasParamName<TException>(this aweXpect.Core.IThat<TException> source, string? expected)
where TException : System.ArgumentException? { }
public static aweXpect.Results.AndOrResult<System.Exception?, aweXpect.Core.IThat<System.Exception?>> HasRecursiveInnerExceptions(this aweXpect.Core.IThat<System.Exception?> source, System.Action<aweXpect.Core.IThat<System.Collections.Generic.IEnumerable<System.Exception>>> expectations) { }
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
namespace aweXpect.Tests;

public sealed partial class ThatDelegate
{
public sealed partial class ThrowsException
{
public sealed class WithMessageContainingTests
{
[Fact]
public async Task CanCompareCaseInsensitive()
{
string message = "_FOO_BAR";
Exception exception =
new OuterException(message, new CustomException());
void Delegate() => throw exception;

async Task Act()
=> await That(Delegate).ThrowsException()
.WithMessageContaining("foo").IgnoringCase();

await That(Act).DoesNotThrow();
}

[Fact]
public async Task CanUseWildcardCheck()
{
string message = "_foo-BAR";
Exception exception =
new OuterException(message, new CustomException());
void Delegate() => throw exception;

async Task Act()
=> await That(Delegate).ThrowsException()
.WithMessageContaining("f?o-");

await That(Act).DoesNotThrow();
}

[Fact]
public async Task ShouldCompareCaseSensitive()
{
string message = "FOO";
Exception exception =
new OuterException(message, new CustomException());
void Delegate() => throw exception;

async Task Act()
=> await That(Delegate).ThrowsException()
.WithMessageContaining("foo");

await That(Act).Throws<XunitException>()
.WithMessage("""
Expected that Delegate
throws an exception with Message containing matching "foo",
but it did not match:
↓ (actual)
"FOO"
"foo"
↑ (wildcard pattern)

Message:
FOO
""");
}

[Fact]
public async Task ShouldIgnorePrecedingText()
{
string message = "some text before foo";
Exception exception =
new OuterException(message, new CustomException());
void Delegate() => throw exception;

async Task Act()
=> await That(Delegate).ThrowsException()
.WithMessageContaining("foo");

await That(Act).DoesNotThrow();
}

[Fact]
public async Task ShouldIgnoreSucceedingText()
{
string message = "foo and some other text";
Exception exception =
new OuterException(message, new CustomException());
void Delegate() => throw exception;

async Task Act()
=> await That(Delegate).ThrowsException()
.WithMessageContaining("foo");

await That(Act).DoesNotThrow();
}

[Fact]
public async Task ShouldIncludeExceptionType()
{
string message = "FOO";
Exception exception = new CustomException(message);
void Delegate() => throw exception;

async Task Act()
=> await That(Delegate).Throws<CustomException>()
.WithMessageContaining("foo");

await That(Act).Throws<XunitException>()
.WithMessage("""
Expected that Delegate
throws a ThatDelegate.CustomException with Message containing matching "foo",
but it did not match:
↓ (actual)
"FOO"
"foo"
↑ (wildcard pattern)

Message:
FOO
""");
}

[Theory]
[AutoData]
public async Task WhenAwaited_ShouldReturnThrownException(string message)
{
Exception exception =
new OuterException(message, new CustomException());
void Delegate() => throw exception;

Exception result = await That(Delegate)
.ThrowsException().WithMessageContaining(message);

await That(result).IsSameAs(exception);
}

[Theory]
[AutoData]
public async Task WhenExpectedIsNull_ShouldSucceed(string message)
{
Exception exception = new(message);
void Delegate() => throw exception;

async Task Act()
=> await That(Delegate).ThrowsException()
.WithMessageContaining(null);

await That(Act).DoesNotThrow();
}

[Fact]
public async Task WhenMessagesAreDifferent_ShouldFail()
{
string actual = "expected actual text";
string expected = "expected other text";
Action action = () => throw new CustomException(actual);

async Task Act()
=> await That(action).ThrowsException().WithMessageContaining(expected);

await That(Act).Throws<XunitException>()
.WithMessage("""
Expected that action
throws an exception with Message containing matching "expected other text",
but it did not match:
↓ (actual)
"expected actual text"
"expected other text"
↑ (wildcard pattern)

Message:
expected actual text
""");
}
}
}
}
Loading
Loading