diff --git a/Pipeline/Build.cs b/Pipeline/Build.cs index a07a0cc08..25356ef59 100644 --- a/Pipeline/Build.cs +++ b/Pipeline/Build.cs @@ -19,7 +19,7 @@ partial class Build : NukeBuild /// /// Afterward, you can update the package reference in `Directory.Packages.props` and reset this flag. /// - readonly BuildScope BuildScope = BuildScope.Default; + readonly BuildScope BuildScope = BuildScope.CoreOnly; [Parameter("Github Token")] readonly string GithubToken; diff --git a/Source/aweXpect.Core/Core/Constraints/ConstraintResult.ExceptionConstraintResult.cs b/Source/aweXpect.Core/Core/Constraints/ConstraintResult.ExceptionConstraintResult.cs new file mode 100644 index 000000000..873ac0cad --- /dev/null +++ b/Source/aweXpect.Core/Core/Constraints/ConstraintResult.ExceptionConstraintResult.cs @@ -0,0 +1,72 @@ +using System; +using System.Diagnostics.CodeAnalysis; +using System.Text; +using aweXpect.Core.Helpers; + +namespace aweXpect.Core.Constraints; + +/// +/// The result of the check if an expectation is met. +/// +public abstract partial class ConstraintResult +{ + /// + /// A failed due to an . + /// + internal class ExceptionConstraintResult : ConstraintResult + { + private readonly Exception _exception; + private readonly ConstraintResult _inner; + + /// + /// A failed due to a thrown . + /// + public ExceptionConstraintResult( + ConstraintResult inner, + Exception exception, + ExpectationBuilder expectationBuilder) + : base(inner.Grammars) + { + _inner = inner; + _exception = exception; + FurtherProcessingStrategy = inner.FurtherProcessingStrategy; + expectationBuilder.UpdateContexts(c => c.Add(new ResultContext("Exception", exception.ToString()))); + } + + public override Outcome Outcome + { + get => Outcome.Failure; + protected set => _inner.Outcome = value; + } + + /// + public override void AppendExpectation(StringBuilder stringBuilder, string? indentation = null) + => _inner.AppendExpectation(stringBuilder, indentation); + + /// + public override void AppendResult(StringBuilder stringBuilder, string? indentation = null) + { + stringBuilder + .Append("it did throw "); + + Type? exceptionType = _exception.GetType(); + if (exceptionType == typeof(Exception)) + { + stringBuilder.Append("an exception"); + } + else + { + stringBuilder.Append(Formatter.Format(exceptionType).PrependAOrAn()); + } + } + + /// + public override bool TryGetValue([NotNullWhen(true)] out TValue? value) + where TValue : default + => _inner.TryGetValue(out value); + + /// + public override ConstraintResult Negate() + => _inner.Negate(); + } +} diff --git a/Source/aweXpect.Core/Core/ExpectationBuilder.cs b/Source/aweXpect.Core/Core/ExpectationBuilder.cs index f9f07b526..0070c174b 100644 --- a/Source/aweXpect.Core/Core/ExpectationBuilder.cs +++ b/Source/aweXpect.Core/Core/ExpectationBuilder.cs @@ -540,12 +540,25 @@ internal override async Task IsMet(Node rootNode, timeoutCts.CancelAfter(timeout.Value); CancellationToken token = timeoutCts.Token; TValue dataWithTimeout = await _subjectSource.GetValue(timeSystem, token); - Customize.aweXpect.TraceWriter.Value?.WriteMessage($"Checking expectation for {Subject} {dataWithTimeout} with timeout of {Formatter.Format(timeout)}"); + Customize.aweXpect.TraceWriter.Value?.WriteMessage( + $"Checking expectation for {Subject} {dataWithTimeout} with timeout of {Formatter.Format(timeout)}"); return await rootNode.IsMetBy(dataWithTimeout, context, token); } - TValue data = await _subjectSource.GetValue(timeSystem, cancellationToken); - Customize.aweXpect.TraceWriter.Value?.WriteMessage($"Checking expectation for {Subject} {data}"); + TValue data; + try + { + data = await _subjectSource.GetValue(timeSystem, cancellationToken); + Customize.aweXpect.TraceWriter.Value?.WriteMessage($"Checking expectation for {Subject} {data}"); + } + catch (Exception exception) + { + ConstraintResult expectation = await rootNode.IsMetBy(default(TValue), context, cancellationToken); + Customize.aweXpect.TraceWriter.Value?.WriteMessage( + $"Checking expectation for {Subject} threw an exception"); + return new ConstraintResult.ExceptionConstraintResult(expectation, exception, this); + } + return await rootNode.IsMetBy(data, context, cancellationToken); } } diff --git a/Tests/aweXpect.Tests/Booleans/ThatBool.IsFalse.Tests.cs b/Tests/aweXpect.Tests/Booleans/ThatBool.IsFalse.Tests.cs index b68911f3d..a4697316a 100644 --- a/Tests/aweXpect.Tests/Booleans/ThatBool.IsFalse.Tests.cs +++ b/Tests/aweXpect.Tests/Booleans/ThatBool.IsFalse.Tests.cs @@ -17,6 +17,26 @@ async Task Act() await That(Act).DoesNotThrow(); } + [Fact] + public async Task WhenTaskFails_ShouldFailWithExceptionMessage() + { + Task subject = Task.FromException( + new NotSupportedException("When Task throws an exception")); + + async Task Act() + => await That(subject).IsFalse().Because("the exception should be logged"); + + await That(Act).Throws() + .WithMessage(""" + Expected that subject + is False, because the exception should be logged, + but it did throw a NotSupportedException + + Exception: + System.NotSupportedException: When Task throws an exception + """).AsPrefix(); + } + [Fact] public async Task WhenTrue_ShouldFail() { diff --git a/Tests/aweXpect.Tests/Booleans/ThatBool.IsTrue.Tests.cs b/Tests/aweXpect.Tests/Booleans/ThatBool.IsTrue.Tests.cs index 50e309c62..6aa357562 100644 --- a/Tests/aweXpect.Tests/Booleans/ThatBool.IsTrue.Tests.cs +++ b/Tests/aweXpect.Tests/Booleans/ThatBool.IsTrue.Tests.cs @@ -38,6 +38,26 @@ but it was False """); } + [Fact] + public async Task WhenTaskFails_ShouldFailWithExceptionMessage() + { + Task subject = Task.FromException( + new NotSupportedException("When Task throws an exception")); + + async Task Act() + => await That(subject).IsTrue().Because("the exception should be logged"); + + await That(Act).Throws() + .WithMessage(""" + Expected that subject + is True, because the exception should be logged, + but it did throw a NotSupportedException + + Exception: + System.NotSupportedException: When Task throws an exception + """).AsPrefix(); + } + [Fact] public async Task WhenTrue_ShouldSucceed() { diff --git a/Tests/aweXpect.Tests/Booleans/ThatBool.Nullable.IsFalse.Tests.cs b/Tests/aweXpect.Tests/Booleans/ThatBool.Nullable.IsFalse.Tests.cs index eb6f7f951..f037a3811 100644 --- a/Tests/aweXpect.Tests/Booleans/ThatBool.Nullable.IsFalse.Tests.cs +++ b/Tests/aweXpect.Tests/Booleans/ThatBool.Nullable.IsFalse.Tests.cs @@ -19,6 +19,26 @@ async Task Act() await That(Act).DoesNotThrow(); } + [Fact] + public async Task WhenTaskFails_ShouldFailWithExceptionMessage() + { + Task subject = Task.FromException( + new NotSupportedException("When Task throws an exception")); + + async Task Act() + => await That(subject).IsFalse().Because("the exception should be logged"); + + await That(Act).Throws() + .WithMessage(""" + Expected that subject + is False, because the exception should be logged, + but it did throw a NotSupportedException + + Exception: + System.NotSupportedException: When Task throws an exception + """).AsPrefix(); + } + [Theory] [InlineData(true)] [InlineData(null)] diff --git a/Tests/aweXpect.Tests/Booleans/ThatBool.Nullable.IsNotEqualTo.Tests.cs b/Tests/aweXpect.Tests/Booleans/ThatBool.Nullable.IsNotEqualTo.Tests.cs index 425ff8c67..6a3189982 100644 --- a/Tests/aweXpect.Tests/Booleans/ThatBool.Nullable.IsNotEqualTo.Tests.cs +++ b/Tests/aweXpect.Tests/Booleans/ThatBool.Nullable.IsNotEqualTo.Tests.cs @@ -18,11 +18,11 @@ async Task Act() => await That(subject).IsNotEqualTo(unexpected); await That(Act).Throws() - .WithMessage($""" - Expected that subject - is not , - but it was - """); + .WithMessage(""" + Expected that subject + is not , + but it was + """); } [Theory] diff --git a/Tests/aweXpect.Tests/Booleans/ThatBool.Nullable.IsNotFalse.Tests.cs b/Tests/aweXpect.Tests/Booleans/ThatBool.Nullable.IsNotFalse.Tests.cs index 2e43e42be..98f0a2344 100644 --- a/Tests/aweXpect.Tests/Booleans/ThatBool.Nullable.IsNotFalse.Tests.cs +++ b/Tests/aweXpect.Tests/Booleans/ThatBool.Nullable.IsNotFalse.Tests.cs @@ -24,6 +24,26 @@ but it was """); } + [Fact] + public async Task WhenTaskFails_ShouldFailWithExceptionMessage() + { + Task subject = Task.FromException( + new NotSupportedException("When Task throws an exception")); + + async Task Act() + => await That(subject).IsNotFalse().Because("the exception should be logged"); + + await That(Act).Throws() + .WithMessage(""" + Expected that subject + is not False, because the exception should be logged, + but it did throw a NotSupportedException + + Exception: + System.NotSupportedException: When Task throws an exception + """).AsPrefix(); + } + [Theory] [InlineData(true)] [InlineData(null)] diff --git a/Tests/aweXpect.Tests/Booleans/ThatBool.Nullable.IsNotTrue.Tests.cs b/Tests/aweXpect.Tests/Booleans/ThatBool.Nullable.IsNotTrue.Tests.cs index a705a1734..31d0ba272 100644 --- a/Tests/aweXpect.Tests/Booleans/ThatBool.Nullable.IsNotTrue.Tests.cs +++ b/Tests/aweXpect.Tests/Booleans/ThatBool.Nullable.IsNotTrue.Tests.cs @@ -19,6 +19,26 @@ async Task Act() await That(Act).DoesNotThrow(); } + [Fact] + public async Task WhenTaskFails_ShouldFailWithExceptionMessage() + { + Task subject = Task.FromException( + new NotSupportedException("When Task throws an exception")); + + async Task Act() + => await That(subject).IsNotTrue().Because("the exception should be logged"); + + await That(Act).Throws() + .WithMessage(""" + Expected that subject + is not True, because the exception should be logged, + but it did throw a NotSupportedException + + Exception: + System.NotSupportedException: When Task throws an exception + """).AsPrefix(); + } + [Fact] public async Task WhenTrue_ShouldFail() { diff --git a/Tests/aweXpect.Tests/Booleans/ThatBool.Nullable.IsTrue.Tests.cs b/Tests/aweXpect.Tests/Booleans/ThatBool.Nullable.IsTrue.Tests.cs index 640b5f666..91dc8efa4 100644 --- a/Tests/aweXpect.Tests/Booleans/ThatBool.Nullable.IsTrue.Tests.cs +++ b/Tests/aweXpect.Tests/Booleans/ThatBool.Nullable.IsTrue.Tests.cs @@ -24,6 +24,26 @@ Expected that subject """); } + [Fact] + public async Task WhenTaskFails_ShouldFailWithExceptionMessage() + { + Task subject = Task.FromException( + new NotSupportedException("When Task throws an exception")); + + async Task Act() + => await That(subject).IsTrue().Because("the exception should be logged"); + + await That(Act).Throws() + .WithMessage(""" + Expected that subject + is True, because the exception should be logged, + but it did throw a NotSupportedException + + Exception: + System.NotSupportedException: When Task throws an exception + """).AsPrefix(); + } + [Fact] public async Task WhenTrue_ShouldSucceed() {