diff --git a/Src/FluentAssertions/Collections/GenericCollectionAssertions.cs b/Src/FluentAssertions/Collections/GenericCollectionAssertions.cs index aceb88ff45..aab4e55760 100644 --- a/Src/FluentAssertions/Collections/GenericCollectionAssertions.cs +++ b/Src/FluentAssertions/Collections/GenericCollectionAssertions.cs @@ -35,6 +35,8 @@ public GenericCollectionAssertions(TCollection actualValue) } } +#pragma warning disable CS0659 // Ignore not overriding Object.GetHashCode() +#pragma warning disable CA1065 // Ignore throwing NotSupportedException from Equals [DebuggerNonUserCode] public class GenericCollectionAssertions : ReferenceTypeAssertions @@ -3449,6 +3451,10 @@ private AndConstraint NotBeInOrder(IComparer comparer, SortOrder return new AndConstraint((TAssertions)this); } + /// + public override bool Equals(object obj) => + throw new NotSupportedException("Equals is not part of Fluent Assertions. Did you mean BeSameAs(), Equal(), or BeEquivalentTo() instead?"); + private static int IndexOf(IList items, T item, int startIndex) { Func comparer = ObjectExtensions.GetComparer(); diff --git a/Src/FluentAssertions/Numeric/NumericAssertions.cs b/Src/FluentAssertions/Numeric/NumericAssertions.cs index adf7ddabd3..84c2f79ab4 100644 --- a/Src/FluentAssertions/Numeric/NumericAssertions.cs +++ b/Src/FluentAssertions/Numeric/NumericAssertions.cs @@ -474,7 +474,7 @@ public AndConstraint NotBeOfType(Type unexpectedType, string becaus /// public override bool Equals(object obj) => - throw new NotSupportedException("Calling Equals on Assertion classes is not supported."); + throw new NotSupportedException("Equals is not part of Fluent Assertions. Did you mean Be() instead?"); private protected virtual bool IsNaN(T value) => false; diff --git a/Src/FluentAssertions/Primitives/BooleanAssertions.cs b/Src/FluentAssertions/Primitives/BooleanAssertions.cs index 77f92a78c9..5864de1590 100644 --- a/Src/FluentAssertions/Primitives/BooleanAssertions.cs +++ b/Src/FluentAssertions/Primitives/BooleanAssertions.cs @@ -120,5 +120,5 @@ public AndConstraint NotBe(bool unexpected, string because = "", pa /// public override bool Equals(object obj) => - throw new NotSupportedException("Calling Equals on Assertion classes is not supported."); + throw new NotSupportedException("Equals is not part of Fluent Assertions. Did you mean Be() instead?"); } diff --git a/Src/FluentAssertions/Primitives/DateOnlyAssertions.cs b/Src/FluentAssertions/Primitives/DateOnlyAssertions.cs index 7e8d38d1d1..84bb1189d2 100644 --- a/Src/FluentAssertions/Primitives/DateOnlyAssertions.cs +++ b/Src/FluentAssertions/Primitives/DateOnlyAssertions.cs @@ -512,7 +512,7 @@ public AndConstraint BeOneOf(IEnumerable validValues, st /// public override bool Equals(object obj) => - throw new NotSupportedException("Calling Equals on Assertion classes is not supported."); + throw new NotSupportedException("Equals is not part of Fluent Assertions. Did you mean Be() instead?"); } #endif diff --git a/Src/FluentAssertions/Primitives/DateTimeAssertions.cs b/Src/FluentAssertions/Primitives/DateTimeAssertions.cs index ae1444afb2..67cd63a310 100644 --- a/Src/FluentAssertions/Primitives/DateTimeAssertions.cs +++ b/Src/FluentAssertions/Primitives/DateTimeAssertions.cs @@ -925,5 +925,5 @@ public AndConstraint BeIn(DateTimeKind expectedKind, string because /// public override bool Equals(object obj) => - throw new NotSupportedException("Calling Equals on Assertion classes is not supported."); + throw new NotSupportedException("Equals is not part of Fluent Assertions. Did you mean Be() instead?"); } diff --git a/Src/FluentAssertions/Primitives/DateTimeOffsetAssertions.cs b/Src/FluentAssertions/Primitives/DateTimeOffsetAssertions.cs index c0f7585cfa..1f69c8e919 100644 --- a/Src/FluentAssertions/Primitives/DateTimeOffsetAssertions.cs +++ b/Src/FluentAssertions/Primitives/DateTimeOffsetAssertions.cs @@ -1094,5 +1094,5 @@ public AndConstraint BeOneOf(IEnumerable validValu /// public override bool Equals(object obj) => - throw new NotSupportedException("Calling Equals on Assertion classes is not supported."); + throw new NotSupportedException("Equals is not part of Fluent Assertions. Did you mean Be() instead?"); } diff --git a/Src/FluentAssertions/Primitives/DateTimeOffsetRangeAssertions.cs b/Src/FluentAssertions/Primitives/DateTimeOffsetRangeAssertions.cs index 30bf53b37c..84134ae086 100644 --- a/Src/FluentAssertions/Primitives/DateTimeOffsetRangeAssertions.cs +++ b/Src/FluentAssertions/Primitives/DateTimeOffsetRangeAssertions.cs @@ -132,5 +132,5 @@ private static string PositionRelativeToTarget(DateTimeOffset actual, DateTimeOf /// public override bool Equals(object obj) => - throw new NotSupportedException("Calling Equals on Assertion classes is not supported."); + throw new NotSupportedException("Equals is not part of Fluent Assertions. Did you mean Before() or After() instead?"); } diff --git a/Src/FluentAssertions/Primitives/DateTimeRangeAssertions.cs b/Src/FluentAssertions/Primitives/DateTimeRangeAssertions.cs index 13011f41e8..c42f06ecb8 100644 --- a/Src/FluentAssertions/Primitives/DateTimeRangeAssertions.cs +++ b/Src/FluentAssertions/Primitives/DateTimeRangeAssertions.cs @@ -135,5 +135,5 @@ private static string PositionRelativeToTarget(DateTime actual, DateTime target) /// public override bool Equals(object obj) => - throw new NotSupportedException("Calling Equals on Assertion classes is not supported."); + throw new NotSupportedException("Equals is not part of Fluent Assertions. Did you mean Before() or After() instead?"); } diff --git a/Src/FluentAssertions/Primitives/EnumAssertions.cs b/Src/FluentAssertions/Primitives/EnumAssertions.cs index 4802fdbf6f..f462c13296 100644 --- a/Src/FluentAssertions/Primitives/EnumAssertions.cs +++ b/Src/FluentAssertions/Primitives/EnumAssertions.cs @@ -443,5 +443,5 @@ private static string GetName(T @enum) /// public override bool Equals(object obj) => - throw new NotSupportedException("Calling Equals on Assertion classes is not supported."); + throw new NotSupportedException("Equals is not part of Fluent Assertions. Did you mean Be() instead?"); } diff --git a/Src/FluentAssertions/Primitives/GuidAssertions.cs b/Src/FluentAssertions/Primitives/GuidAssertions.cs index 651f2037be..2f086cf29c 100644 --- a/Src/FluentAssertions/Primitives/GuidAssertions.cs +++ b/Src/FluentAssertions/Primitives/GuidAssertions.cs @@ -171,5 +171,5 @@ public AndConstraint NotBe(Guid unexpected, string because = "", pa /// public override bool Equals(object obj) => - throw new NotSupportedException("Calling Equals on Assertion classes is not supported."); + throw new NotSupportedException("Equals is not part of Fluent Assertions. Did you mean Be() or BeOneOf() instead?"); } diff --git a/Src/FluentAssertions/Primitives/ObjectAssertions.cs b/Src/FluentAssertions/Primitives/ObjectAssertions.cs index 7205c0fcc1..91847aaa9c 100644 --- a/Src/FluentAssertions/Primitives/ObjectAssertions.cs +++ b/Src/FluentAssertions/Primitives/ObjectAssertions.cs @@ -17,6 +17,8 @@ public ObjectAssertions(object value) } } +#pragma warning disable CS0659 // Ignore not overriding Object.GetHashCode() +#pragma warning disable CA1065 // Ignore throwing NotSupportedException from Equals /// /// Contains a number of methods to assert that a is in the expected state. /// @@ -220,6 +222,10 @@ public AndConstraint NotBe(TSubject unexpected, string because = "" return new AndConstraint((TAssertions)this); } + /// + public override bool Equals(object obj) => + throw new NotSupportedException("Equals is not part of Fluent Assertions. Did you mean Be() or BeSameAs() instead?"); + /// /// Returns the type of the subject the assertion applies on. /// diff --git a/Src/FluentAssertions/Primitives/ReferenceTypeAssertions.cs b/Src/FluentAssertions/Primitives/ReferenceTypeAssertions.cs index 3b8a793d7e..9035f43976 100644 --- a/Src/FluentAssertions/Primitives/ReferenceTypeAssertions.cs +++ b/Src/FluentAssertions/Primitives/ReferenceTypeAssertions.cs @@ -422,5 +422,5 @@ public AndConstraint NotBeAssignableTo(Type type, string because = /// public override bool Equals(object obj) => - throw new NotSupportedException("Calling Equals on Assertion classes is not supported."); + throw new NotSupportedException("Equals is not part of Fluent Assertions. Did you mean BeSameAs() instead?"); } diff --git a/Src/FluentAssertions/Primitives/SimpleTimeSpanAssertions.cs b/Src/FluentAssertions/Primitives/SimpleTimeSpanAssertions.cs index 51fd604d3c..34bd206aaa 100644 --- a/Src/FluentAssertions/Primitives/SimpleTimeSpanAssertions.cs +++ b/Src/FluentAssertions/Primitives/SimpleTimeSpanAssertions.cs @@ -301,5 +301,5 @@ public AndConstraint BeGreaterThan(TimeSpan expected, string becaus /// public override bool Equals(object obj) => - throw new NotSupportedException("Calling Equals on Assertion classes is not supported."); + throw new NotSupportedException("Equals is not part of Fluent Assertions. Did you mean Be() instead?"); } diff --git a/Src/FluentAssertions/Primitives/TimeOnlyAssertions.cs b/Src/FluentAssertions/Primitives/TimeOnlyAssertions.cs index 4b2ed9ed2b..1a552dc901 100644 --- a/Src/FluentAssertions/Primitives/TimeOnlyAssertions.cs +++ b/Src/FluentAssertions/Primitives/TimeOnlyAssertions.cs @@ -566,7 +566,7 @@ public AndConstraint BeOneOf(IEnumerable validValues, st /// public override bool Equals(object obj) => - throw new NotSupportedException("Calling Equals on Assertion classes is not supported."); + throw new NotSupportedException("Equals is not part of Fluent Assertions. Did you mean Be() instead?"); } #endif diff --git a/Src/FluentAssertions/Specialized/ExecutionTimeAssertions.cs b/Src/FluentAssertions/Specialized/ExecutionTimeAssertions.cs index 1ff4e014e2..3f122ccde1 100644 --- a/Src/FluentAssertions/Specialized/ExecutionTimeAssertions.cs +++ b/Src/FluentAssertions/Specialized/ExecutionTimeAssertions.cs @@ -231,5 +231,5 @@ public AndConstraint BeCloseTo(TimeSpan expectedDuratio /// public override bool Equals(object obj) => - throw new NotSupportedException("Calling Equals on Assertion classes is not supported."); + throw new NotSupportedException("Equals is not part of Fluent Assertions. Did you mean BeLessThanOrEqualTo() or BeGreaterThanOrEqualTo() instead?"); } diff --git a/Src/FluentAssertions/Specialized/TaskCompletionSourceAssertions.cs b/Src/FluentAssertions/Specialized/TaskCompletionSourceAssertions.cs index 3adc8892a0..ae6a61ae83 100644 --- a/Src/FluentAssertions/Specialized/TaskCompletionSourceAssertions.cs +++ b/Src/FluentAssertions/Specialized/TaskCompletionSourceAssertions.cs @@ -184,7 +184,7 @@ protected TaskCompletionSourceAssertionsBase(IClock clock) /// public override bool Equals(object obj) => - throw new NotSupportedException("Calling Equals on Assertion classes is not supported."); + throw new NotSupportedException("Equals is not part of Fluent Assertions. Did you mean CompleteWithinAsync() instead?"); /// /// Monitors the specified task whether it completes withing the remaining time span. diff --git a/Src/FluentAssertions/Types/MethodInfoSelectorAssertions.cs b/Src/FluentAssertions/Types/MethodInfoSelectorAssertions.cs index 10f4820300..b6c86ae1dc 100644 --- a/Src/FluentAssertions/Types/MethodInfoSelectorAssertions.cs +++ b/Src/FluentAssertions/Types/MethodInfoSelectorAssertions.cs @@ -330,5 +330,5 @@ private static string GetDescriptionsFor(IEnumerable methods) /// public override bool Equals(object obj) => - throw new NotSupportedException("Calling Equals on Assertion classes is not supported."); + throw new NotSupportedException("Equals is not part of Fluent Assertions. Did you mean Be() instead?"); } diff --git a/Src/FluentAssertions/Types/PropertyInfoSelectorAssertions.cs b/Src/FluentAssertions/Types/PropertyInfoSelectorAssertions.cs index ce048a4011..3f276a939a 100644 --- a/Src/FluentAssertions/Types/PropertyInfoSelectorAssertions.cs +++ b/Src/FluentAssertions/Types/PropertyInfoSelectorAssertions.cs @@ -229,5 +229,5 @@ private static string GetDescriptionsFor(IEnumerable properties) /// public override bool Equals(object obj) => - throw new NotSupportedException("Calling Equals on Assertion classes is not supported."); + throw new NotSupportedException("Equals is not part of Fluent Assertions. Did you mean Be() instead?"); } diff --git a/Src/FluentAssertions/Types/TypeSelectorAssertions.cs b/Src/FluentAssertions/Types/TypeSelectorAssertions.cs index 6bf90d1cb4..dfe6d0f75b 100644 --- a/Src/FluentAssertions/Types/TypeSelectorAssertions.cs +++ b/Src/FluentAssertions/Types/TypeSelectorAssertions.cs @@ -477,5 +477,5 @@ private static string GetDescriptionFor(Type type) /// public override bool Equals(object obj) => - throw new NotSupportedException("Calling Equals on Assertion classes is not supported."); + throw new NotSupportedException("Equals is not part of Fluent Assertions. Did you mean BeInNamespace() or BeDecoratedWith() instead?"); } diff --git a/Tests/Approval.Tests/ApprovedApi/FluentAssertions/net47.verified.txt b/Tests/Approval.Tests/ApprovedApi/FluentAssertions/net47.verified.txt index 3567266697..efd909ba8f 100644 --- a/Tests/Approval.Tests/ApprovedApi/FluentAssertions/net47.verified.txt +++ b/Tests/Approval.Tests/ApprovedApi/FluentAssertions/net47.verified.txt @@ -463,6 +463,7 @@ namespace FluentAssertions.Collections public FluentAssertions.AndConstraint Equal(params T[] elements) { } public FluentAssertions.AndConstraint Equal(System.Collections.Generic.IEnumerable expected, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint Equal(System.Collections.Generic.IEnumerable expectation, System.Func equalityComparison, string because = "", params object[] becauseArgs) { } + public override bool Equals(object obj) { } public FluentAssertions.AndConstraint HaveCount(int expected, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint HaveCount(System.Linq.Expressions.Expression> countPredicate, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint HaveCountGreaterOrEqualTo(int expected, string because = "", params object[] becauseArgs) { } @@ -2100,6 +2101,7 @@ namespace FluentAssertions.Primitives public FluentAssertions.AndConstraint Be(TSubject expected, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint BeEquivalentTo(TExpectation expectation, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint BeEquivalentTo(TExpectation expectation, System.Func, FluentAssertions.Equivalency.EquivalencyAssertionOptions> config, string because = "", params object[] becauseArgs) { } + public override bool Equals(object obj) { } public FluentAssertions.AndConstraint NotBe(TSubject unexpected, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint NotBeEquivalentTo(TExpectation unexpected, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint NotBeEquivalentTo(TExpectation unexpected, System.Func, FluentAssertions.Equivalency.EquivalencyAssertionOptions> config, string because = "", params object[] becauseArgs) { } diff --git a/Tests/Approval.Tests/ApprovedApi/FluentAssertions/net6.0.verified.txt b/Tests/Approval.Tests/ApprovedApi/FluentAssertions/net6.0.verified.txt index c6cf598019..4a3bf00561 100644 --- a/Tests/Approval.Tests/ApprovedApi/FluentAssertions/net6.0.verified.txt +++ b/Tests/Approval.Tests/ApprovedApi/FluentAssertions/net6.0.verified.txt @@ -476,6 +476,7 @@ namespace FluentAssertions.Collections public FluentAssertions.AndConstraint Equal(params T[] elements) { } public FluentAssertions.AndConstraint Equal(System.Collections.Generic.IEnumerable expected, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint Equal(System.Collections.Generic.IEnumerable expectation, System.Func equalityComparison, string because = "", params object[] becauseArgs) { } + public override bool Equals(object obj) { } public FluentAssertions.AndConstraint HaveCount(int expected, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint HaveCount(System.Linq.Expressions.Expression> countPredicate, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint HaveCountGreaterOrEqualTo(int expected, string because = "", params object[] becauseArgs) { } @@ -2184,6 +2185,7 @@ namespace FluentAssertions.Primitives public FluentAssertions.AndConstraint Be(TSubject expected, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint BeEquivalentTo(TExpectation expectation, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint BeEquivalentTo(TExpectation expectation, System.Func, FluentAssertions.Equivalency.EquivalencyAssertionOptions> config, string because = "", params object[] becauseArgs) { } + public override bool Equals(object obj) { } public FluentAssertions.AndConstraint NotBe(TSubject unexpected, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint NotBeEquivalentTo(TExpectation unexpected, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint NotBeEquivalentTo(TExpectation unexpected, System.Func, FluentAssertions.Equivalency.EquivalencyAssertionOptions> config, string because = "", params object[] becauseArgs) { } diff --git a/Tests/Approval.Tests/ApprovedApi/FluentAssertions/netcoreapp2.1.verified.txt b/Tests/Approval.Tests/ApprovedApi/FluentAssertions/netcoreapp2.1.verified.txt index 5adc56dd10..fac6192f15 100644 --- a/Tests/Approval.Tests/ApprovedApi/FluentAssertions/netcoreapp2.1.verified.txt +++ b/Tests/Approval.Tests/ApprovedApi/FluentAssertions/netcoreapp2.1.verified.txt @@ -463,6 +463,7 @@ namespace FluentAssertions.Collections public FluentAssertions.AndConstraint Equal(params T[] elements) { } public FluentAssertions.AndConstraint Equal(System.Collections.Generic.IEnumerable expected, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint Equal(System.Collections.Generic.IEnumerable expectation, System.Func equalityComparison, string because = "", params object[] becauseArgs) { } + public override bool Equals(object obj) { } public FluentAssertions.AndConstraint HaveCount(int expected, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint HaveCount(System.Linq.Expressions.Expression> countPredicate, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint HaveCountGreaterOrEqualTo(int expected, string because = "", params object[] becauseArgs) { } @@ -2100,6 +2101,7 @@ namespace FluentAssertions.Primitives public FluentAssertions.AndConstraint Be(TSubject expected, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint BeEquivalentTo(TExpectation expectation, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint BeEquivalentTo(TExpectation expectation, System.Func, FluentAssertions.Equivalency.EquivalencyAssertionOptions> config, string because = "", params object[] becauseArgs) { } + public override bool Equals(object obj) { } public FluentAssertions.AndConstraint NotBe(TSubject unexpected, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint NotBeEquivalentTo(TExpectation unexpected, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint NotBeEquivalentTo(TExpectation unexpected, System.Func, FluentAssertions.Equivalency.EquivalencyAssertionOptions> config, string because = "", params object[] becauseArgs) { } diff --git a/Tests/Approval.Tests/ApprovedApi/FluentAssertions/netcoreapp3.0.verified.txt b/Tests/Approval.Tests/ApprovedApi/FluentAssertions/netcoreapp3.0.verified.txt index 9c2cee42c9..22d306e8da 100644 --- a/Tests/Approval.Tests/ApprovedApi/FluentAssertions/netcoreapp3.0.verified.txt +++ b/Tests/Approval.Tests/ApprovedApi/FluentAssertions/netcoreapp3.0.verified.txt @@ -463,6 +463,7 @@ namespace FluentAssertions.Collections public FluentAssertions.AndConstraint Equal(params T[] elements) { } public FluentAssertions.AndConstraint Equal(System.Collections.Generic.IEnumerable expected, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint Equal(System.Collections.Generic.IEnumerable expectation, System.Func equalityComparison, string because = "", params object[] becauseArgs) { } + public override bool Equals(object obj) { } public FluentAssertions.AndConstraint HaveCount(int expected, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint HaveCount(System.Linq.Expressions.Expression> countPredicate, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint HaveCountGreaterOrEqualTo(int expected, string because = "", params object[] becauseArgs) { } @@ -2100,6 +2101,7 @@ namespace FluentAssertions.Primitives public FluentAssertions.AndConstraint Be(TSubject expected, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint BeEquivalentTo(TExpectation expectation, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint BeEquivalentTo(TExpectation expectation, System.Func, FluentAssertions.Equivalency.EquivalencyAssertionOptions> config, string because = "", params object[] becauseArgs) { } + public override bool Equals(object obj) { } public FluentAssertions.AndConstraint NotBe(TSubject unexpected, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint NotBeEquivalentTo(TExpectation unexpected, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint NotBeEquivalentTo(TExpectation unexpected, System.Func, FluentAssertions.Equivalency.EquivalencyAssertionOptions> config, string because = "", params object[] becauseArgs) { } diff --git a/Tests/Approval.Tests/ApprovedApi/FluentAssertions/netstandard2.0.verified.txt b/Tests/Approval.Tests/ApprovedApi/FluentAssertions/netstandard2.0.verified.txt index ee6d495c4a..924195ba5f 100644 --- a/Tests/Approval.Tests/ApprovedApi/FluentAssertions/netstandard2.0.verified.txt +++ b/Tests/Approval.Tests/ApprovedApi/FluentAssertions/netstandard2.0.verified.txt @@ -456,6 +456,7 @@ namespace FluentAssertions.Collections public FluentAssertions.AndConstraint Equal(params T[] elements) { } public FluentAssertions.AndConstraint Equal(System.Collections.Generic.IEnumerable expected, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint Equal(System.Collections.Generic.IEnumerable expectation, System.Func equalityComparison, string because = "", params object[] becauseArgs) { } + public override bool Equals(object obj) { } public FluentAssertions.AndConstraint HaveCount(int expected, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint HaveCount(System.Linq.Expressions.Expression> countPredicate, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint HaveCountGreaterOrEqualTo(int expected, string because = "", params object[] becauseArgs) { } @@ -2052,6 +2053,7 @@ namespace FluentAssertions.Primitives public FluentAssertions.AndConstraint Be(TSubject expected, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint BeEquivalentTo(TExpectation expectation, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint BeEquivalentTo(TExpectation expectation, System.Func, FluentAssertions.Equivalency.EquivalencyAssertionOptions> config, string because = "", params object[] becauseArgs) { } + public override bool Equals(object obj) { } public FluentAssertions.AndConstraint NotBe(TSubject unexpected, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint NotBeEquivalentTo(TExpectation unexpected, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint NotBeEquivalentTo(TExpectation unexpected, System.Func, FluentAssertions.Equivalency.EquivalencyAssertionOptions> config, string because = "", params object[] becauseArgs) { } diff --git a/Tests/Approval.Tests/ApprovedApi/FluentAssertions/netstandard2.1.verified.txt b/Tests/Approval.Tests/ApprovedApi/FluentAssertions/netstandard2.1.verified.txt index 4741d7b627..c3db12e985 100644 --- a/Tests/Approval.Tests/ApprovedApi/FluentAssertions/netstandard2.1.verified.txt +++ b/Tests/Approval.Tests/ApprovedApi/FluentAssertions/netstandard2.1.verified.txt @@ -463,6 +463,7 @@ namespace FluentAssertions.Collections public FluentAssertions.AndConstraint Equal(params T[] elements) { } public FluentAssertions.AndConstraint Equal(System.Collections.Generic.IEnumerable expected, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint Equal(System.Collections.Generic.IEnumerable expectation, System.Func equalityComparison, string because = "", params object[] becauseArgs) { } + public override bool Equals(object obj) { } public FluentAssertions.AndConstraint HaveCount(int expected, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint HaveCount(System.Linq.Expressions.Expression> countPredicate, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint HaveCountGreaterOrEqualTo(int expected, string because = "", params object[] becauseArgs) { } @@ -2100,6 +2101,7 @@ namespace FluentAssertions.Primitives public FluentAssertions.AndConstraint Be(TSubject expected, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint BeEquivalentTo(TExpectation expectation, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint BeEquivalentTo(TExpectation expectation, System.Func, FluentAssertions.Equivalency.EquivalencyAssertionOptions> config, string because = "", params object[] becauseArgs) { } + public override bool Equals(object obj) { } public FluentAssertions.AndConstraint NotBe(TSubject unexpected, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint NotBeEquivalentTo(TExpectation unexpected, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint NotBeEquivalentTo(TExpectation unexpected, System.Func, FluentAssertions.Equivalency.EquivalencyAssertionOptions> config, string because = "", params object[] becauseArgs) { } diff --git a/Tests/FluentAssertions.Specs/Collections/GenericCollectionAssertionOfStringSpecs.cs b/Tests/FluentAssertions.Specs/Collections/GenericCollectionAssertionOfStringSpecs.cs index ba6c244424..5d341eec6f 100644 --- a/Tests/FluentAssertions.Specs/Collections/GenericCollectionAssertionOfStringSpecs.cs +++ b/Tests/FluentAssertions.Specs/Collections/GenericCollectionAssertionOfStringSpecs.cs @@ -1984,4 +1984,17 @@ public void When_string_collection_does_not_satisfy_all_inspectors_it_should_thr } #endregion + + [Fact] + public void When_accidentally_using_equals_it_should_throw_a_helpful_error() + { + // Arrange + var someCollection = new List { "one", "two", "three" }; + + // Act + Action action = () => someCollection.Should().Equals(someCollection); + + // Assert + action.Should().Throw().WithMessage("Equals is not part of Fluent Assertions. Did you mean BeSameAs(), Equal(), or BeEquivalentTo() instead?"); + } } diff --git a/Tests/FluentAssertions.Specs/Numeric/NumericAssertionSpecs.cs b/Tests/FluentAssertions.Specs/Numeric/NumericAssertionSpecs.cs index 1936e03886..8d30d8fcbc 100644 --- a/Tests/FluentAssertions.Specs/Numeric/NumericAssertionSpecs.cs +++ b/Tests/FluentAssertions.Specs/Numeric/NumericAssertionSpecs.cs @@ -3963,4 +3963,17 @@ public void When_chaining_constraints_with_and_should_not_throw() // Assert action.Should().NotThrow(); } + + [Fact] + public void Should_throw_a_helpful_error_when_accidentally_using_equals() + { + // Arrange + int value = 1; + + // Act + Action action = () => value.Should().Equals(1); + + // Assert + action.Should().Throw().WithMessage("Equals is not part of Fluent Assertions. Did you mean Be() instead?"); + } } diff --git a/Tests/FluentAssertions.Specs/Primitives/BooleanAssertionSpecs.cs b/Tests/FluentAssertions.Specs/Primitives/BooleanAssertionSpecs.cs index fa7ca04a52..5dac3340c6 100644 --- a/Tests/FluentAssertions.Specs/Primitives/BooleanAssertionSpecs.cs +++ b/Tests/FluentAssertions.Specs/Primitives/BooleanAssertionSpecs.cs @@ -143,4 +143,14 @@ public void Should_fail_with_descriptive_message_when_asserting_boolean_value_no action.Should().Throw() .WithMessage("*Expected*boolean*True*because we want to test the failure message, but found True.*"); } + + [Fact] + public void Should_throw_a_helpful_error_when_accidentally_using_equals() + { + // Act + Action action = () => true.Should().Equals(true); + + // Assert + action.Should().Throw().WithMessage("Equals is not part of Fluent Assertions. Did you mean Be() instead?"); + } } diff --git a/Tests/FluentAssertions.Specs/Primitives/DateOnlyAssertionSpecs.cs b/Tests/FluentAssertions.Specs/Primitives/DateOnlyAssertionSpecs.cs index 20fefb8b06..823a98b013 100644 --- a/Tests/FluentAssertions.Specs/Primitives/DateOnlyAssertionSpecs.cs +++ b/Tests/FluentAssertions.Specs/Primitives/DateOnlyAssertionSpecs.cs @@ -771,6 +771,22 @@ public void Should_support_chaining_constraints_with_and() .BeAfter(earlierDateOnly); } } + + public class Miscellaneous + { + [Fact] + public void Should_throw_a_helpful_error_when_accidentally_using_equals() + { + // Arrange + DateOnly someDateOnly = new(2022, 9, 25); + + // Act + Action action = () => someDateOnly.Should().Equals(someDateOnly); + + // Assert + action.Should().Throw().WithMessage("Equals is not part of Fluent Assertions. Did you mean Be() instead?"); + } + } } #endif diff --git a/Tests/FluentAssertions.Specs/Primitives/DateTimeAssertionSpecs.cs b/Tests/FluentAssertions.Specs/Primitives/DateTimeAssertionSpecs.cs index 28774a5c00..0a83d093fb 100644 --- a/Tests/FluentAssertions.Specs/Primitives/DateTimeAssertionSpecs.cs +++ b/Tests/FluentAssertions.Specs/Primitives/DateTimeAssertionSpecs.cs @@ -1390,7 +1390,7 @@ public void When_asserting_subject_null_datetime_should_have_day_should_throw() } } - public class BotHaveDay + public class NotHaveDay { [Fact] public void When_asserting_subject_datetime_should_not_have_day_with_the_same_value_it_should_throw() @@ -2294,4 +2294,33 @@ public void When_a_value_is_one_of_the_specified_values_it_should_succeed_when_d action.Should().NotThrow(); } } + + public class Miscellaneous + { + [Fact] + public void Should_throw_a_helpful_error_when_accidentally_using_equals() + { + // Arrange + DateTime someDateTime = new(2022, 9, 25, 13, 38, 42, DateTimeKind.Utc); + + // Act + Action action = () => someDateTime.Should().Equals(someDateTime); + + // Assert + action.Should().Throw().WithMessage("Equals is not part of Fluent Assertions. Did you mean Be() instead?"); + } + + [Fact] + public void Should_throw_a_helpful_error_when_accidentally_using_equals_with_a_range() + { + // Arrange + DateTime someDateTime = new(2022, 9, 25, 13, 38, 42, DateTimeKind.Utc); + + // Act + Action action = () => someDateTime.Should().BeLessThan(0.Seconds()).Equals(someDateTime); + + // Assert + action.Should().Throw().WithMessage("Equals is not part of Fluent Assertions. Did you mean Before() or After() instead?"); + } + } } diff --git a/Tests/FluentAssertions.Specs/Primitives/DateTimeOffsetAssertionSpecs.cs b/Tests/FluentAssertions.Specs/Primitives/DateTimeOffsetAssertionSpecs.cs index 0945a60b5e..343aa00fae 100644 --- a/Tests/FluentAssertions.Specs/Primitives/DateTimeOffsetAssertionSpecs.cs +++ b/Tests/FluentAssertions.Specs/Primitives/DateTimeOffsetAssertionSpecs.cs @@ -2437,6 +2437,19 @@ public void When_asserting_subject_be_less_than_10_seconds_before_target_but_sub action.Should().Throw() .WithMessage("Expected subject <00:00:45 +0h> to be less than 10s before <00:00:30 +0h>, but it is ahead by 15s."); } + + [Fact] + public void Should_throw_a_helpful_error_when_accidentally_using_equals_with_a_range() + { + // Arrange + DateTimeOffset someDateTimeOffset = new(2022, 9, 25, 13, 48, 42, 0, TimeSpan.Zero); + + // Act + Action action = () => someDateTimeOffset.Should().BeLessThan(0.Seconds()).Equals(someDateTimeOffset); + + // Assert + action.Should().Throw().WithMessage("Equals is not part of Fluent Assertions. Did you mean Before() or After() instead?"); + } } public class ChainingConstraint @@ -2530,4 +2543,20 @@ public void When_a_value_is_one_of_the_specified_values_it_should_succeed_when_d action.Should().NotThrow(); } } + + public class Miscellaneous + { + [Fact] + public void Should_throw_a_helpful_error_when_accidentally_using_equals() + { + // Arrange + DateTimeOffset someDateTimeOffset = new(2022, 9, 25, 13, 48, 42, 0, TimeSpan.Zero); + + // Act + Action action = () => someDateTimeOffset.Should().Equals(someDateTimeOffset); + + // Assert + action.Should().Throw().WithMessage("Equals is not part of Fluent Assertions. Did you mean Be() instead?"); + } + } } diff --git a/Tests/FluentAssertions.Specs/Primitives/EnumAssertionSpecs.cs b/Tests/FluentAssertions.Specs/Primitives/EnumAssertionSpecs.cs index 96652e30eb..f00823cd9c 100644 --- a/Tests/FluentAssertions.Specs/Primitives/EnumAssertionSpecs.cs +++ b/Tests/FluentAssertions.Specs/Primitives/EnumAssertionSpecs.cs @@ -883,4 +883,20 @@ public void A_null_value_of_an_enum_is_not_defined_and_throws() .WithMessage("Did not expect *to be defined in*, but found ."); } } + + public class Miscellaneous + { + [Fact] + public void Should_throw_a_helpful_error_when_accidentally_using_equals() + { + // Arrange + MyEnum? subject = null; + + // Act + Action action = () => subject.Should().Equals(subject); + + // Assert + action.Should().Throw().WithMessage("Equals is not part of Fluent Assertions. Did you mean Be() instead?"); + } + } } diff --git a/Tests/FluentAssertions.Specs/Primitives/GuidAssertionSpecs.cs b/Tests/FluentAssertions.Specs/Primitives/GuidAssertionSpecs.cs index f7b3164188..47ce833458 100644 --- a/Tests/FluentAssertions.Specs/Primitives/GuidAssertionSpecs.cs +++ b/Tests/FluentAssertions.Specs/Primitives/GuidAssertionSpecs.cs @@ -209,4 +209,20 @@ public void Should_support_chaining_constraints_with_and() .And.Be(guid); } } + + public class Miscellaneous + { + [Fact] + public void Should_throw_a_helpful_error_when_accidentally_using_equals() + { + // Arrange + Guid subject = Guid.Empty; + + // Act + Action action = () => subject.Should().Equals(subject); + + // Assert + action.Should().Throw().WithMessage("Equals is not part of Fluent Assertions. Did you mean Be() or BeOneOf() instead?"); + } + } } diff --git a/Tests/FluentAssertions.Specs/Primitives/ObjectAssertionSpecs.cs b/Tests/FluentAssertions.Specs/Primitives/ObjectAssertionSpecs.cs index 7bf45dae2d..91a9715f2a 100644 --- a/Tests/FluentAssertions.Specs/Primitives/ObjectAssertionSpecs.cs +++ b/Tests/FluentAssertions.Specs/Primitives/ObjectAssertionSpecs.cs @@ -836,6 +836,19 @@ public void Should_support_chaining_constraints_with_and() .And .NotBeNull(); } + + [Fact] + public void Should_throw_a_helpful_error_when_accidentally_using_equals() + { + // Arrange + var someObject = new Exception(); + + // Act + Action action = () => someObject.Should().Equals(someObject); + + // Assert + action.Should().Throw().WithMessage("Equals is not part of Fluent Assertions. Did you mean Be() or BeSameAs() instead?"); + } } public class BeBinarySerializable diff --git a/Tests/FluentAssertions.Specs/Primitives/ReferenceTypeAssertionsSpecs.cs b/Tests/FluentAssertions.Specs/Primitives/ReferenceTypeAssertionsSpecs.cs index 87cb70a754..9f3256ee1d 100644 --- a/Tests/FluentAssertions.Specs/Primitives/ReferenceTypeAssertionsSpecs.cs +++ b/Tests/FluentAssertions.Specs/Primitives/ReferenceTypeAssertionsSpecs.cs @@ -1,6 +1,7 @@ using System; using FluentAssertions.Execution; using FluentAssertions.Extensions; +using FluentAssertions.Primitives; using Xunit; using Xunit.Sdk; @@ -407,6 +408,30 @@ public void When_an_assertion_on_two_unknown_objects_fails_it_should_report_the_ } #endregion + + public class Miscellaneous + { + [Fact] + public void Should_throw_a_helpful_error_when_accidentally_using_equals() + { + // Arrange + var subject = new ReferenceTypeAssertionsDummy(null); + + // Act + Action action = () => subject.Equals(subject); + + // Assert + action.Should().Throw().WithMessage("Equals is not part of Fluent Assertions. Did you mean BeSameAs() instead?"); + } + + public class ReferenceTypeAssertionsDummy : ReferenceTypeAssertions + { + public ReferenceTypeAssertionsDummy(object subject) + : base(subject) { } + + protected override string Identifier => string.Empty; + } + } } public class SomeDto diff --git a/Tests/FluentAssertions.Specs/Primitives/SimpleTimeSpanAssertionSpecs.cs b/Tests/FluentAssertions.Specs/Primitives/SimpleTimeSpanAssertionSpecs.cs index 279e377cc9..70ab3416bb 100644 --- a/Tests/FluentAssertions.Specs/Primitives/SimpleTimeSpanAssertionSpecs.cs +++ b/Tests/FluentAssertions.Specs/Primitives/SimpleTimeSpanAssertionSpecs.cs @@ -515,6 +515,19 @@ public void When_asserting_value_to_be_less_than_or_equal_to_smaller_value_it_sh "Expected actual to be less than or equal to 1s because we want to test the failure message, but found 2s."); } + [Fact] + public void When_accidentally_using_equals_it_should_throw_a_helpful_error() + { + // Arrange + TimeSpan someTimeSpan = 2.Seconds(); + + // Act + Action act = () => someTimeSpan.Should().Equals(someTimeSpan); + + // Assert + act.Should().Throw().WithMessage("Equals is not part of Fluent Assertions. Did you mean Be() instead?"); + } + #region Be Close To [Fact] diff --git a/Tests/FluentAssertions.Specs/Primitives/TimeOnlyAssertionSpecs.cs b/Tests/FluentAssertions.Specs/Primitives/TimeOnlyAssertionSpecs.cs index f36e0366d7..5004451aae 100644 --- a/Tests/FluentAssertions.Specs/Primitives/TimeOnlyAssertionSpecs.cs +++ b/Tests/FluentAssertions.Specs/Primitives/TimeOnlyAssertionSpecs.cs @@ -855,6 +855,22 @@ public void Should_support_chaining_constraints_with_and() .BeAfter(earlierTimeOnly); } } + + public class Miscellaneous + { + [Fact] + public void Should_throw_a_helpful_error_when_accidentally_using_equals() + { + // Arrange + TimeOnly someTimeOnly = new(21, 1); + + // Act + Action act = () => someTimeOnly.Should().Equals(someTimeOnly); + + // Assert + act.Should().Throw().WithMessage("Equals is not part of Fluent Assertions. Did you mean Be() instead?"); + } + } } #endif diff --git a/Tests/FluentAssertions.Specs/Specialized/ExecutionTimeAssertionsSpecs.cs b/Tests/FluentAssertions.Specs/Specialized/ExecutionTimeAssertionsSpecs.cs index 9224b67664..92d7c340a2 100644 --- a/Tests/FluentAssertions.Specs/Specialized/ExecutionTimeAssertionsSpecs.cs +++ b/Tests/FluentAssertions.Specs/Specialized/ExecutionTimeAssertionsSpecs.cs @@ -615,6 +615,19 @@ public void When_asserting_execution_time_of_null_it_should_throw() act.Should().ThrowExactly() .WithParameterName("action"); } + + [Fact] + public void When_accidentally_using_equals_it_should_throw_a_helpful_error() + { + // Arrange + var subject = new object(); + + // Act + Action act = () => subject.ExecutionTimeOf(s => s.ToString()).Should().Equals(1.Seconds()); + + // Assert + act.Should().Throw().WithMessage("Equals is not part of Fluent Assertions. Did you mean BeLessThanOrEqualTo() or BeGreaterThanOrEqualTo() instead?"); + } } internal class SleepingClass diff --git a/Tests/FluentAssertions.Specs/Specialized/TaskCompletionSourceAssertionSpecs.cs b/Tests/FluentAssertions.Specs/Specialized/TaskCompletionSourceAssertionSpecs.cs index ca0409a405..7520f1a565 100644 --- a/Tests/FluentAssertions.Specs/Specialized/TaskCompletionSourceAssertionSpecs.cs +++ b/Tests/FluentAssertions.Specs/Specialized/TaskCompletionSourceAssertionSpecs.cs @@ -102,6 +102,19 @@ public async Task When_it_is_null_and_we_validate_to_not_complete_it_should_fail await action.Should().ThrowAsync() .WithMessage("Expected subject to not complete within 1s because test testArg, but found ."); } + + [Fact] + public async Task When_accidentally_using_equals_it_should_throw_a_helpful_error() + { + // Arrange + var subject = new TaskCompletionSource(); + + // Act + Func action = () => Task.FromResult(subject.Should().Equals(subject)); + + // Assert + await action.Should().ThrowAsync().WithMessage("Equals is not part of Fluent Assertions. Did you mean CompleteWithinAsync() instead?"); + } } #endif @@ -264,5 +277,18 @@ public async Task When_it_is_null_and_we_validate_to_not_complete_it_should_fail await action.Should().ThrowAsync() .WithMessage("Did not expect subject to complete within 1s because test testArg, but found ."); } + + [Fact] + public async Task When_accidentally_using_equals_with_generic_it_should_throw_a_helpful_error() + { + // Arrange + var subject = new TaskCompletionSource(); + + // Act + Func> action = () => Task.FromResult(subject.Should().Equals(subject)); + + // Assert + await action.Should().ThrowAsync().WithMessage("Equals is not part of Fluent Assertions. Did you mean CompleteWithinAsync() instead?"); + } } } diff --git a/Tests/FluentAssertions.Specs/Types/MethodInfoSelectorSpecs.cs b/Tests/FluentAssertions.Specs/Types/MethodInfoSelectorSpecs.cs index 86acad481b..05a3ee9586 100644 --- a/Tests/FluentAssertions.Specs/Types/MethodInfoSelectorSpecs.cs +++ b/Tests/FluentAssertions.Specs/Types/MethodInfoSelectorSpecs.cs @@ -390,6 +390,19 @@ public void When_selecting_methods_return_types_it_should_return_the_correct_typ .And.Contain(typeof(int)) .And.Contain(typeof(string)); } + + [Fact] + public void When_accidentally_using_equals_it_should_throw_a_helpful_error() + { + // Arrange + Type type = typeof(TestClassForMethodSelector); + + // Act + Action action = () => type.Methods().Should().Equals(null); + + // Assert + action.Should().Throw().WithMessage("Equals is not part of Fluent Assertions. Did you mean Be() instead?"); + } } #region Internal classes used in unit tests diff --git a/Tests/FluentAssertions.Specs/Types/PropertyInfoSelectorAssertionSpecs.cs b/Tests/FluentAssertions.Specs/Types/PropertyInfoSelectorAssertionSpecs.cs index a9568ecc0b..3f775420ae 100644 --- a/Tests/FluentAssertions.Specs/Types/PropertyInfoSelectorAssertionSpecs.cs +++ b/Tests/FluentAssertions.Specs/Types/PropertyInfoSelectorAssertionSpecs.cs @@ -288,6 +288,22 @@ public void When_read_only_properties_are_expected_to_not_be_writable_it_should_ action.Should().NotThrow(); } } + + public class Miscellaneous + { + [Fact] + public void When_accidentally_using_equals_it_should_throw_a_helpful_error() + { + // Arrange + var someObject = new PropertyInfoSelectorAssertions(); + + // Act + Action action = () => someObject.Equals(someObject); + + // Assert + action.Should().Throw().WithMessage("Equals is not part of Fluent Assertions. Did you mean Be() instead?"); + } + } } #region Internal classes used in unit tests diff --git a/Tests/FluentAssertions.Specs/Types/TypeSelectorAssertionSpecs.cs b/Tests/FluentAssertions.Specs/Types/TypeSelectorAssertionSpecs.cs index 6ab8ac0030..15c6720f5d 100644 --- a/Tests/FluentAssertions.Specs/Types/TypeSelectorAssertionSpecs.cs +++ b/Tests/FluentAssertions.Specs/Types/TypeSelectorAssertionSpecs.cs @@ -789,4 +789,23 @@ public void When_a_type_only_shares_a_prefix_with_the_unexpected_namespace_it_sh act.Should().NotThrow(); } } + + public class Miscellaneous + { + [Fact] + public void When_accidentally_using_equals_it_should_throw_a_helpful_error() + { + // Arrange + var types = new TypeSelector(new[] + { + typeof(ClassWithAttribute) + }); + + // Act + Action action = () => types.Should().Equals(types); + + // Assert + action.Should().Throw().WithMessage("Equals is not part of Fluent Assertions. Did you mean BeInNamespace() or BeDecoratedWith() instead?"); + } + } } diff --git a/docs/_pages/releases.md b/docs/_pages/releases.md index 756cc3f235..8d6e8fc48d 100644 --- a/docs/_pages/releases.md +++ b/docs/_pages/releases.md @@ -14,6 +14,7 @@ sidebar: * Added `NotCompleteWithinAsync` for assertions on `Task` - [#1967](https://github.com/fluentassertions/fluentassertions/pull/1967) * Added `CompleteWithinAsync` and `NotCompleteWithinAsync` for non-generic `TaskCompletionSource` (.NET 6 and above) - [#1961](https://github.com/fluentassertions/fluentassertions/pull/1961) * Added a `ParentType` to `IObjectInfo` to help determining the parent in a call to `Using`/`When` constructs - [#1950](https://github.com/fluentassertions/fluentassertions/pull/1950) +* Updated exception messages to provide suggestions when incorrectly using `Equals()` - [#2006](https://github.com/fluentassertions/fluentassertions/pull/2006) ### Fixes * Fixed `For`/`Exclude` not excluding properties in objects in a collection - [#1953](https://github.com/fluentassertions/fluentassertions/pull/1953)