diff --git a/Source/aweXpect/That/ThatGeneric.IsEquatableTo.cs b/Source/aweXpect/That/ThatGeneric.IsEquatableTo.cs
new file mode 100644
index 000000000..bea9730af
--- /dev/null
+++ b/Source/aweXpect/That/ThatGeneric.IsEquatableTo.cs
@@ -0,0 +1,74 @@
+using System;
+using aweXpect.Core;
+using aweXpect.Core.Constraints;
+using aweXpect.Helpers;
+using aweXpect.Results;
+
+namespace aweXpect;
+
+public static partial class ThatGeneric
+{
+ ///
+ /// Verifies that the subject is equal to the value
+ /// using the method.
+ ///
+ public static AndOrResult> IsEquatableTo(
+ this IThat source,
+ T expected)
+ where TEquatable : IEquatable
+ => new(source.Get().ExpectationBuilder.AddConstraint((it, grammars)
+ => new IsEquatableToConstraint(it, grammars, expected)),
+ source);
+
+ ///
+ /// Verifies that the subject is not equal to the value
+ /// using the method.
+ ///
+ public static AndOrResult> IsNotEquatableTo(
+ this IThat source,
+ T unexpected)
+ where TEquatable : IEquatable
+ => new(source.Get().ExpectationBuilder.AddConstraint((it, grammars)
+ => new IsEquatableToConstraint(it, grammars, unexpected).Invert()),
+ source);
+
+ private sealed class IsEquatableToConstraint(
+ string it,
+ ExpectationGrammars grammars,
+ T expected)
+ : ConstraintResult.WithValue>(grammars),
+ IValueConstraint
+ where TEquatable : IEquatable
+ {
+ public ConstraintResult IsMetBy(TEquatable actual)
+ {
+ Actual = actual;
+ Outcome = actual.Equals(expected) ? Outcome.Success : Outcome.Failure;
+ return this;
+ }
+
+ protected override void AppendNormalExpectation(StringBuilder stringBuilder, string? indentation = null)
+ {
+ stringBuilder.Append("is equatable to ");
+ Formatter.Format(stringBuilder, expected);
+ }
+
+ protected override void AppendNormalResult(StringBuilder stringBuilder, string? indentation = null)
+ {
+ stringBuilder.Append(it).Append(" was ");
+ Formatter.Format(stringBuilder, Actual);
+ }
+
+ protected override void AppendNegatedExpectation(StringBuilder stringBuilder, string? indentation = null)
+ {
+ stringBuilder.Append("is not equatable to ");
+ Formatter.Format(stringBuilder, expected);
+ }
+
+ protected override void AppendNegatedResult(StringBuilder stringBuilder, string? indentation = null)
+ {
+ stringBuilder.Append(it).Append(" was in ");
+ Formatter.Format(stringBuilder, Actual);
+ }
+ }
+}
diff --git a/Tests/aweXpect.Api.Tests/Expected/aweXpect_net8.0.txt b/Tests/aweXpect.Api.Tests/Expected/aweXpect_net8.0.txt
index 008ede787..43c593949 100644
--- a/Tests/aweXpect.Api.Tests/Expected/aweXpect_net8.0.txt
+++ b/Tests/aweXpect.Api.Tests/Expected/aweXpect_net8.0.txt
@@ -724,6 +724,10 @@ namespace aweXpect
public static aweXpect.Results.RepeatedCheckResult> DoesNotComplyWith(this aweXpect.Core.IThat source, System.Action> expectations) { }
public static aweXpect.Results.AndOrResult> DoesNotSatisfy(this aweXpect.Core.IThat source, System.Func predicate, [System.Runtime.CompilerServices.CallerArgumentExpression("predicate")] string doNotPopulateThisValue = "") { }
public static aweXpect.Results.AndOrResult> For(this aweXpect.Core.IThat source, System.Func memberSelector, System.Action> expectations, [System.Runtime.CompilerServices.CallerArgumentExpression("memberSelector")] string doNotPopulateThisValue = "") { }
+ public static aweXpect.Results.AndOrResult> IsEquatableTo(this aweXpect.Core.IThat source, T expected)
+ where TEquatable : System.IEquatable { }
+ public static aweXpect.Results.AndOrResult> IsNotEquatableTo(this aweXpect.Core.IThat source, T unexpected)
+ where TEquatable : System.IEquatable { }
public static aweXpect.Results.RepeatedCheckResult> Satisfies(this aweXpect.Core.IThat source, System.Func predicate, [System.Runtime.CompilerServices.CallerArgumentExpression("predicate")] string doNotPopulateThisValue = "") { }
}
public static class ThatGuid
diff --git a/Tests/aweXpect.Api.Tests/Expected/aweXpect_netstandard2.0.txt b/Tests/aweXpect.Api.Tests/Expected/aweXpect_netstandard2.0.txt
index c33f3ae16..f319217a3 100644
--- a/Tests/aweXpect.Api.Tests/Expected/aweXpect_netstandard2.0.txt
+++ b/Tests/aweXpect.Api.Tests/Expected/aweXpect_netstandard2.0.txt
@@ -487,6 +487,10 @@ namespace aweXpect
public static aweXpect.Results.RepeatedCheckResult> DoesNotComplyWith(this aweXpect.Core.IThat source, System.Action> expectations) { }
public static aweXpect.Results.AndOrResult> DoesNotSatisfy(this aweXpect.Core.IThat source, System.Func predicate, [System.Runtime.CompilerServices.CallerArgumentExpression("predicate")] string doNotPopulateThisValue = "") { }
public static aweXpect.Results.AndOrResult> For(this aweXpect.Core.IThat source, System.Func memberSelector, System.Action> expectations, [System.Runtime.CompilerServices.CallerArgumentExpression("memberSelector")] string doNotPopulateThisValue = "") { }
+ public static aweXpect.Results.AndOrResult> IsEquatableTo(this aweXpect.Core.IThat source, T expected)
+ where TEquatable : System.IEquatable { }
+ public static aweXpect.Results.AndOrResult> IsNotEquatableTo(this aweXpect.Core.IThat source, T unexpected)
+ where TEquatable : System.IEquatable { }
public static aweXpect.Results.RepeatedCheckResult> Satisfies(this aweXpect.Core.IThat source, System.Func predicate, [System.Runtime.CompilerServices.CallerArgumentExpression("predicate")] string doNotPopulateThisValue = "") { }
}
public static class ThatGuid
diff --git a/Tests/aweXpect.Tests/ThatGeneric.IsEquatableTo.Tests.cs b/Tests/aweXpect.Tests/ThatGeneric.IsEquatableTo.Tests.cs
new file mode 100644
index 000000000..f5b839f23
--- /dev/null
+++ b/Tests/aweXpect.Tests/ThatGeneric.IsEquatableTo.Tests.cs
@@ -0,0 +1,150 @@
+namespace aweXpect.Tests;
+
+public sealed partial class ThatGeneric
+{
+ public sealed class IsEquatableTo
+ {
+ public sealed class Tests
+ {
+ [Fact]
+ public async Task WhenComparingToMatchingLong_ShouldSucceed()
+ {
+ Wrapper subject = new(1);
+
+ async Task Act()
+ => await That(subject).IsEquatableTo(1L);
+
+ await That(Act).DoesNotThrow();
+ }
+
+ [Fact]
+ public async Task WhenComparingToMatchingWrapper_ShouldSucceed()
+ {
+ Wrapper subject = new(1);
+ Wrapper expected = new(1);
+
+ async Task Act()
+ => await That(subject).IsEquatableTo(expected);
+
+ await That(Act).DoesNotThrow();
+ }
+
+ [Fact]
+ public async Task WhenComparingToNotMatchingLong_ShouldFail()
+ {
+ Wrapper subject = new(1);
+
+ async Task Act()
+ => await That(subject).IsEquatableTo(2L);
+
+ await That(Act).Throws()
+ .WithMessage("""
+ Expected that subject
+ is equatable to 2,
+ but it was ThatGeneric.IsEquatableTo.Wrapper {
+ Value = 1
+ }
+ """);
+ }
+
+ [Fact]
+ public async Task WhenComparingToNotMatchingWrapper_ShouldFail()
+ {
+ Wrapper subject = new(1);
+ Wrapper expected = new(3);
+
+ async Task Act()
+ => await That(subject).IsEquatableTo(expected);
+
+ await That(Act).Throws()
+ .WithMessage("""
+ Expected that subject
+ is equatable to ThatGeneric.IsEquatableTo.Wrapper {
+ Value = 3
+ },
+ but it was ThatGeneric.IsEquatableTo.Wrapper {
+ Value = 1
+ }
+ """);
+ }
+ }
+
+ public sealed class NegatedTests
+ {
+ [Fact]
+ public async Task WhenComparingToMatchingLong_ShouldFail()
+ {
+ Wrapper subject = new(1);
+
+ async Task Act()
+ => await That(subject).DoesNotComplyWith(it => it.IsEquatableTo(1L));
+
+ await That(Act).Throws()
+ .WithMessage("""
+ Expected that subject
+ is not equatable to 1,
+ but it was in ThatGeneric.IsEquatableTo.Wrapper {
+ Value = 1
+ }
+ """);
+ }
+
+ [Fact]
+ public async Task WhenComparingToMatchingWrapper_ShouldFail()
+ {
+ Wrapper subject = new(1);
+ Wrapper expected = new(1);
+
+ async Task Act()
+ => await That(subject).DoesNotComplyWith(it => it.IsEquatableTo(expected));
+
+ await That(Act).Throws()
+ .WithMessage("""
+ Expected that subject
+ is not equatable to ThatGeneric.IsEquatableTo.Wrapper {
+ Value = 1
+ },
+ but it was in ThatGeneric.IsEquatableTo.Wrapper {
+ Value = 1
+ }
+ """);
+ }
+
+ [Fact]
+ public async Task WhenComparingToNotMatchingLong_ShouldSucceed()
+ {
+ Wrapper subject = new(1);
+
+ async Task Act()
+ => await That(subject).DoesNotComplyWith(it => it.IsEquatableTo(2L));
+
+ await That(Act).DoesNotThrow();
+ }
+
+ [Fact]
+ public async Task WhenComparingToNotMatchingWrapper_ShouldSucceed()
+ {
+ Wrapper subject = new(1);
+ Wrapper expected = new(3);
+
+ async Task Act()
+ => await That(subject).DoesNotComplyWith(it => it.IsEquatableTo(expected));
+
+ await That(Act).DoesNotThrow();
+ }
+ }
+
+ private readonly struct Wrapper(long value)
+ : IEquatable,
+ IEquatable
+ {
+ public long Value { get; } = value;
+
+ public bool Equals(Wrapper other)
+ => Value == other.Value;
+
+ public bool Equals(long other)
+ => Value == other;
+ }
+ }
+}
diff --git a/Tests/aweXpect.Tests/ThatGeneric.IsNotEquatableTo.Tests.cs b/Tests/aweXpect.Tests/ThatGeneric.IsNotEquatableTo.Tests.cs
new file mode 100644
index 000000000..6def14d0e
--- /dev/null
+++ b/Tests/aweXpect.Tests/ThatGeneric.IsNotEquatableTo.Tests.cs
@@ -0,0 +1,150 @@
+namespace aweXpect.Tests;
+
+public sealed partial class ThatGeneric
+{
+ public sealed class IsNotEquatableTo
+ {
+ public sealed class Tests
+ {
+ [Fact]
+ public async Task WhenComparingToMatchingLong_ShouldFail()
+ {
+ Wrapper subject = new(1);
+
+ async Task Act()
+ => await That(subject).IsNotEquatableTo(1L);
+
+ await That(Act).Throws()
+ .WithMessage("""
+ Expected that subject
+ is not equatable to 1,
+ but it was in ThatGeneric.IsNotEquatableTo.Wrapper {
+ Value = 1
+ }
+ """);
+ }
+
+ [Fact]
+ public async Task WhenComparingToMatchingWrapper_ShouldFail()
+ {
+ Wrapper subject = new(1);
+ Wrapper expected = new(1);
+
+ async Task Act()
+ => await That(subject).IsNotEquatableTo(expected);
+
+ await That(Act).Throws()
+ .WithMessage("""
+ Expected that subject
+ is not equatable to ThatGeneric.IsNotEquatableTo.Wrapper {
+ Value = 1
+ },
+ but it was in ThatGeneric.IsNotEquatableTo.Wrapper {
+ Value = 1
+ }
+ """);
+ }
+
+ [Fact]
+ public async Task WhenComparingToNotMatchingLong_ShouldSucceed()
+ {
+ Wrapper subject = new(1);
+
+ async Task Act()
+ => await That(subject).IsNotEquatableTo(2L);
+
+ await That(Act).DoesNotThrow();
+ }
+
+ [Fact]
+ public async Task WhenComparingToNotMatchingWrapper_ShouldSucceed()
+ {
+ Wrapper subject = new(1);
+ Wrapper expected = new(3);
+
+ async Task Act()
+ => await That(subject).IsNotEquatableTo(expected);
+
+ await That(Act).DoesNotThrow();
+ }
+ }
+
+ public sealed class NegatedTests
+ {
+ [Fact]
+ public async Task WhenComparingToMatchingLong_ShouldSucceed()
+ {
+ Wrapper subject = new(1);
+
+ async Task Act()
+ => await That(subject).DoesNotComplyWith(it => it.IsNotEquatableTo(1L));
+
+ await That(Act).DoesNotThrow();
+ }
+
+ [Fact]
+ public async Task WhenComparingToMatchingWrapper_ShouldSucceed()
+ {
+ Wrapper subject = new(1);
+ Wrapper expected = new(1);
+
+ async Task Act()
+ => await That(subject).DoesNotComplyWith(it => it.IsNotEquatableTo(expected));
+
+ await That(Act).DoesNotThrow();
+ }
+
+ [Fact]
+ public async Task WhenComparingToNotMatchingLong_ShouldFail()
+ {
+ Wrapper subject = new(1);
+
+ async Task Act()
+ => await That(subject).DoesNotComplyWith(it => it.IsNotEquatableTo(2L));
+
+ await That(Act).Throws()
+ .WithMessage("""
+ Expected that subject
+ is equatable to 2,
+ but it was ThatGeneric.IsNotEquatableTo.Wrapper {
+ Value = 1
+ }
+ """);
+ }
+
+ [Fact]
+ public async Task WhenComparingToNotMatchingWrapper_ShouldFail()
+ {
+ Wrapper subject = new(1);
+ Wrapper expected = new(3);
+
+ async Task Act()
+ => await That(subject).DoesNotComplyWith(it => it.IsNotEquatableTo(expected));
+
+ await That(Act).Throws()
+ .WithMessage("""
+ Expected that subject
+ is equatable to ThatGeneric.IsNotEquatableTo.Wrapper {
+ Value = 3
+ },
+ but it was ThatGeneric.IsNotEquatableTo.Wrapper {
+ Value = 1
+ }
+ """);
+ }
+ }
+
+ private readonly struct Wrapper(long value)
+ : IEquatable,
+ IEquatable
+ {
+ public long Value { get; } = value;
+
+ public bool Equals(Wrapper other)
+ => Value == other.Value;
+
+ public bool Equals(long other)
+ => Value == other;
+ }
+ }
+}