diff --git a/Source/aweXpect.Core/Core/ThatBool.cs b/Source/aweXpect.Core/Core/ThatBool.cs new file mode 100644 index 000000000..59a34f274 --- /dev/null +++ b/Source/aweXpect.Core/Core/ThatBool.cs @@ -0,0 +1,88 @@ +using System; +using System.Diagnostics; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using aweXpect.Core.Constraints; +using aweXpect.Core.Nodes; +using aweXpect.Core.TimeSystem; +using aweXpect.Results; + +namespace aweXpect.Core; + +/// +/// Wraps the for a bool. +/// +[DebuggerDisplay("ThatBool: {ExpectationBuilder}")] +public class ThatBool : ExpectationResult, IExpectThat +{ + /// + public ThatBool(ExpectationBuilder expectationBuilder) : this( + new WithDefaultExpectationBuilderProxy(expectationBuilder)) + { + } + + private ThatBool(WithDefaultExpectationBuilderProxy expectationBuilder) : base(expectationBuilder) + { + ExpectationBuilder = expectationBuilder; + } + + /// + public ExpectationBuilder ExpectationBuilder { get; } + + private sealed class WithDefaultExpectationBuilderProxy(ExpectationBuilder inner) + : ExpectationBuilder(inner.Subject, inner.ExpectationGrammars) + { + public override ExpectationBuilder UpdateContexts(Action callback) + => inner.UpdateContexts(callback); + + internal override Task IsMet(Node rootNode, EvaluationContext.EvaluationContext context, + ITimeSystem timeSystem, TimeSpan? timeout, + CancellationToken cancellationToken) + { + if (rootNode is ExpectationNode expectationNode && expectationNode.IsEmpty()) + { + rootNode.AddConstraint(new IsTrueConstraint(inner.ExpectationGrammars)); + } + + return inner.IsMet(rootNode, context, timeSystem, timeout, cancellationToken); + } + + private sealed class IsTrueConstraint(ExpectationGrammars grammars) + : ConstraintResult.WithEqualToValue("it", grammars, false), + IValueConstraint + { + public ConstraintResult IsMetBy(bool actual) + { + Actual = actual; + Outcome = true.Equals(actual) ? Outcome.Success : Outcome.Failure; + return this; + } + + protected override void AppendNormalExpectation(StringBuilder stringBuilder, string? indentation = null) + { + stringBuilder.Append("is "); + Formatter.Format(stringBuilder, true, FormattingOptions.Indented(indentation)); + } + + protected override void AppendNormalResult(StringBuilder stringBuilder, string? indentation = null) + { + stringBuilder.Append(It); + stringBuilder.Append(" was "); + Formatter.Format(stringBuilder, Actual, FormattingOptions.Indented(indentation)); + } + + protected override void AppendNegatedExpectation(StringBuilder stringBuilder, string? indentation = null) + { + stringBuilder.Append("is not "); + Formatter.Format(stringBuilder, true, FormattingOptions.Indented(indentation)); + } + + protected override void AppendNegatedResult(StringBuilder stringBuilder, string? indentation = null) + { + stringBuilder.Append(It); + stringBuilder.Append(" was"); + } + } + } +} diff --git a/Source/aweXpect.Core/Expect.cs b/Source/aweXpect.Core/Expect.cs index bd06fbf69..ead8a2b8c 100644 --- a/Source/aweXpect.Core/Expect.cs +++ b/Source/aweXpect.Core/Expect.cs @@ -192,6 +192,14 @@ public static ThatDelegate.WithValue That( doNotPopulateThisValue)); #endif + /// + /// Specify expectations for the current boolean . + /// + public static ThatBool That(bool subject, + [CallerArgumentExpression("subject")] string doNotPopulateThisValue = "") + => new(new ExpectationBuilder( + new ValueSource(subject), doNotPopulateThisValue)); + /// /// Verifies that all provided are met. /// diff --git a/Tests/aweXpect.Core.Api.Tests/Expected/aweXpect.Core_net8.0.txt b/Tests/aweXpect.Core.Api.Tests/Expected/aweXpect.Core_net8.0.txt index 1071ee9d5..42818f14b 100644 --- a/Tests/aweXpect.Core.Api.Tests/Expected/aweXpect.Core_net8.0.txt +++ b/Tests/aweXpect.Core.Api.Tests/Expected/aweXpect.Core_net8.0.txt @@ -320,6 +320,12 @@ namespace aweXpect.Core { public static aweXpect.Core.StringDifferenceSettings WithMatchType(this aweXpect.Core.StringDifferenceSettings? settings, aweXpect.Core.StringDifference.MatchType matchType) { } } + [System.Diagnostics.DebuggerDisplay("ThatBool: {ExpectationBuilder}")] + public class ThatBool : aweXpect.Results.ExpectationResult, aweXpect.Core.IExpectThat, aweXpect.Core.IThat + { + public ThatBool(aweXpect.Core.ExpectationBuilder expectationBuilder) { } + public aweXpect.Core.ExpectationBuilder ExpectationBuilder { get; } + } [System.Diagnostics.DebuggerDisplay("ThatSubject<{typeof(T)}>: {ExpectationBuilder}")] public readonly struct ThatSubject : aweXpect.Core.IExpectThat, aweXpect.Core.IThat { @@ -627,6 +633,7 @@ namespace aweXpect public static aweXpect.Delegates.ThatDelegate.WithoutValue That(System.Func @delegate, [System.Runtime.CompilerServices.CallerArgumentExpression("delegate")] string doNotPopulateThisValue = "") { } public static aweXpect.Delegates.ThatDelegate.WithoutValue That(System.Func @delegate, [System.Runtime.CompilerServices.CallerArgumentExpression("delegate")] string doNotPopulateThisValue = "") { } public static aweXpect.Delegates.ThatDelegate.WithoutValue That(System.Func @delegate, [System.Runtime.CompilerServices.CallerArgumentExpression("delegate")] string doNotPopulateThisValue = "") { } + public static aweXpect.Core.ThatBool That(bool subject, [System.Runtime.CompilerServices.CallerArgumentExpression("subject")] string doNotPopulateThisValue = "") { } public static aweXpect.Delegates.ThatDelegate.WithValue That(System.Func> @delegate, [System.Runtime.CompilerServices.CallerArgumentExpression("delegate")] string doNotPopulateThisValue = "") { } public static aweXpect.Delegates.ThatDelegate.WithValue That(System.Func> @delegate, [System.Runtime.CompilerServices.CallerArgumentExpression("delegate")] string doNotPopulateThisValue = "") { } public static aweXpect.Delegates.ThatDelegate.WithValue That(System.Func @delegate, [System.Runtime.CompilerServices.CallerArgumentExpression("delegate")] string doNotPopulateThisValue = "") { } diff --git a/Tests/aweXpect.Core.Api.Tests/Expected/aweXpect.Core_netstandard2.0.txt b/Tests/aweXpect.Core.Api.Tests/Expected/aweXpect.Core_netstandard2.0.txt index 4ef086681..e700b7506 100644 --- a/Tests/aweXpect.Core.Api.Tests/Expected/aweXpect.Core_netstandard2.0.txt +++ b/Tests/aweXpect.Core.Api.Tests/Expected/aweXpect.Core_netstandard2.0.txt @@ -306,6 +306,12 @@ namespace aweXpect.Core { public static aweXpect.Core.StringDifferenceSettings WithMatchType(this aweXpect.Core.StringDifferenceSettings? settings, aweXpect.Core.StringDifference.MatchType matchType) { } } + [System.Diagnostics.DebuggerDisplay("ThatBool: {ExpectationBuilder}")] + public class ThatBool : aweXpect.Results.ExpectationResult, aweXpect.Core.IExpectThat, aweXpect.Core.IThat + { + public ThatBool(aweXpect.Core.ExpectationBuilder expectationBuilder) { } + public aweXpect.Core.ExpectationBuilder ExpectationBuilder { get; } + } [System.Diagnostics.DebuggerDisplay("ThatSubject<{typeof(T)}>: {ExpectationBuilder}")] public readonly struct ThatSubject : aweXpect.Core.IExpectThat, aweXpect.Core.IThat { @@ -611,6 +617,7 @@ namespace aweXpect public static aweXpect.Delegates.ThatDelegate.WithoutValue That(System.Action @delegate, [System.Runtime.CompilerServices.CallerArgumentExpression("delegate")] string doNotPopulateThisValue = "") { } public static aweXpect.Delegates.ThatDelegate.WithoutValue That(System.Func @delegate, [System.Runtime.CompilerServices.CallerArgumentExpression("delegate")] string doNotPopulateThisValue = "") { } public static aweXpect.Delegates.ThatDelegate.WithoutValue That(System.Func @delegate, [System.Runtime.CompilerServices.CallerArgumentExpression("delegate")] string doNotPopulateThisValue = "") { } + public static aweXpect.Core.ThatBool That(bool subject, [System.Runtime.CompilerServices.CallerArgumentExpression("subject")] string doNotPopulateThisValue = "") { } public static aweXpect.Delegates.ThatDelegate.WithValue That(System.Func> @delegate, [System.Runtime.CompilerServices.CallerArgumentExpression("delegate")] string doNotPopulateThisValue = "") { } public static aweXpect.Delegates.ThatDelegate.WithValue That(System.Func @delegate, [System.Runtime.CompilerServices.CallerArgumentExpression("delegate")] string doNotPopulateThisValue = "") { } public static aweXpect.Delegates.ThatDelegate.WithValue That(System.Func> @delegate, [System.Runtime.CompilerServices.CallerArgumentExpression("delegate")] string doNotPopulateThisValue = "") { } diff --git a/Tests/aweXpect.Core.Tests/Results/ExpectationTests.cs b/Tests/aweXpect.Core.Tests/Results/ExpectationTests.cs index 3863f2a7d..9b1bd2a58 100644 --- a/Tests/aweXpect.Core.Tests/Results/ExpectationTests.cs +++ b/Tests/aweXpect.Core.Tests/Results/ExpectationTests.cs @@ -46,12 +46,12 @@ public async Task GetType_ShouldForwardToBase() public async Task ToString_ShouldForwardToExpectationBuilder() { #pragma warning disable aweXpect0001 - Expectation sut = That(true).IsTrue(); + Expectation sut = That(1).IsGreaterThan(0); #pragma warning restore aweXpect0001 string? result = sut.ToString(); await That(result) - .IsEqualTo("aweXpect.Core.ExpectationBuilder`1[System.Boolean]"); + .IsEqualTo("aweXpect.Core.ExpectationBuilder`1[System.Int32]"); } } diff --git a/Tests/aweXpect.Tests/Booleans/ThatBool.cs b/Tests/aweXpect.Tests/Booleans/ThatBool.cs index 4f3bce5cc..bb3eb7982 100644 --- a/Tests/aweXpect.Tests/Booleans/ThatBool.cs +++ b/Tests/aweXpect.Tests/Booleans/ThatBool.cs @@ -1,4 +1,53 @@ namespace aweXpect.Tests; // ReSharper disable once ClassNeverInstantiated.Global -public sealed partial class ThatBool; +public sealed partial class ThatBool +{ +/* TODO: Enable after next Core update + public sealed class Tests + { + [Fact] + public async Task WhenFalse_ShouldFail() + { + bool subject = false; + + async Task Act() + => await That(subject); + + await That(Act).Throws() + .WithMessage(""" + Expected that subject + is True, + but it was False + """); + } + + [Fact] + public async Task WhenFalse_ShouldFailWithDescriptiveMessage() + { + bool subject = false; + + async Task Act() + => await That(subject).Because("we want to test the failure"); + + await That(Act).Throws() + .WithMessage(""" + Expected that subject + is True, because we want to test the failure, + but it was False + """); + } + + [Fact] + public async Task WhenTrue_ShouldSucceed() + { + bool subject = true; + + async Task Act() + => await That(subject); + + await That(Act).DoesNotThrow(); + } + } +*/ +}