diff --git a/Build/Build.cs b/Build/Build.cs index a523146572..29b8e4ee15 100644 --- a/Build/Build.cs +++ b/Build/Build.cs @@ -76,11 +76,14 @@ class Build : NukeBuild .DependsOn(Compile) .Executes(() => { - Xunit2(s => s - .SetFramework("net47") - .AddTargetAssemblies(GlobFiles( - Solution.Specs.FluentAssertions_Specs.Directory, - "bin/Debug/net47/*.Specs.dll").NotEmpty())); + if (EnvironmentInfo.IsWin) + { + Xunit2(s => s + .SetFramework("net47") + .AddTargetAssemblies(GlobFiles( + Solution.Specs.FluentAssertions_Specs.Directory, + "bin/Debug/net47/*.Specs.dll").NotEmpty())); + } DotNetTest(s => s .SetProjectFile(Solution.Specs.FluentAssertions_Specs) @@ -95,20 +98,30 @@ class Build : NukeBuild .DependsOn(Compile) .Executes(() => { + var testCombinations = + from project in new[] + { + Solution.TestFrameworks.MSpec_Specs, + Solution.TestFrameworks.MSTestV2_Specs, + Solution.TestFrameworks.NUnit3_Specs, + Solution.TestFrameworks.XUnit2_Specs + } + let frameworks = project.GetTargetFrameworks() + let supportedFrameworks = EnvironmentInfo.IsWin ? frameworks : frameworks.Except(new[] { "net47" }) + from framework in supportedFrameworks + select new { project, framework }; + DotNetTest(s => s .SetConfiguration("Debug") .EnableNoBuild() .CombineWith( - new[] - { - Solution.TestFrameworks.MSpec_Specs, - Solution.TestFrameworks.MSTestV2_Specs, - Solution.TestFrameworks.NUnit3_Specs, - Solution.TestFrameworks.XUnit2_Specs - }, - (_, v) => _.SetProjectFile(v))); + testCombinations, + (_, v) => _.SetProjectFile(v.project).SetFramework(v.framework))); - NSpec3(Solution.TestFrameworks.NSpec3_Net47_Specs.Directory / "bin" / "Debug" / "net47" / "NSpec3.Specs.dll"); + if (EnvironmentInfo.IsWin) + { + NSpec3(Solution.TestFrameworks.NSpec3_Net47_Specs.Directory / "bin" / "Debug" / "net47" / "NSpec3.Specs.dll"); + } }); Target Pack => _ => _ diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 0b6fa14d30..d78fee1965 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -2,9 +2,9 @@ No open-source project is going to be successful without contributions. After we decided to move to Github, the involvement of the .NET community has increased significantly. However, contributing to this project involves a few steps that will seriously increase the chance we will accept it. -* The [Pull Request](https://help.github.com/articles/using-pull-requests) is targeted at the `develop` branch. +* The [Pull Request](https://help.github.com/articles/using-pull-requests) is targeted at the `master` branch. * The code complies with the [Coding Guidelines for C#](https://csharpcodingguidelines.com/). * The changes are covered by a new or existing set of unit tests which follow the Arrange-Act-Assert syntax such as is used [in this example](https://github.com/fluentassertions/fluentassertions/blob/daaf35b9b59b622c96d0c034e8972a020b2bee55/Tests/FluentAssertions.Shared.Specs/BasicEquivalencySpecs.cs#L33). -* If the contribution adds a feature or fixes a bug, please update the [**release notes**](https://github.com/fluentassertions/fluentassertions/blob/develop/docs/_pages/releases.md), which is published on the [website](https://fluentassertions.com/releases). -* If the contribution changes the public API the changes needs to be included by running [`AcceptApiChanges.ps1`](https://github.com/fluentassertions/fluentassertions/tree/develop/AcceptApiChanges.ps1)/[`AcceptApiChanges.sh`](https://github.com/fluentassertions/fluentassertions/tree/develop/AcceptApiChanges.sh). -* If the contribution affects the documentation, please update the [**documentation**](https://github.com/fluentassertions/fluentassertions/tree/develop/docs/_pages), under the appropriate file (i.e. [strings.md](https://github.com/fluentassertions/fluentassertions/blob/develop/docs/_pages/strings.md) for changes to string assertions), which is published on the [website](https://fluentassertions.com/introduction). +* If the contribution adds a feature or fixes a bug, please update the [**release notes**](https://github.com/fluentassertions/fluentassertions/blob/master/docs/_pages/releases.md), which is published on the [website](https://fluentassertions.com/releases). +* If the contribution changes the public API the changes needs to be included by running [`AcceptApiChanges.ps1`](https://github.com/fluentassertions/fluentassertions/tree/master/AcceptApiChanges.ps1)/[`AcceptApiChanges.sh`](https://github.com/fluentassertions/fluentassertions/tree/master/AcceptApiChanges.sh). +* If the contribution affects the documentation, please update the [**documentation**](https://github.com/fluentassertions/fluentassertions/tree/master/docs/_pages), under the appropriate file (i.e. [strings.md](https://github.com/fluentassertions/fluentassertions/blob/master/docs/_pages/strings.md) for changes to string assertions), which is published on the [website](https://fluentassertions.com/introduction). diff --git a/Src/FluentAssertions/Collections/GenericCollectionAssertions.cs b/Src/FluentAssertions/Collections/GenericCollectionAssertions.cs index b08a563007..ff75c7090d 100644 --- a/Src/FluentAssertions/Collections/GenericCollectionAssertions.cs +++ b/Src/FluentAssertions/Collections/GenericCollectionAssertions.cs @@ -1005,7 +1005,8 @@ public AndWhichConstraint ContainSingle(string because = "", par if (success) { - switch (Subject.Count()) + ICollection actualItems = Subject.ConvertOrCastToCollection(); + switch (actualItems.Count) { case 0: // Fail, Collection is empty Execute.Assertion @@ -1013,7 +1014,7 @@ public AndWhichConstraint ContainSingle(string because = "", par .FailWith("Expected {context:collection} to contain a single item{reason}, but the collection is empty."); break; case 1: // Success Condition - match = Subject.SingleOrDefault(); + match = actualItems.Single(); break; default: // Fail, Collection contains more than a single item Execute.Assertion @@ -1229,8 +1230,8 @@ public AndConstraint HaveCount(int expected, string because = "", p .ForCondition(actualCount == expected) .BecauseOf(because, becauseArgs) .FailWith( - "Expected {context:collection} {0} to contain {1} item(s){reason}, but found {2}.", - Subject, expected, actualCount); + "Expected {context:collection} to contain {0} item(s){reason}, but found {1}: {2}.", + expected, actualCount, Subject); } return new AndConstraint((TAssertions)this); @@ -1268,8 +1269,8 @@ public AndConstraint HaveCount(Expression> countPre { Execute.Assertion .BecauseOf(because, becauseArgs) - .FailWith("Expected {context:collection} {0} to have a count {1}{reason}, but count is {2}.", - Subject, countPredicate.Body, actualCount); + .FailWith("Expected {context:collection} to have a count {0}{reason}, but count is {1}: {2}.", + countPredicate.Body, actualCount, Subject); } } @@ -1298,7 +1299,7 @@ public AndConstraint HaveCountGreaterThanOrEqualTo(int expected, st .Then .Given(subject => subject.Count()) .ForCondition(actualCount => actualCount >= expected) - .FailWith("but found {0}.", actualCount => actualCount) + .FailWith("but found {0}: {1}.", actualCount => actualCount, _ => Subject) .Then .ClearExpectation(); @@ -1330,7 +1331,7 @@ public AndConstraint HaveCountGreaterThan(int expected, string beca .Then .Given(subject => subject.Count()) .ForCondition(actualCount => actualCount > expected) - .FailWith("but found {0}.", actualCount => actualCount) + .FailWith("but found {0}: {1}.", actualCount => actualCount, _ => Subject) .Then .ClearExpectation(); @@ -1359,7 +1360,7 @@ public AndConstraint HaveCountLessThanOrEqualTo(int expected, strin .Then .Given(subject => subject.Count()) .ForCondition(actualCount => actualCount <= expected) - .FailWith("but found {0}.", actualCount => actualCount) + .FailWith("but found {0}: {1}.", actualCount => actualCount, _ => Subject) .Then .ClearExpectation(); @@ -1391,7 +1392,7 @@ public AndConstraint HaveCountLessThan(int expected, string because .Then .Given(subject => subject.Count()) .ForCondition(actualCount => actualCount < expected) - .FailWith("but found {0}.", actualCount => actualCount) + .FailWith("but found {0}: {1}.", actualCount => actualCount, _ => Subject) .Then .ClearExpectation(); @@ -2430,7 +2431,7 @@ public AndConstraint NotEqual(IEnumerable unexpected, string bec .Then .Given(subject => subject.ConvertOrCastToCollection()) .ForCondition(actualItems => !actualItems.SequenceEqual(unexpected)) - .FailWith("Did not expect collections {0} and {1} to be equal{reason}.", actualItems => unexpected, actualItems => actualItems); + .FailWith("Did not expect collections {0} and {1} to be equal{reason}.", _ => unexpected, actualItems => actualItems); return new AndConstraint((TAssertions)this); } @@ -2492,7 +2493,7 @@ public AndConstraint NotHaveSameCount(IEnumerable !ReferenceEquals(subject, otherCollection)) .FailWith( "Expected {context:collection} {0} to not have the same count as {1}{reason}, but they both reference the same object.", - subject => subject, subject => otherCollection) + subject => subject, _ => otherCollection) .Then .Given(subject => (actual: subject.Count(), expected: otherCollection.Count())) .ForCondition(count => count.actual != count.expected) @@ -2531,13 +2532,13 @@ public AndConstraint NotIntersectWith(IEnumerable otherCollectio .ForCondition(subject => !ReferenceEquals(subject, otherCollection)) .FailWith( "Did not expect {context:collection} {0} to intersect with {1}{reason}, but they both reference the same object.", - subject => subject, subject => otherCollection) + subject => subject, _ => otherCollection) .Then .Given(subject => subject.Intersect(otherCollection)) .ForCondition(sharedItems => !sharedItems.Any()) .FailWith( "Did not expect {context:collection} to intersect with {0}{reason}, but found the following shared items {1}.", - sharedItems => otherCollection, sharedItems => sharedItems); + _ => otherCollection, sharedItems => sharedItems); return new AndConstraint((TAssertions)this); } diff --git a/Src/FluentAssertions/Common/TypeExtensions.cs b/Src/FluentAssertions/Common/TypeExtensions.cs index 3d512e4055..82e56943eb 100644 --- a/Src/FluentAssertions/Common/TypeExtensions.cs +++ b/Src/FluentAssertions/Common/TypeExtensions.cs @@ -217,7 +217,7 @@ public static IEnumerable GetNonPrivateMembers(this Type typeToRefle public static IEnumerable GetNonPrivateProperties(this Type typeToReflect, MemberVisibility visibility) { - return NonPrivatePropertiesCache.GetOrAdd((typeToReflect, visibility), key => + return NonPrivatePropertiesCache.GetOrAdd((typeToReflect, visibility), static key => { IEnumerable query = from propertyInfo in GetPropertiesFromHierarchy(key.Type, key.Visibility) @@ -245,7 +245,7 @@ private static IEnumerable GetPropertiesFromHierarchy(Type typeToR public static IEnumerable GetNonPrivateFields(this Type typeToReflect, MemberVisibility visibility) { - return NonPrivateFieldsCache.GetOrAdd((typeToReflect, visibility), key => + return NonPrivateFieldsCache.GetOrAdd((typeToReflect, visibility), static key => { IEnumerable query = from fieldInfo in GetFieldsFromHierarchy(key.Type, key.Visibility) @@ -533,7 +533,7 @@ public static MethodInfo GetImplicitConversionOperator(this Type type, Type sour public static bool HasValueSemantics(this Type type) { - return HasValueSemanticsCache.GetOrAdd(type, t => + return HasValueSemanticsCache.GetOrAdd(type, static t => t.OverridesEquals() && !t.IsAnonymousType() && !t.IsTuple() && @@ -583,7 +583,7 @@ private static bool IsAnonymousType(this Type type) public static bool IsRecord(this Type type) { - return TypeIsRecordCache.GetOrAdd(type, t => + return TypeIsRecordCache.GetOrAdd(type, static t => t.GetMethod("$") is not null && t.GetTypeInfo() .DeclaredProperties diff --git a/Src/FluentAssertions/Equivalency/SelfReferenceEquivalencyAssertionOptions.cs b/Src/FluentAssertions/Equivalency/SelfReferenceEquivalencyAssertionOptions.cs index 22077ea8bb..8e0df96248 100644 --- a/Src/FluentAssertions/Equivalency/SelfReferenceEquivalencyAssertionOptions.cs +++ b/Src/FluentAssertions/Equivalency/SelfReferenceEquivalencyAssertionOptions.cs @@ -166,6 +166,8 @@ IEnumerable IEquivalencyAssertionOptions.SelectionRules EqualityStrategy IEquivalencyAssertionOptions.GetEqualityStrategy(Type requestedType) { + // As the valueFactory parameter captures instance members, + // be aware if the cache must be cleared on mutating the members. return equalityStrategyCache.GetOrAdd(requestedType, type => { EqualityStrategy strategy; diff --git a/Src/FluentAssertions/Equivalency/Steps/DictionaryInterfaceInfo.cs b/Src/FluentAssertions/Equivalency/Steps/DictionaryInterfaceInfo.cs index c59c576367..6a92d1a1e4 100644 --- a/Src/FluentAssertions/Equivalency/Steps/DictionaryInterfaceInfo.cs +++ b/Src/FluentAssertions/Equivalency/Steps/DictionaryInterfaceInfo.cs @@ -95,7 +95,7 @@ public static bool TryGetFromWithKey(Type target, string role, Type key, out Dic private static DictionaryInterfaceInfo[] GetDictionaryInterfacesFrom(Type target) { - return Cache.GetOrAdd(target, key => + return Cache.GetOrAdd(target, static key => { if (Type.GetTypeCode(key) != TypeCode.Object) { diff --git a/Src/FluentAssertions/Numeric/NumericAssertions.cs b/Src/FluentAssertions/Numeric/NumericAssertions.cs index f0a230a1be..842f08a374 100644 --- a/Src/FluentAssertions/Numeric/NumericAssertions.cs +++ b/Src/FluentAssertions/Numeric/NumericAssertions.cs @@ -22,6 +22,8 @@ public NumericAssertions(T 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 an is in the expected state. /// @@ -443,5 +445,9 @@ public AndConstraint Match(Expression> predicate, return new AndConstraint((TAssertions)this); } + + /// + public override bool Equals(object obj) => + throw new NotSupportedException("Calling Equals on Assertion classes is not supported."); } } diff --git a/Src/FluentAssertions/Primitives/BooleanAssertions.cs b/Src/FluentAssertions/Primitives/BooleanAssertions.cs index d90fd80170..732ba3830b 100644 --- a/Src/FluentAssertions/Primitives/BooleanAssertions.cs +++ b/Src/FluentAssertions/Primitives/BooleanAssertions.cs @@ -1,4 +1,5 @@ -using System.Diagnostics; +using System; +using System.Diagnostics; using FluentAssertions.Execution; namespace FluentAssertions.Primitives @@ -16,6 +17,8 @@ public BooleanAssertions(bool? 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. /// @@ -114,5 +117,9 @@ public AndConstraint NotBe(bool unexpected, string because = "", pa return new AndConstraint((TAssertions)this); } + + /// + public override bool Equals(object obj) => + throw new NotSupportedException("Calling Equals on Assertion classes is not supported."); } } diff --git a/Src/FluentAssertions/Primitives/DateTimeAssertions.cs b/Src/FluentAssertions/Primitives/DateTimeAssertions.cs index 8d9a15a955..f40c2032f0 100644 --- a/Src/FluentAssertions/Primitives/DateTimeAssertions.cs +++ b/Src/FluentAssertions/Primitives/DateTimeAssertions.cs @@ -22,6 +22,8 @@ public DateTimeAssertions(DateTime? 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. /// @@ -920,5 +922,9 @@ public AndConstraint BeIn(DateTimeKind expectedKind, string because return new AndConstraint((TAssertions)this); } + + /// + public override bool Equals(object obj) => + throw new NotSupportedException("Calling Equals on Assertion classes is not supported."); } } diff --git a/Src/FluentAssertions/Primitives/DateTimeOffsetAssertions.cs b/Src/FluentAssertions/Primitives/DateTimeOffsetAssertions.cs index 33e57e59c7..4272688927 100644 --- a/Src/FluentAssertions/Primitives/DateTimeOffsetAssertions.cs +++ b/Src/FluentAssertions/Primitives/DateTimeOffsetAssertions.cs @@ -23,6 +23,8 @@ public DateTimeOffsetAssertions(DateTimeOffset? 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. /// @@ -1089,5 +1091,9 @@ public AndConstraint BeOneOf(IEnumerable validValu return new AndConstraint((TAssertions)this); } + + /// + public override bool Equals(object obj) => + throw new NotSupportedException("Calling Equals on Assertion classes is not supported."); } } diff --git a/Src/FluentAssertions/Primitives/DateTimeOffsetRangeAssertions.cs b/Src/FluentAssertions/Primitives/DateTimeOffsetRangeAssertions.cs index 652b2ecb76..587da0ce20 100644 --- a/Src/FluentAssertions/Primitives/DateTimeOffsetRangeAssertions.cs +++ b/Src/FluentAssertions/Primitives/DateTimeOffsetRangeAssertions.cs @@ -6,6 +6,8 @@ namespace FluentAssertions.Primitives { +#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 two objects differ in the expected way. /// @@ -127,5 +129,9 @@ private static string PositionRelativeToTarget(DateTimeOffset actual, DateTimeOf { return actual - target >= TimeSpan.Zero ? "ahead" : "behind"; } + + /// + public override bool Equals(object obj) => + throw new NotSupportedException("Calling Equals on Assertion classes is not supported."); } } diff --git a/Src/FluentAssertions/Primitives/DateTimeRangeAssertions.cs b/Src/FluentAssertions/Primitives/DateTimeRangeAssertions.cs index 76bbd0a836..4d483f4f7f 100644 --- a/Src/FluentAssertions/Primitives/DateTimeRangeAssertions.cs +++ b/Src/FluentAssertions/Primitives/DateTimeRangeAssertions.cs @@ -5,6 +5,8 @@ namespace FluentAssertions.Primitives { +#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 two objects differ in the expected way. /// @@ -130,5 +132,9 @@ private static string PositionRelativeToTarget(DateTime actual, DateTime target) { return actual - target >= TimeSpan.Zero ? "ahead" : "behind"; } + + /// + public override bool Equals(object obj) => + throw new NotSupportedException("Calling Equals on Assertion classes is not supported."); } } diff --git a/Src/FluentAssertions/Primitives/EnumAssertions.cs b/Src/FluentAssertions/Primitives/EnumAssertions.cs index c2d3715858..c072123095 100644 --- a/Src/FluentAssertions/Primitives/EnumAssertions.cs +++ b/Src/FluentAssertions/Primitives/EnumAssertions.cs @@ -20,6 +20,8 @@ public EnumAssertions(TEnum subject) } } +#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. /// @@ -386,5 +388,9 @@ private static string GetName(T @enum) { return @enum.ToString(); } + + /// + public override bool Equals(object obj) => + throw new NotSupportedException("Calling Equals on Assertion classes is not supported."); } } diff --git a/Src/FluentAssertions/Primitives/GuidAssertions.cs b/Src/FluentAssertions/Primitives/GuidAssertions.cs index 2cd1914087..4d7e0ebc6e 100644 --- a/Src/FluentAssertions/Primitives/GuidAssertions.cs +++ b/Src/FluentAssertions/Primitives/GuidAssertions.cs @@ -16,6 +16,8 @@ public GuidAssertions(Guid? 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 correct state. /// @@ -166,5 +168,9 @@ public AndConstraint NotBe(Guid unexpected, string because = "", pa } #endregion + + /// + public override bool Equals(object obj) => + throw new NotSupportedException("Calling Equals on Assertion classes is not supported."); } } diff --git a/Src/FluentAssertions/Primitives/ReferenceTypeAssertions.cs b/Src/FluentAssertions/Primitives/ReferenceTypeAssertions.cs index 2eb7fae525..b3a56a1e56 100644 --- a/Src/FluentAssertions/Primitives/ReferenceTypeAssertions.cs +++ b/Src/FluentAssertions/Primitives/ReferenceTypeAssertions.cs @@ -6,6 +6,8 @@ namespace FluentAssertions.Primitives { +#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 reference type object is in the expected state. /// @@ -416,5 +418,9 @@ public AndConstraint Match(Expression> predicate, /// Returns the type of the subject the assertion applies on. /// protected abstract string Identifier { get; } + + /// + public override bool Equals(object obj) => + throw new NotSupportedException("Calling Equals on Assertion classes is not supported."); } } diff --git a/Src/FluentAssertions/Primitives/SimpleTimeSpanAssertions.cs b/Src/FluentAssertions/Primitives/SimpleTimeSpanAssertions.cs index 023e091714..9def21a654 100644 --- a/Src/FluentAssertions/Primitives/SimpleTimeSpanAssertions.cs +++ b/Src/FluentAssertions/Primitives/SimpleTimeSpanAssertions.cs @@ -17,6 +17,8 @@ public SimpleTimeSpanAssertions(TimeSpan? 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 nullable is in the expected state. /// @@ -338,5 +340,9 @@ public AndConstraint NotBeCloseTo(TimeSpan distantTime, TimeSpan pr return new AndConstraint((TAssertions)this); } + + /// + public override bool Equals(object obj) => + throw new NotSupportedException("Calling Equals on Assertion classes is not supported."); } } diff --git a/Src/FluentAssertions/Specialized/AsyncFunctionAssertions.cs b/Src/FluentAssertions/Specialized/AsyncFunctionAssertions.cs index 6cad4cea81..7981b77f65 100644 --- a/Src/FluentAssertions/Specialized/AsyncFunctionAssertions.cs +++ b/Src/FluentAssertions/Specialized/AsyncFunctionAssertions.cs @@ -46,22 +46,32 @@ public async Task> CompleteWithinAsync( .BecauseOf(because, becauseArgs) .FailWith("Expected {context:task} to complete within {0}{reason}, but found .", timeSpan); - using var timeoutCancellationTokenSource = new CancellationTokenSource(); + ITimer timer = Clock.StartTimer(); TTask task = Subject.Invoke(); + TimeSpan remainingTime = timeSpan - timer.Elapsed; - Task completedTask = - await Task.WhenAny(task, Clock.DelayAsync(timeSpan, timeoutCancellationTokenSource.Token)); + bool success = Execute.Assertion + .ForCondition(remainingTime >= TimeSpan.Zero) + .BecauseOf(because, becauseArgs) + .FailWith("Expected {context:task} to complete within {0}{reason}.", timeSpan); - if (completedTask == task) + if (success) { - timeoutCancellationTokenSource.Cancel(); - await completedTask; - } + using var timeoutCancellationTokenSource = new CancellationTokenSource(); + Task completedTask = + await Task.WhenAny(task, Clock.DelayAsync(remainingTime, timeoutCancellationTokenSource.Token)); - Execute.Assertion - .ForCondition(completedTask == task) - .BecauseOf(because, becauseArgs) - .FailWith("Expected {context:task} to complete within {0}{reason}.", timeSpan); + if (completedTask == task) + { + timeoutCancellationTokenSource.Cancel(); + await completedTask; + } + + Execute.Assertion + .ForCondition(completedTask == task) + .BecauseOf(because, becauseArgs) + .FailWith("Expected {context:task} to complete within {0}{reason}.", timeSpan); + } return new AndConstraint((TAssertions)this); } diff --git a/Src/FluentAssertions/Specialized/ExecutionTimeAssertions.cs b/Src/FluentAssertions/Specialized/ExecutionTimeAssertions.cs index 507e49e2c1..2c5b15692b 100644 --- a/Src/FluentAssertions/Specialized/ExecutionTimeAssertions.cs +++ b/Src/FluentAssertions/Specialized/ExecutionTimeAssertions.cs @@ -4,6 +4,8 @@ namespace FluentAssertions.Specialized { +#pragma warning disable CS0659 // Ignore not overriding Object.GetHashCode() +#pragma warning disable CA1065 // Ignore throwing NotSupportedException from Equals /// /// Provides methods for asserting that the execution time of an satisfies certain conditions. /// @@ -225,5 +227,9 @@ public AndConstraint BeCloseTo(TimeSpan expectedDuratio return new AndConstraint(this); } + + /// + public override bool Equals(object obj) => + throw new NotSupportedException("Calling Equals on Assertion classes is not supported."); } } diff --git a/Src/FluentAssertions/Specialized/FunctionAssertionHelpers.cs b/Src/FluentAssertions/Specialized/FunctionAssertionHelpers.cs index 5dc6da999a..58e008ddbd 100644 --- a/Src/FluentAssertions/Specialized/FunctionAssertionHelpers.cs +++ b/Src/FluentAssertions/Specialized/FunctionAssertionHelpers.cs @@ -4,7 +4,7 @@ namespace FluentAssertions.Specialized { - internal class FunctionAssertionHelpers + internal static class FunctionAssertionHelpers { internal static T NotThrow(Func subject, string because, object[] becauseArgs) { diff --git a/Src/FluentAssertions/Specialized/GenericAsyncFunctionAssertions.cs b/Src/FluentAssertions/Specialized/GenericAsyncFunctionAssertions.cs index 94470654ce..bc9e9a8948 100644 --- a/Src/FluentAssertions/Specialized/GenericAsyncFunctionAssertions.cs +++ b/Src/FluentAssertions/Specialized/GenericAsyncFunctionAssertions.cs @@ -37,22 +37,32 @@ public GenericAsyncFunctionAssertions(Func> subject, IExtractExcep .BecauseOf(because, becauseArgs) .FailWith("Expected {context} to complete within {0}{reason}, but found .", timeSpan); - using var timeoutCancellationTokenSource = new CancellationTokenSource(); + ITimer timer = Clock.StartTimer(); Task task = Subject.Invoke(); + TimeSpan remainingTime = timeSpan - timer.Elapsed; - Task completedTask = - await Task.WhenAny(task, Clock.DelayAsync(timeSpan, timeoutCancellationTokenSource.Token)); + bool success = Execute.Assertion + .ForCondition(remainingTime >= TimeSpan.Zero) + .BecauseOf(because, becauseArgs) + .FailWith("Expected {context:task} to complete within {0}{reason}.", timeSpan); - if (completedTask == task) + if (success) { - timeoutCancellationTokenSource.Cancel(); - await completedTask; - } + using var timeoutCancellationTokenSource = new CancellationTokenSource(); + Task completedTask = + await Task.WhenAny(task, Clock.DelayAsync(remainingTime, timeoutCancellationTokenSource.Token)); - Execute.Assertion - .ForCondition(completedTask == task) - .BecauseOf(because, becauseArgs) - .FailWith("Expected {context:task} to complete within {0}{reason}.", timeSpan); + if (completedTask == task) + { + timeoutCancellationTokenSource.Cancel(); + await completedTask; + } + + Execute.Assertion + .ForCondition(completedTask == task) + .BecauseOf(because, becauseArgs) + .FailWith("Expected {context:task} to complete within {0}{reason}.", timeSpan); + } return new AndWhichConstraint, TResult>(this, task.Result); } diff --git a/Src/FluentAssertions/Specialized/TaskCompletionSourceAssertions.cs b/Src/FluentAssertions/Specialized/TaskCompletionSourceAssertions.cs index 1c7d0ddbdb..f64c16f50a 100644 --- a/Src/FluentAssertions/Specialized/TaskCompletionSourceAssertions.cs +++ b/Src/FluentAssertions/Specialized/TaskCompletionSourceAssertions.cs @@ -6,6 +6,8 @@ namespace FluentAssertions.Specialized { +#pragma warning disable CS0659 // Ignore not overriding Object.GetHashCode() +#pragma warning disable CA1065 // Ignore throwing NotSupportedException from Equals public class TaskCompletionSourceAssertions { private readonly TaskCompletionSource subject; @@ -95,5 +97,9 @@ public async Task NotCompleteWithinAsync( .BecauseOf(because, becauseArgs) .FailWith("Expected {context:task} to not complete within {0}{reason}.", timeSpan); } + + /// + public override bool Equals(object obj) => + throw new NotSupportedException("Calling Equals on Assertion classes is not supported."); } } diff --git a/Src/FluentAssertions/Types/MethodInfoSelector.cs b/Src/FluentAssertions/Types/MethodInfoSelector.cs index d10ee543d9..e3ba8ca102 100644 --- a/Src/FluentAssertions/Types/MethodInfoSelector.cs +++ b/Src/FluentAssertions/Types/MethodInfoSelector.cs @@ -133,6 +133,42 @@ public MethodInfoSelector ThatAreNotDecoratedWithOrInherit() return this; } + /// + /// Only return methods that are async. + /// + public MethodInfoSelector ThatAreAsync() + { + selectedMethods = selectedMethods.Where(method => method.IsAsync()); + return this; + } + + /// + /// Only return methods that are not async. + /// + public MethodInfoSelector ThatAreNotAsync() + { + selectedMethods = selectedMethods.Where(method => !method.IsAsync()); + return this; + } + + /// + /// Only return methods that are virtual. + /// + public MethodInfoSelector ThatAreVirtual() + { + selectedMethods = selectedMethods.Where(method => !method.IsNonVirtual()); + return this; + } + + /// + /// Only return methods that are not virtual. + /// + public MethodInfoSelector ThatAreNotVirtual() + { + selectedMethods = selectedMethods.Where(method => method.IsNonVirtual()); + return this; + } + /// /// Select return types of the methods /// diff --git a/Src/FluentAssertions/Types/MethodInfoSelectorAssertions.cs b/Src/FluentAssertions/Types/MethodInfoSelectorAssertions.cs index 37e7f8209c..3af1f0a49a 100644 --- a/Src/FluentAssertions/Types/MethodInfoSelectorAssertions.cs +++ b/Src/FluentAssertions/Types/MethodInfoSelectorAssertions.cs @@ -9,6 +9,8 @@ namespace FluentAssertions.Types { +#pragma warning disable CS0659 // Ignore not overriding Object.GetHashCode() +#pragma warning disable CA1065 // Ignore throwing NotSupportedException from Equals /// /// Contains assertions for the objects returned by the parent . /// @@ -325,5 +327,9 @@ private static string GetDescriptionsFor(IEnumerable methods) #pragma warning disable CA1822 // Do not change signature of a public member protected string Context => "method"; #pragma warning restore CA1822 + + /// + public override bool Equals(object obj) => + throw new NotSupportedException("Calling Equals on Assertion classes is not supported."); } } diff --git a/Src/FluentAssertions/Types/PropertyInfoSelectorAssertions.cs b/Src/FluentAssertions/Types/PropertyInfoSelectorAssertions.cs index 2d9c12f08d..27b22710d2 100644 --- a/Src/FluentAssertions/Types/PropertyInfoSelectorAssertions.cs +++ b/Src/FluentAssertions/Types/PropertyInfoSelectorAssertions.cs @@ -8,6 +8,8 @@ namespace FluentAssertions.Types { +#pragma warning disable CS0659 // Ignore not overriding Object.GetHashCode() +#pragma warning disable CA1065 // Ignore throwing NotSupportedException from Equals /// /// Contains assertions for the objects returned by the parent . /// @@ -224,5 +226,9 @@ private static string GetDescriptionsFor(IEnumerable properties) #pragma warning disable CA1822 // Do not change signature of a public member protected string Context => "property info"; #pragma warning restore CA1822 + + /// + public override bool Equals(object obj) => + throw new NotSupportedException("Calling Equals on Assertion classes is not supported."); } } diff --git a/Src/FluentAssertions/Types/TypeSelectorAssertions.cs b/Src/FluentAssertions/Types/TypeSelectorAssertions.cs index 822f377237..9e99e15a3c 100644 --- a/Src/FluentAssertions/Types/TypeSelectorAssertions.cs +++ b/Src/FluentAssertions/Types/TypeSelectorAssertions.cs @@ -8,6 +8,8 @@ namespace FluentAssertions.Types { +#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 all s in a /// meet certain expectations. @@ -472,5 +474,9 @@ private static string GetDescriptionFor(Type type) { return type.ToString(); } + + /// + public override bool Equals(object obj) => + throw new NotSupportedException("Calling Equals on Assertion classes is not supported."); } } diff --git a/Tests/Approval.Tests/ApprovedApi/FluentAssertions/net47.verified.txt b/Tests/Approval.Tests/ApprovedApi/FluentAssertions/net47.verified.txt index f4ea4fb655..ee73949aa0 100644 --- a/Tests/Approval.Tests/ApprovedApi/FluentAssertions/net47.verified.txt +++ b/Tests/Approval.Tests/ApprovedApi/FluentAssertions/net47.verified.txt @@ -1716,6 +1716,7 @@ namespace FluentAssertions.Numeric public FluentAssertions.AndConstraint BeOneOf(params T[] validValues) { } public FluentAssertions.AndConstraint BeOneOf(System.Collections.Generic.IEnumerable validValues, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint BePositive(string because = "", params object[] becauseArgs) { } + public override bool Equals(object obj) { } public FluentAssertions.AndConstraint Match(System.Linq.Expressions.Expression> predicate, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint NotBe(T unexpected, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint NotBe(T? unexpected, string because = "", params object[] becauseArgs) { } @@ -1737,6 +1738,7 @@ namespace FluentAssertions.Primitives public FluentAssertions.AndConstraint Be(bool expected, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint BeFalse(string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint BeTrue(string because = "", params object[] becauseArgs) { } + public override bool Equals(object obj) { } public FluentAssertions.AndConstraint NotBe(bool unexpected, string because = "", params object[] becauseArgs) { } } public class DateTimeAssertions : FluentAssertions.Primitives.DateTimeAssertions @@ -1766,6 +1768,7 @@ namespace FluentAssertions.Primitives public FluentAssertions.AndConstraint BeOneOf(System.Collections.Generic.IEnumerable validValues, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint BeSameDateAs(System.DateTime expected, string because = "", params object[] becauseArgs) { } public FluentAssertions.Primitives.DateTimeRangeAssertions BeWithin(System.TimeSpan timeSpan) { } + public override bool Equals(object obj) { } public FluentAssertions.AndConstraint HaveDay(int expected, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint HaveHour(int expected, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint HaveMinute(int expected, string because = "", params object[] becauseArgs) { } @@ -1815,6 +1818,7 @@ namespace FluentAssertions.Primitives public FluentAssertions.AndConstraint BeOneOf(System.Collections.Generic.IEnumerable validValues, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint BeSameDateAs(System.DateTimeOffset expected, string because = "", params object[] becauseArgs) { } public FluentAssertions.Primitives.DateTimeOffsetRangeAssertions BeWithin(System.TimeSpan timeSpan) { } + public override bool Equals(object obj) { } public FluentAssertions.AndConstraint HaveDay(int expected, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint HaveHour(int expected, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint HaveMinute(int expected, string because = "", params object[] becauseArgs) { } @@ -1846,6 +1850,7 @@ namespace FluentAssertions.Primitives protected DateTimeOffsetRangeAssertions(TAssertions parentAssertions, System.DateTimeOffset? subject, FluentAssertions.Primitives.TimeSpanCondition condition, System.TimeSpan timeSpan) { } public FluentAssertions.AndConstraint After(System.DateTimeOffset target, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint Before(System.DateTimeOffset target, string because = "", params object[] becauseArgs) { } + public override bool Equals(object obj) { } } public class DateTimeRangeAssertions where TAssertions : FluentAssertions.Primitives.DateTimeAssertions @@ -1853,6 +1858,7 @@ namespace FluentAssertions.Primitives protected DateTimeRangeAssertions(TAssertions parentAssertions, System.DateTime? subject, FluentAssertions.Primitives.TimeSpanCondition condition, System.TimeSpan timeSpan) { } public FluentAssertions.AndConstraint After(System.DateTime target, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint Before(System.DateTime target, string because = "", params object[] becauseArgs) { } + public override bool Equals(object obj) { } } public class EnumAssertions : FluentAssertions.Primitives.EnumAssertions> where TEnum : struct, System.Enum @@ -1869,6 +1875,7 @@ namespace FluentAssertions.Primitives public FluentAssertions.AndConstraint Be(TEnum? expected, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint BeOneOf(params TEnum[] validValues) { } public FluentAssertions.AndConstraint BeOneOf(System.Collections.Generic.IEnumerable validValues, string because = "", params object[] becauseArgs) { } + public override bool Equals(object obj) { } public FluentAssertions.AndConstraint HaveFlag(TEnum expectedFlag, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint HaveSameNameAs(T expected, string because = "", params object[] becauseArgs) where T : struct, System.Enum { } @@ -1897,6 +1904,7 @@ namespace FluentAssertions.Primitives public FluentAssertions.AndConstraint Be(System.Guid expected, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint Be(string expected, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint BeEmpty(string because = "", params object[] becauseArgs) { } + public override bool Equals(object obj) { } public FluentAssertions.AndConstraint NotBe(System.Guid unexpected, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint NotBe(string unexpected, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint NotBeEmpty(string because = "", params object[] becauseArgs) { } @@ -2014,6 +2022,7 @@ namespace FluentAssertions.Primitives public FluentAssertions.AndConstraint BeOfType(System.Type expectedType, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndWhichConstraint BeOfType(string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint BeSameAs(TSubject expected, string because = "", params object[] becauseArgs) { } + public override bool Equals(object obj) { } public FluentAssertions.AndConstraint Match(System.Linq.Expressions.Expression> predicate, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint Match(System.Linq.Expressions.Expression> predicate, string because = "", params object[] becauseArgs) where T : TSubject { } @@ -2043,6 +2052,7 @@ namespace FluentAssertions.Primitives public FluentAssertions.AndConstraint BeLessThanOrEqualTo(System.TimeSpan expected, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint BeNegative(string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint BePositive(string because = "", params object[] becauseArgs) { } + public override bool Equals(object obj) { } public FluentAssertions.AndConstraint NotBe(System.TimeSpan unexpected, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint NotBeCloseTo(System.TimeSpan distantTime, System.TimeSpan precision, string because = "", params object[] becauseArgs) { } } @@ -2205,6 +2215,7 @@ namespace FluentAssertions.Specialized public FluentAssertions.AndConstraint BeLessOrEqualTo(System.TimeSpan maxDuration, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint BeLessThan(System.TimeSpan maxDuration, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint BeLessThanOrEqualTo(System.TimeSpan maxDuration, string because = "", params object[] becauseArgs) { } + public override bool Equals(object obj) { } } public class FunctionAssertions : FluentAssertions.Specialized.DelegateAssertions, FluentAssertions.Specialized.FunctionAssertions> { @@ -2242,6 +2253,7 @@ namespace FluentAssertions.Specialized public TaskCompletionSourceAssertions(System.Threading.Tasks.TaskCompletionSource tcs) { } public TaskCompletionSourceAssertions(System.Threading.Tasks.TaskCompletionSource tcs, FluentAssertions.Common.IClock clock) { } public System.Threading.Tasks.Task, T>> CompleteWithinAsync(System.TimeSpan timeSpan, string because = "", params object[] becauseArgs) { } + public override bool Equals(object obj) { } public System.Threading.Tasks.Task NotCompleteWithinAsync(System.TimeSpan timeSpan, string because = "", params object[] becauseArgs) { } } } @@ -2341,14 +2353,18 @@ namespace FluentAssertions.Types public FluentAssertions.Types.MethodInfoSelector ThatReturnVoid { get; } public System.Collections.Generic.IEnumerator GetEnumerator() { } public FluentAssertions.Types.TypeSelector ReturnTypes() { } + public FluentAssertions.Types.MethodInfoSelector ThatAreAsync() { } public FluentAssertions.Types.MethodInfoSelector ThatAreDecoratedWith() where TAttribute : System.Attribute { } public FluentAssertions.Types.MethodInfoSelector ThatAreDecoratedWithOrInherit() where TAttribute : System.Attribute { } + public FluentAssertions.Types.MethodInfoSelector ThatAreNotAsync() { } public FluentAssertions.Types.MethodInfoSelector ThatAreNotDecoratedWith() where TAttribute : System.Attribute { } public FluentAssertions.Types.MethodInfoSelector ThatAreNotDecoratedWithOrInherit() where TAttribute : System.Attribute { } + public FluentAssertions.Types.MethodInfoSelector ThatAreNotVirtual() { } + public FluentAssertions.Types.MethodInfoSelector ThatAreVirtual() { } public FluentAssertions.Types.MethodInfoSelector ThatDoNotReturn() { } public FluentAssertions.Types.MethodInfoSelector ThatReturn() { } public System.Reflection.MethodInfo[] ToArray() { } @@ -2365,6 +2381,7 @@ namespace FluentAssertions.Types public FluentAssertions.AndConstraint BeDecoratedWith(System.Linq.Expressions.Expression> isMatchingAttributePredicate, string because = "", params object[] becauseArgs) where TAttribute : System.Attribute { } public FluentAssertions.AndConstraint BeVirtual(string because = "", params object[] becauseArgs) { } + public override bool Equals(object obj) { } public FluentAssertions.AndConstraint NotBe(FluentAssertions.Common.CSharpAccessModifier accessModifier, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint NotBeAsync(string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint NotBeDecoratedWith(string because = "", params object[] becauseArgs) @@ -2418,6 +2435,7 @@ namespace FluentAssertions.Types where TAttribute : System.Attribute { } public FluentAssertions.AndConstraint BeVirtual(string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint BeWritable(string because = "", params object[] becauseArgs) { } + public override bool Equals(object obj) { } public FluentAssertions.AndConstraint NotBeDecoratedWith(string because = "", params object[] becauseArgs) where TAttribute : System.Attribute { } public FluentAssertions.AndConstraint NotBeVirtual(string because = "", params object[] becauseArgs) { } @@ -2548,6 +2566,7 @@ namespace FluentAssertions.Types public FluentAssertions.AndConstraint BeInNamespace(string @namespace, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint BeSealed(string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint BeUnderNamespace(string @namespace, string because = "", params object[] becauseArgs) { } + public override bool Equals(object obj) { } public FluentAssertions.AndConstraint NotBeDecoratedWith(string because = "", params object[] becauseArgs) where TAttribute : System.Attribute { } public FluentAssertions.AndConstraint NotBeDecoratedWith(System.Linq.Expressions.Expression> isMatchingAttributePredicate, 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 a3a805d23d..d5b927c7d6 100644 --- a/Tests/Approval.Tests/ApprovedApi/FluentAssertions/netcoreapp2.1.verified.txt +++ b/Tests/Approval.Tests/ApprovedApi/FluentAssertions/netcoreapp2.1.verified.txt @@ -1716,6 +1716,7 @@ namespace FluentAssertions.Numeric public FluentAssertions.AndConstraint BeOneOf(params T[] validValues) { } public FluentAssertions.AndConstraint BeOneOf(System.Collections.Generic.IEnumerable validValues, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint BePositive(string because = "", params object[] becauseArgs) { } + public override bool Equals(object obj) { } public FluentAssertions.AndConstraint Match(System.Linq.Expressions.Expression> predicate, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint NotBe(T unexpected, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint NotBe(T? unexpected, string because = "", params object[] becauseArgs) { } @@ -1737,6 +1738,7 @@ namespace FluentAssertions.Primitives public FluentAssertions.AndConstraint Be(bool expected, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint BeFalse(string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint BeTrue(string because = "", params object[] becauseArgs) { } + public override bool Equals(object obj) { } public FluentAssertions.AndConstraint NotBe(bool unexpected, string because = "", params object[] becauseArgs) { } } public class DateTimeAssertions : FluentAssertions.Primitives.DateTimeAssertions @@ -1766,6 +1768,7 @@ namespace FluentAssertions.Primitives public FluentAssertions.AndConstraint BeOneOf(System.Collections.Generic.IEnumerable validValues, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint BeSameDateAs(System.DateTime expected, string because = "", params object[] becauseArgs) { } public FluentAssertions.Primitives.DateTimeRangeAssertions BeWithin(System.TimeSpan timeSpan) { } + public override bool Equals(object obj) { } public FluentAssertions.AndConstraint HaveDay(int expected, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint HaveHour(int expected, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint HaveMinute(int expected, string because = "", params object[] becauseArgs) { } @@ -1815,6 +1818,7 @@ namespace FluentAssertions.Primitives public FluentAssertions.AndConstraint BeOneOf(System.Collections.Generic.IEnumerable validValues, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint BeSameDateAs(System.DateTimeOffset expected, string because = "", params object[] becauseArgs) { } public FluentAssertions.Primitives.DateTimeOffsetRangeAssertions BeWithin(System.TimeSpan timeSpan) { } + public override bool Equals(object obj) { } public FluentAssertions.AndConstraint HaveDay(int expected, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint HaveHour(int expected, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint HaveMinute(int expected, string because = "", params object[] becauseArgs) { } @@ -1846,6 +1850,7 @@ namespace FluentAssertions.Primitives protected DateTimeOffsetRangeAssertions(TAssertions parentAssertions, System.DateTimeOffset? subject, FluentAssertions.Primitives.TimeSpanCondition condition, System.TimeSpan timeSpan) { } public FluentAssertions.AndConstraint After(System.DateTimeOffset target, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint Before(System.DateTimeOffset target, string because = "", params object[] becauseArgs) { } + public override bool Equals(object obj) { } } public class DateTimeRangeAssertions where TAssertions : FluentAssertions.Primitives.DateTimeAssertions @@ -1853,6 +1858,7 @@ namespace FluentAssertions.Primitives protected DateTimeRangeAssertions(TAssertions parentAssertions, System.DateTime? subject, FluentAssertions.Primitives.TimeSpanCondition condition, System.TimeSpan timeSpan) { } public FluentAssertions.AndConstraint After(System.DateTime target, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint Before(System.DateTime target, string because = "", params object[] becauseArgs) { } + public override bool Equals(object obj) { } } public class EnumAssertions : FluentAssertions.Primitives.EnumAssertions> where TEnum : struct, System.Enum @@ -1869,6 +1875,7 @@ namespace FluentAssertions.Primitives public FluentAssertions.AndConstraint Be(TEnum? expected, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint BeOneOf(params TEnum[] validValues) { } public FluentAssertions.AndConstraint BeOneOf(System.Collections.Generic.IEnumerable validValues, string because = "", params object[] becauseArgs) { } + public override bool Equals(object obj) { } public FluentAssertions.AndConstraint HaveFlag(TEnum expectedFlag, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint HaveSameNameAs(T expected, string because = "", params object[] becauseArgs) where T : struct, System.Enum { } @@ -1897,6 +1904,7 @@ namespace FluentAssertions.Primitives public FluentAssertions.AndConstraint Be(System.Guid expected, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint Be(string expected, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint BeEmpty(string because = "", params object[] becauseArgs) { } + public override bool Equals(object obj) { } public FluentAssertions.AndConstraint NotBe(System.Guid unexpected, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint NotBe(string unexpected, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint NotBeEmpty(string because = "", params object[] becauseArgs) { } @@ -2014,6 +2022,7 @@ namespace FluentAssertions.Primitives public FluentAssertions.AndConstraint BeOfType(System.Type expectedType, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndWhichConstraint BeOfType(string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint BeSameAs(TSubject expected, string because = "", params object[] becauseArgs) { } + public override bool Equals(object obj) { } public FluentAssertions.AndConstraint Match(System.Linq.Expressions.Expression> predicate, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint Match(System.Linq.Expressions.Expression> predicate, string because = "", params object[] becauseArgs) where T : TSubject { } @@ -2043,6 +2052,7 @@ namespace FluentAssertions.Primitives public FluentAssertions.AndConstraint BeLessThanOrEqualTo(System.TimeSpan expected, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint BeNegative(string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint BePositive(string because = "", params object[] becauseArgs) { } + public override bool Equals(object obj) { } public FluentAssertions.AndConstraint NotBe(System.TimeSpan unexpected, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint NotBeCloseTo(System.TimeSpan distantTime, System.TimeSpan precision, string because = "", params object[] becauseArgs) { } } @@ -2205,6 +2215,7 @@ namespace FluentAssertions.Specialized public FluentAssertions.AndConstraint BeLessOrEqualTo(System.TimeSpan maxDuration, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint BeLessThan(System.TimeSpan maxDuration, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint BeLessThanOrEqualTo(System.TimeSpan maxDuration, string because = "", params object[] becauseArgs) { } + public override bool Equals(object obj) { } } public class FunctionAssertions : FluentAssertions.Specialized.DelegateAssertions, FluentAssertions.Specialized.FunctionAssertions> { @@ -2242,6 +2253,7 @@ namespace FluentAssertions.Specialized public TaskCompletionSourceAssertions(System.Threading.Tasks.TaskCompletionSource tcs) { } public TaskCompletionSourceAssertions(System.Threading.Tasks.TaskCompletionSource tcs, FluentAssertions.Common.IClock clock) { } public System.Threading.Tasks.Task, T>> CompleteWithinAsync(System.TimeSpan timeSpan, string because = "", params object[] becauseArgs) { } + public override bool Equals(object obj) { } public System.Threading.Tasks.Task NotCompleteWithinAsync(System.TimeSpan timeSpan, string because = "", params object[] becauseArgs) { } } } @@ -2343,14 +2355,18 @@ namespace FluentAssertions.Types public FluentAssertions.Types.MethodInfoSelector ThatReturnVoid { get; } public System.Collections.Generic.IEnumerator GetEnumerator() { } public FluentAssertions.Types.TypeSelector ReturnTypes() { } + public FluentAssertions.Types.MethodInfoSelector ThatAreAsync() { } public FluentAssertions.Types.MethodInfoSelector ThatAreDecoratedWith() where TAttribute : System.Attribute { } public FluentAssertions.Types.MethodInfoSelector ThatAreDecoratedWithOrInherit() where TAttribute : System.Attribute { } + public FluentAssertions.Types.MethodInfoSelector ThatAreNotAsync() { } public FluentAssertions.Types.MethodInfoSelector ThatAreNotDecoratedWith() where TAttribute : System.Attribute { } public FluentAssertions.Types.MethodInfoSelector ThatAreNotDecoratedWithOrInherit() where TAttribute : System.Attribute { } + public FluentAssertions.Types.MethodInfoSelector ThatAreNotVirtual() { } + public FluentAssertions.Types.MethodInfoSelector ThatAreVirtual() { } public FluentAssertions.Types.MethodInfoSelector ThatDoNotReturn() { } public FluentAssertions.Types.MethodInfoSelector ThatReturn() { } public System.Reflection.MethodInfo[] ToArray() { } @@ -2367,6 +2383,7 @@ namespace FluentAssertions.Types public FluentAssertions.AndConstraint BeDecoratedWith(System.Linq.Expressions.Expression> isMatchingAttributePredicate, string because = "", params object[] becauseArgs) where TAttribute : System.Attribute { } public FluentAssertions.AndConstraint BeVirtual(string because = "", params object[] becauseArgs) { } + public override bool Equals(object obj) { } public FluentAssertions.AndConstraint NotBe(FluentAssertions.Common.CSharpAccessModifier accessModifier, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint NotBeAsync(string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint NotBeDecoratedWith(string because = "", params object[] becauseArgs) @@ -2420,6 +2437,7 @@ namespace FluentAssertions.Types where TAttribute : System.Attribute { } public FluentAssertions.AndConstraint BeVirtual(string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint BeWritable(string because = "", params object[] becauseArgs) { } + public override bool Equals(object obj) { } public FluentAssertions.AndConstraint NotBeDecoratedWith(string because = "", params object[] becauseArgs) where TAttribute : System.Attribute { } public FluentAssertions.AndConstraint NotBeVirtual(string because = "", params object[] becauseArgs) { } @@ -2550,6 +2568,7 @@ namespace FluentAssertions.Types public FluentAssertions.AndConstraint BeInNamespace(string @namespace, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint BeSealed(string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint BeUnderNamespace(string @namespace, string because = "", params object[] becauseArgs) { } + public override bool Equals(object obj) { } public FluentAssertions.AndConstraint NotBeDecoratedWith(string because = "", params object[] becauseArgs) where TAttribute : System.Attribute { } public FluentAssertions.AndConstraint NotBeDecoratedWith(System.Linq.Expressions.Expression> isMatchingAttributePredicate, 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 94a2362b0a..62d7b60d9a 100644 --- a/Tests/Approval.Tests/ApprovedApi/FluentAssertions/netcoreapp3.0.verified.txt +++ b/Tests/Approval.Tests/ApprovedApi/FluentAssertions/netcoreapp3.0.verified.txt @@ -1716,6 +1716,7 @@ namespace FluentAssertions.Numeric public FluentAssertions.AndConstraint BeOneOf(params T[] validValues) { } public FluentAssertions.AndConstraint BeOneOf(System.Collections.Generic.IEnumerable validValues, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint BePositive(string because = "", params object[] becauseArgs) { } + public override bool Equals(object obj) { } public FluentAssertions.AndConstraint Match(System.Linq.Expressions.Expression> predicate, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint NotBe(T unexpected, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint NotBe(T? unexpected, string because = "", params object[] becauseArgs) { } @@ -1737,6 +1738,7 @@ namespace FluentAssertions.Primitives public FluentAssertions.AndConstraint Be(bool expected, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint BeFalse(string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint BeTrue(string because = "", params object[] becauseArgs) { } + public override bool Equals(object obj) { } public FluentAssertions.AndConstraint NotBe(bool unexpected, string because = "", params object[] becauseArgs) { } } public class DateTimeAssertions : FluentAssertions.Primitives.DateTimeAssertions @@ -1766,6 +1768,7 @@ namespace FluentAssertions.Primitives public FluentAssertions.AndConstraint BeOneOf(System.Collections.Generic.IEnumerable validValues, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint BeSameDateAs(System.DateTime expected, string because = "", params object[] becauseArgs) { } public FluentAssertions.Primitives.DateTimeRangeAssertions BeWithin(System.TimeSpan timeSpan) { } + public override bool Equals(object obj) { } public FluentAssertions.AndConstraint HaveDay(int expected, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint HaveHour(int expected, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint HaveMinute(int expected, string because = "", params object[] becauseArgs) { } @@ -1815,6 +1818,7 @@ namespace FluentAssertions.Primitives public FluentAssertions.AndConstraint BeOneOf(System.Collections.Generic.IEnumerable validValues, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint BeSameDateAs(System.DateTimeOffset expected, string because = "", params object[] becauseArgs) { } public FluentAssertions.Primitives.DateTimeOffsetRangeAssertions BeWithin(System.TimeSpan timeSpan) { } + public override bool Equals(object obj) { } public FluentAssertions.AndConstraint HaveDay(int expected, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint HaveHour(int expected, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint HaveMinute(int expected, string because = "", params object[] becauseArgs) { } @@ -1846,6 +1850,7 @@ namespace FluentAssertions.Primitives protected DateTimeOffsetRangeAssertions(TAssertions parentAssertions, System.DateTimeOffset? subject, FluentAssertions.Primitives.TimeSpanCondition condition, System.TimeSpan timeSpan) { } public FluentAssertions.AndConstraint After(System.DateTimeOffset target, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint Before(System.DateTimeOffset target, string because = "", params object[] becauseArgs) { } + public override bool Equals(object obj) { } } public class DateTimeRangeAssertions where TAssertions : FluentAssertions.Primitives.DateTimeAssertions @@ -1853,6 +1858,7 @@ namespace FluentAssertions.Primitives protected DateTimeRangeAssertions(TAssertions parentAssertions, System.DateTime? subject, FluentAssertions.Primitives.TimeSpanCondition condition, System.TimeSpan timeSpan) { } public FluentAssertions.AndConstraint After(System.DateTime target, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint Before(System.DateTime target, string because = "", params object[] becauseArgs) { } + public override bool Equals(object obj) { } } public class EnumAssertions : FluentAssertions.Primitives.EnumAssertions> where TEnum : struct, System.Enum @@ -1869,6 +1875,7 @@ namespace FluentAssertions.Primitives public FluentAssertions.AndConstraint Be(TEnum? expected, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint BeOneOf(params TEnum[] validValues) { } public FluentAssertions.AndConstraint BeOneOf(System.Collections.Generic.IEnumerable validValues, string because = "", params object[] becauseArgs) { } + public override bool Equals(object obj) { } public FluentAssertions.AndConstraint HaveFlag(TEnum expectedFlag, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint HaveSameNameAs(T expected, string because = "", params object[] becauseArgs) where T : struct, System.Enum { } @@ -1897,6 +1904,7 @@ namespace FluentAssertions.Primitives public FluentAssertions.AndConstraint Be(System.Guid expected, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint Be(string expected, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint BeEmpty(string because = "", params object[] becauseArgs) { } + public override bool Equals(object obj) { } public FluentAssertions.AndConstraint NotBe(System.Guid unexpected, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint NotBe(string unexpected, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint NotBeEmpty(string because = "", params object[] becauseArgs) { } @@ -2014,6 +2022,7 @@ namespace FluentAssertions.Primitives public FluentAssertions.AndConstraint BeOfType(System.Type expectedType, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndWhichConstraint BeOfType(string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint BeSameAs(TSubject expected, string because = "", params object[] becauseArgs) { } + public override bool Equals(object obj) { } public FluentAssertions.AndConstraint Match(System.Linq.Expressions.Expression> predicate, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint Match(System.Linq.Expressions.Expression> predicate, string because = "", params object[] becauseArgs) where T : TSubject { } @@ -2043,6 +2052,7 @@ namespace FluentAssertions.Primitives public FluentAssertions.AndConstraint BeLessThanOrEqualTo(System.TimeSpan expected, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint BeNegative(string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint BePositive(string because = "", params object[] becauseArgs) { } + public override bool Equals(object obj) { } public FluentAssertions.AndConstraint NotBe(System.TimeSpan unexpected, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint NotBeCloseTo(System.TimeSpan distantTime, System.TimeSpan precision, string because = "", params object[] becauseArgs) { } } @@ -2205,6 +2215,7 @@ namespace FluentAssertions.Specialized public FluentAssertions.AndConstraint BeLessOrEqualTo(System.TimeSpan maxDuration, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint BeLessThan(System.TimeSpan maxDuration, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint BeLessThanOrEqualTo(System.TimeSpan maxDuration, string because = "", params object[] becauseArgs) { } + public override bool Equals(object obj) { } } public class FunctionAssertions : FluentAssertions.Specialized.DelegateAssertions, FluentAssertions.Specialized.FunctionAssertions> { @@ -2242,6 +2253,7 @@ namespace FluentAssertions.Specialized public TaskCompletionSourceAssertions(System.Threading.Tasks.TaskCompletionSource tcs) { } public TaskCompletionSourceAssertions(System.Threading.Tasks.TaskCompletionSource tcs, FluentAssertions.Common.IClock clock) { } public System.Threading.Tasks.Task, T>> CompleteWithinAsync(System.TimeSpan timeSpan, string because = "", params object[] becauseArgs) { } + public override bool Equals(object obj) { } public System.Threading.Tasks.Task NotCompleteWithinAsync(System.TimeSpan timeSpan, string because = "", params object[] becauseArgs) { } } } @@ -2343,14 +2355,18 @@ namespace FluentAssertions.Types public FluentAssertions.Types.MethodInfoSelector ThatReturnVoid { get; } public System.Collections.Generic.IEnumerator GetEnumerator() { } public FluentAssertions.Types.TypeSelector ReturnTypes() { } + public FluentAssertions.Types.MethodInfoSelector ThatAreAsync() { } public FluentAssertions.Types.MethodInfoSelector ThatAreDecoratedWith() where TAttribute : System.Attribute { } public FluentAssertions.Types.MethodInfoSelector ThatAreDecoratedWithOrInherit() where TAttribute : System.Attribute { } + public FluentAssertions.Types.MethodInfoSelector ThatAreNotAsync() { } public FluentAssertions.Types.MethodInfoSelector ThatAreNotDecoratedWith() where TAttribute : System.Attribute { } public FluentAssertions.Types.MethodInfoSelector ThatAreNotDecoratedWithOrInherit() where TAttribute : System.Attribute { } + public FluentAssertions.Types.MethodInfoSelector ThatAreNotVirtual() { } + public FluentAssertions.Types.MethodInfoSelector ThatAreVirtual() { } public FluentAssertions.Types.MethodInfoSelector ThatDoNotReturn() { } public FluentAssertions.Types.MethodInfoSelector ThatReturn() { } public System.Reflection.MethodInfo[] ToArray() { } @@ -2367,6 +2383,7 @@ namespace FluentAssertions.Types public FluentAssertions.AndConstraint BeDecoratedWith(System.Linq.Expressions.Expression> isMatchingAttributePredicate, string because = "", params object[] becauseArgs) where TAttribute : System.Attribute { } public FluentAssertions.AndConstraint BeVirtual(string because = "", params object[] becauseArgs) { } + public override bool Equals(object obj) { } public FluentAssertions.AndConstraint NotBe(FluentAssertions.Common.CSharpAccessModifier accessModifier, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint NotBeAsync(string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint NotBeDecoratedWith(string because = "", params object[] becauseArgs) @@ -2420,6 +2437,7 @@ namespace FluentAssertions.Types where TAttribute : System.Attribute { } public FluentAssertions.AndConstraint BeVirtual(string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint BeWritable(string because = "", params object[] becauseArgs) { } + public override bool Equals(object obj) { } public FluentAssertions.AndConstraint NotBeDecoratedWith(string because = "", params object[] becauseArgs) where TAttribute : System.Attribute { } public FluentAssertions.AndConstraint NotBeVirtual(string because = "", params object[] becauseArgs) { } @@ -2550,6 +2568,7 @@ namespace FluentAssertions.Types public FluentAssertions.AndConstraint BeInNamespace(string @namespace, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint BeSealed(string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint BeUnderNamespace(string @namespace, string because = "", params object[] becauseArgs) { } + public override bool Equals(object obj) { } public FluentAssertions.AndConstraint NotBeDecoratedWith(string because = "", params object[] becauseArgs) where TAttribute : System.Attribute { } public FluentAssertions.AndConstraint NotBeDecoratedWith(System.Linq.Expressions.Expression> isMatchingAttributePredicate, 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 8b379c216f..45c197d938 100644 --- a/Tests/Approval.Tests/ApprovedApi/FluentAssertions/netstandard2.0.verified.txt +++ b/Tests/Approval.Tests/ApprovedApi/FluentAssertions/netstandard2.0.verified.txt @@ -1669,6 +1669,7 @@ namespace FluentAssertions.Numeric public FluentAssertions.AndConstraint BeOneOf(params T[] validValues) { } public FluentAssertions.AndConstraint BeOneOf(System.Collections.Generic.IEnumerable validValues, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint BePositive(string because = "", params object[] becauseArgs) { } + public override bool Equals(object obj) { } public FluentAssertions.AndConstraint Match(System.Linq.Expressions.Expression> predicate, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint NotBe(T unexpected, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint NotBe(T? unexpected, string because = "", params object[] becauseArgs) { } @@ -1690,6 +1691,7 @@ namespace FluentAssertions.Primitives public FluentAssertions.AndConstraint Be(bool expected, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint BeFalse(string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint BeTrue(string because = "", params object[] becauseArgs) { } + public override bool Equals(object obj) { } public FluentAssertions.AndConstraint NotBe(bool unexpected, string because = "", params object[] becauseArgs) { } } public class DateTimeAssertions : FluentAssertions.Primitives.DateTimeAssertions @@ -1719,6 +1721,7 @@ namespace FluentAssertions.Primitives public FluentAssertions.AndConstraint BeOneOf(System.Collections.Generic.IEnumerable validValues, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint BeSameDateAs(System.DateTime expected, string because = "", params object[] becauseArgs) { } public FluentAssertions.Primitives.DateTimeRangeAssertions BeWithin(System.TimeSpan timeSpan) { } + public override bool Equals(object obj) { } public FluentAssertions.AndConstraint HaveDay(int expected, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint HaveHour(int expected, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint HaveMinute(int expected, string because = "", params object[] becauseArgs) { } @@ -1768,6 +1771,7 @@ namespace FluentAssertions.Primitives public FluentAssertions.AndConstraint BeOneOf(System.Collections.Generic.IEnumerable validValues, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint BeSameDateAs(System.DateTimeOffset expected, string because = "", params object[] becauseArgs) { } public FluentAssertions.Primitives.DateTimeOffsetRangeAssertions BeWithin(System.TimeSpan timeSpan) { } + public override bool Equals(object obj) { } public FluentAssertions.AndConstraint HaveDay(int expected, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint HaveHour(int expected, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint HaveMinute(int expected, string because = "", params object[] becauseArgs) { } @@ -1799,6 +1803,7 @@ namespace FluentAssertions.Primitives protected DateTimeOffsetRangeAssertions(TAssertions parentAssertions, System.DateTimeOffset? subject, FluentAssertions.Primitives.TimeSpanCondition condition, System.TimeSpan timeSpan) { } public FluentAssertions.AndConstraint After(System.DateTimeOffset target, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint Before(System.DateTimeOffset target, string because = "", params object[] becauseArgs) { } + public override bool Equals(object obj) { } } public class DateTimeRangeAssertions where TAssertions : FluentAssertions.Primitives.DateTimeAssertions @@ -1806,6 +1811,7 @@ namespace FluentAssertions.Primitives protected DateTimeRangeAssertions(TAssertions parentAssertions, System.DateTime? subject, FluentAssertions.Primitives.TimeSpanCondition condition, System.TimeSpan timeSpan) { } public FluentAssertions.AndConstraint After(System.DateTime target, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint Before(System.DateTime target, string because = "", params object[] becauseArgs) { } + public override bool Equals(object obj) { } } public class EnumAssertions : FluentAssertions.Primitives.EnumAssertions> where TEnum : struct, System.Enum @@ -1822,6 +1828,7 @@ namespace FluentAssertions.Primitives public FluentAssertions.AndConstraint Be(TEnum? expected, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint BeOneOf(params TEnum[] validValues) { } public FluentAssertions.AndConstraint BeOneOf(System.Collections.Generic.IEnumerable validValues, string because = "", params object[] becauseArgs) { } + public override bool Equals(object obj) { } public FluentAssertions.AndConstraint HaveFlag(TEnum expectedFlag, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint HaveSameNameAs(T expected, string because = "", params object[] becauseArgs) where T : struct, System.Enum { } @@ -1850,6 +1857,7 @@ namespace FluentAssertions.Primitives public FluentAssertions.AndConstraint Be(System.Guid expected, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint Be(string expected, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint BeEmpty(string because = "", params object[] becauseArgs) { } + public override bool Equals(object obj) { } public FluentAssertions.AndConstraint NotBe(System.Guid unexpected, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint NotBe(string unexpected, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint NotBeEmpty(string because = "", params object[] becauseArgs) { } @@ -1967,6 +1975,7 @@ namespace FluentAssertions.Primitives public FluentAssertions.AndConstraint BeOfType(System.Type expectedType, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndWhichConstraint BeOfType(string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint BeSameAs(TSubject expected, string because = "", params object[] becauseArgs) { } + public override bool Equals(object obj) { } public FluentAssertions.AndConstraint Match(System.Linq.Expressions.Expression> predicate, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint Match(System.Linq.Expressions.Expression> predicate, string because = "", params object[] becauseArgs) where T : TSubject { } @@ -1996,6 +2005,7 @@ namespace FluentAssertions.Primitives public FluentAssertions.AndConstraint BeLessThanOrEqualTo(System.TimeSpan expected, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint BeNegative(string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint BePositive(string because = "", params object[] becauseArgs) { } + public override bool Equals(object obj) { } public FluentAssertions.AndConstraint NotBe(System.TimeSpan unexpected, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint NotBeCloseTo(System.TimeSpan distantTime, System.TimeSpan precision, string because = "", params object[] becauseArgs) { } } @@ -2158,6 +2168,7 @@ namespace FluentAssertions.Specialized public FluentAssertions.AndConstraint BeLessOrEqualTo(System.TimeSpan maxDuration, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint BeLessThan(System.TimeSpan maxDuration, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint BeLessThanOrEqualTo(System.TimeSpan maxDuration, string because = "", params object[] becauseArgs) { } + public override bool Equals(object obj) { } } public class FunctionAssertions : FluentAssertions.Specialized.DelegateAssertions, FluentAssertions.Specialized.FunctionAssertions> { @@ -2195,6 +2206,7 @@ namespace FluentAssertions.Specialized public TaskCompletionSourceAssertions(System.Threading.Tasks.TaskCompletionSource tcs) { } public TaskCompletionSourceAssertions(System.Threading.Tasks.TaskCompletionSource tcs, FluentAssertions.Common.IClock clock) { } public System.Threading.Tasks.Task, T>> CompleteWithinAsync(System.TimeSpan timeSpan, string because = "", params object[] becauseArgs) { } + public override bool Equals(object obj) { } public System.Threading.Tasks.Task NotCompleteWithinAsync(System.TimeSpan timeSpan, string because = "", params object[] becauseArgs) { } } } @@ -2294,14 +2306,18 @@ namespace FluentAssertions.Types public FluentAssertions.Types.MethodInfoSelector ThatReturnVoid { get; } public System.Collections.Generic.IEnumerator GetEnumerator() { } public FluentAssertions.Types.TypeSelector ReturnTypes() { } + public FluentAssertions.Types.MethodInfoSelector ThatAreAsync() { } public FluentAssertions.Types.MethodInfoSelector ThatAreDecoratedWith() where TAttribute : System.Attribute { } public FluentAssertions.Types.MethodInfoSelector ThatAreDecoratedWithOrInherit() where TAttribute : System.Attribute { } + public FluentAssertions.Types.MethodInfoSelector ThatAreNotAsync() { } public FluentAssertions.Types.MethodInfoSelector ThatAreNotDecoratedWith() where TAttribute : System.Attribute { } public FluentAssertions.Types.MethodInfoSelector ThatAreNotDecoratedWithOrInherit() where TAttribute : System.Attribute { } + public FluentAssertions.Types.MethodInfoSelector ThatAreNotVirtual() { } + public FluentAssertions.Types.MethodInfoSelector ThatAreVirtual() { } public FluentAssertions.Types.MethodInfoSelector ThatDoNotReturn() { } public FluentAssertions.Types.MethodInfoSelector ThatReturn() { } public System.Reflection.MethodInfo[] ToArray() { } @@ -2318,6 +2334,7 @@ namespace FluentAssertions.Types public FluentAssertions.AndConstraint BeDecoratedWith(System.Linq.Expressions.Expression> isMatchingAttributePredicate, string because = "", params object[] becauseArgs) where TAttribute : System.Attribute { } public FluentAssertions.AndConstraint BeVirtual(string because = "", params object[] becauseArgs) { } + public override bool Equals(object obj) { } public FluentAssertions.AndConstraint NotBe(FluentAssertions.Common.CSharpAccessModifier accessModifier, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint NotBeAsync(string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint NotBeDecoratedWith(string because = "", params object[] becauseArgs) @@ -2371,6 +2388,7 @@ namespace FluentAssertions.Types where TAttribute : System.Attribute { } public FluentAssertions.AndConstraint BeVirtual(string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint BeWritable(string because = "", params object[] becauseArgs) { } + public override bool Equals(object obj) { } public FluentAssertions.AndConstraint NotBeDecoratedWith(string because = "", params object[] becauseArgs) where TAttribute : System.Attribute { } public FluentAssertions.AndConstraint NotBeVirtual(string because = "", params object[] becauseArgs) { } @@ -2501,6 +2519,7 @@ namespace FluentAssertions.Types public FluentAssertions.AndConstraint BeInNamespace(string @namespace, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint BeSealed(string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint BeUnderNamespace(string @namespace, string because = "", params object[] becauseArgs) { } + public override bool Equals(object obj) { } public FluentAssertions.AndConstraint NotBeDecoratedWith(string because = "", params object[] becauseArgs) where TAttribute : System.Attribute { } public FluentAssertions.AndConstraint NotBeDecoratedWith(System.Linq.Expressions.Expression> isMatchingAttributePredicate, 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 f4709a87bd..49ebf2d8c8 100644 --- a/Tests/Approval.Tests/ApprovedApi/FluentAssertions/netstandard2.1.verified.txt +++ b/Tests/Approval.Tests/ApprovedApi/FluentAssertions/netstandard2.1.verified.txt @@ -1716,6 +1716,7 @@ namespace FluentAssertions.Numeric public FluentAssertions.AndConstraint BeOneOf(params T[] validValues) { } public FluentAssertions.AndConstraint BeOneOf(System.Collections.Generic.IEnumerable validValues, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint BePositive(string because = "", params object[] becauseArgs) { } + public override bool Equals(object obj) { } public FluentAssertions.AndConstraint Match(System.Linq.Expressions.Expression> predicate, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint NotBe(T unexpected, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint NotBe(T? unexpected, string because = "", params object[] becauseArgs) { } @@ -1737,6 +1738,7 @@ namespace FluentAssertions.Primitives public FluentAssertions.AndConstraint Be(bool expected, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint BeFalse(string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint BeTrue(string because = "", params object[] becauseArgs) { } + public override bool Equals(object obj) { } public FluentAssertions.AndConstraint NotBe(bool unexpected, string because = "", params object[] becauseArgs) { } } public class DateTimeAssertions : FluentAssertions.Primitives.DateTimeAssertions @@ -1766,6 +1768,7 @@ namespace FluentAssertions.Primitives public FluentAssertions.AndConstraint BeOneOf(System.Collections.Generic.IEnumerable validValues, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint BeSameDateAs(System.DateTime expected, string because = "", params object[] becauseArgs) { } public FluentAssertions.Primitives.DateTimeRangeAssertions BeWithin(System.TimeSpan timeSpan) { } + public override bool Equals(object obj) { } public FluentAssertions.AndConstraint HaveDay(int expected, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint HaveHour(int expected, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint HaveMinute(int expected, string because = "", params object[] becauseArgs) { } @@ -1815,6 +1818,7 @@ namespace FluentAssertions.Primitives public FluentAssertions.AndConstraint BeOneOf(System.Collections.Generic.IEnumerable validValues, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint BeSameDateAs(System.DateTimeOffset expected, string because = "", params object[] becauseArgs) { } public FluentAssertions.Primitives.DateTimeOffsetRangeAssertions BeWithin(System.TimeSpan timeSpan) { } + public override bool Equals(object obj) { } public FluentAssertions.AndConstraint HaveDay(int expected, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint HaveHour(int expected, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint HaveMinute(int expected, string because = "", params object[] becauseArgs) { } @@ -1846,6 +1850,7 @@ namespace FluentAssertions.Primitives protected DateTimeOffsetRangeAssertions(TAssertions parentAssertions, System.DateTimeOffset? subject, FluentAssertions.Primitives.TimeSpanCondition condition, System.TimeSpan timeSpan) { } public FluentAssertions.AndConstraint After(System.DateTimeOffset target, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint Before(System.DateTimeOffset target, string because = "", params object[] becauseArgs) { } + public override bool Equals(object obj) { } } public class DateTimeRangeAssertions where TAssertions : FluentAssertions.Primitives.DateTimeAssertions @@ -1853,6 +1858,7 @@ namespace FluentAssertions.Primitives protected DateTimeRangeAssertions(TAssertions parentAssertions, System.DateTime? subject, FluentAssertions.Primitives.TimeSpanCondition condition, System.TimeSpan timeSpan) { } public FluentAssertions.AndConstraint After(System.DateTime target, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint Before(System.DateTime target, string because = "", params object[] becauseArgs) { } + public override bool Equals(object obj) { } } public class EnumAssertions : FluentAssertions.Primitives.EnumAssertions> where TEnum : struct, System.Enum @@ -1869,6 +1875,7 @@ namespace FluentAssertions.Primitives public FluentAssertions.AndConstraint Be(TEnum? expected, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint BeOneOf(params TEnum[] validValues) { } public FluentAssertions.AndConstraint BeOneOf(System.Collections.Generic.IEnumerable validValues, string because = "", params object[] becauseArgs) { } + public override bool Equals(object obj) { } public FluentAssertions.AndConstraint HaveFlag(TEnum expectedFlag, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint HaveSameNameAs(T expected, string because = "", params object[] becauseArgs) where T : struct, System.Enum { } @@ -1897,6 +1904,7 @@ namespace FluentAssertions.Primitives public FluentAssertions.AndConstraint Be(System.Guid expected, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint Be(string expected, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint BeEmpty(string because = "", params object[] becauseArgs) { } + public override bool Equals(object obj) { } public FluentAssertions.AndConstraint NotBe(System.Guid unexpected, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint NotBe(string unexpected, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint NotBeEmpty(string because = "", params object[] becauseArgs) { } @@ -2014,6 +2022,7 @@ namespace FluentAssertions.Primitives public FluentAssertions.AndConstraint BeOfType(System.Type expectedType, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndWhichConstraint BeOfType(string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint BeSameAs(TSubject expected, string because = "", params object[] becauseArgs) { } + public override bool Equals(object obj) { } public FluentAssertions.AndConstraint Match(System.Linq.Expressions.Expression> predicate, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint Match(System.Linq.Expressions.Expression> predicate, string because = "", params object[] becauseArgs) where T : TSubject { } @@ -2043,6 +2052,7 @@ namespace FluentAssertions.Primitives public FluentAssertions.AndConstraint BeLessThanOrEqualTo(System.TimeSpan expected, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint BeNegative(string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint BePositive(string because = "", params object[] becauseArgs) { } + public override bool Equals(object obj) { } public FluentAssertions.AndConstraint NotBe(System.TimeSpan unexpected, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint NotBeCloseTo(System.TimeSpan distantTime, System.TimeSpan precision, string because = "", params object[] becauseArgs) { } } @@ -2205,6 +2215,7 @@ namespace FluentAssertions.Specialized public FluentAssertions.AndConstraint BeLessOrEqualTo(System.TimeSpan maxDuration, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint BeLessThan(System.TimeSpan maxDuration, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint BeLessThanOrEqualTo(System.TimeSpan maxDuration, string because = "", params object[] becauseArgs) { } + public override bool Equals(object obj) { } } public class FunctionAssertions : FluentAssertions.Specialized.DelegateAssertions, FluentAssertions.Specialized.FunctionAssertions> { @@ -2242,6 +2253,7 @@ namespace FluentAssertions.Specialized public TaskCompletionSourceAssertions(System.Threading.Tasks.TaskCompletionSource tcs) { } public TaskCompletionSourceAssertions(System.Threading.Tasks.TaskCompletionSource tcs, FluentAssertions.Common.IClock clock) { } public System.Threading.Tasks.Task, T>> CompleteWithinAsync(System.TimeSpan timeSpan, string because = "", params object[] becauseArgs) { } + public override bool Equals(object obj) { } public System.Threading.Tasks.Task NotCompleteWithinAsync(System.TimeSpan timeSpan, string because = "", params object[] becauseArgs) { } } } @@ -2343,14 +2355,18 @@ namespace FluentAssertions.Types public FluentAssertions.Types.MethodInfoSelector ThatReturnVoid { get; } public System.Collections.Generic.IEnumerator GetEnumerator() { } public FluentAssertions.Types.TypeSelector ReturnTypes() { } + public FluentAssertions.Types.MethodInfoSelector ThatAreAsync() { } public FluentAssertions.Types.MethodInfoSelector ThatAreDecoratedWith() where TAttribute : System.Attribute { } public FluentAssertions.Types.MethodInfoSelector ThatAreDecoratedWithOrInherit() where TAttribute : System.Attribute { } + public FluentAssertions.Types.MethodInfoSelector ThatAreNotAsync() { } public FluentAssertions.Types.MethodInfoSelector ThatAreNotDecoratedWith() where TAttribute : System.Attribute { } public FluentAssertions.Types.MethodInfoSelector ThatAreNotDecoratedWithOrInherit() where TAttribute : System.Attribute { } + public FluentAssertions.Types.MethodInfoSelector ThatAreNotVirtual() { } + public FluentAssertions.Types.MethodInfoSelector ThatAreVirtual() { } public FluentAssertions.Types.MethodInfoSelector ThatDoNotReturn() { } public FluentAssertions.Types.MethodInfoSelector ThatReturn() { } public System.Reflection.MethodInfo[] ToArray() { } @@ -2367,6 +2383,7 @@ namespace FluentAssertions.Types public FluentAssertions.AndConstraint BeDecoratedWith(System.Linq.Expressions.Expression> isMatchingAttributePredicate, string because = "", params object[] becauseArgs) where TAttribute : System.Attribute { } public FluentAssertions.AndConstraint BeVirtual(string because = "", params object[] becauseArgs) { } + public override bool Equals(object obj) { } public FluentAssertions.AndConstraint NotBe(FluentAssertions.Common.CSharpAccessModifier accessModifier, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint NotBeAsync(string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint NotBeDecoratedWith(string because = "", params object[] becauseArgs) @@ -2420,6 +2437,7 @@ namespace FluentAssertions.Types where TAttribute : System.Attribute { } public FluentAssertions.AndConstraint BeVirtual(string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint BeWritable(string because = "", params object[] becauseArgs) { } + public override bool Equals(object obj) { } public FluentAssertions.AndConstraint NotBeDecoratedWith(string because = "", params object[] becauseArgs) where TAttribute : System.Attribute { } public FluentAssertions.AndConstraint NotBeVirtual(string because = "", params object[] becauseArgs) { } @@ -2550,6 +2568,7 @@ namespace FluentAssertions.Types public FluentAssertions.AndConstraint BeInNamespace(string @namespace, string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint BeSealed(string because = "", params object[] becauseArgs) { } public FluentAssertions.AndConstraint BeUnderNamespace(string @namespace, string because = "", params object[] becauseArgs) { } + public override bool Equals(object obj) { } public FluentAssertions.AndConstraint NotBeDecoratedWith(string because = "", params object[] becauseArgs) where TAttribute : System.Attribute { } public FluentAssertions.AndConstraint NotBeDecoratedWith(System.Linq.Expressions.Expression> isMatchingAttributePredicate, string because = "", params object[] becauseArgs) diff --git a/Tests/FluentAssertions.Specs/AssertionExtensionsSpecs.cs b/Tests/FluentAssertions.Specs/AssertionExtensionsSpecs.cs index 5508937af9..e4d55a2028 100644 --- a/Tests/FluentAssertions.Specs/AssertionExtensionsSpecs.cs +++ b/Tests/FluentAssertions.Specs/AssertionExtensionsSpecs.cs @@ -9,6 +9,29 @@ namespace FluentAssertions.Specs { public class AssertionExtensionsSpecs { + [Fact] + public void Assertions_classes_have_overriden_equals() + { + // Arrange / Act + var equalsOverloads = AllTypes.From(typeof(FluentAssertions.AssertionExtensions).Assembly) + .ThatAreClasses() + .Where(t => t.IsPublic && t.Name.TrimEnd('`', '1', '2', '3').EndsWith("Assertions", StringComparison.Ordinal)) + .Select(e => GetMostParentType(e)) + .Distinct() + .Select(t => (type: t, overridesEquals: OverridesEquals(t))) + .ToList(); + + // Assert + equalsOverloads.Should().OnlyContain(e => e.overridesEquals); + } + + private static bool OverridesEquals(Type t) + { + MethodInfo equals = t.GetMethod("Equals", BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public, + null, new[] { typeof(object) }, null); + return equals is not null; + } + [Fact] public void Should_methods_have_a_matching_overload_to_guard_against_chaining_and_constraints() { diff --git a/Tests/FluentAssertions.Specs/AssertionOptionsSpecs.cs b/Tests/FluentAssertions.Specs/AssertionOptionsSpecs.cs index f732cfb4b8..541f1ab5dd 100644 --- a/Tests/FluentAssertions.Specs/AssertionOptionsSpecs.cs +++ b/Tests/FluentAssertions.Specs/AssertionOptionsSpecs.cs @@ -54,9 +54,46 @@ public void It_should_not_throw() } [Collection("AssertionOptionsSpecs")] - public class When_modifying_global_settings_a_previous_assertion_should_not_have_any_effect : Given_temporary_global_assertion_options + public class When_modifying_global_reference_type_settings_a_previous_assertion_should_not_have_any_effect + : Given_temporary_global_assertion_options { - public When_modifying_global_settings_a_previous_assertion_should_not_have_any_effect() + public When_modifying_global_reference_type_settings_a_previous_assertion_should_not_have_any_effect() + { + Given(() => + { + // Trigger a first equivalency check using the default global settings + new MyValueType { Value = 1 }.Should().BeEquivalentTo(new MyValueType { Value = 2 }); + }); + + When(() => + { + AssertionOptions.AssertEquivalencyUsing(o => o.ComparingByMembers()); + }); + } + + [Fact] + public void It_should_try_to_compare_the_classes_by_member_semantics_and_thus_throw() + { + Action act = () => new MyValueType { Value = 1 }.Should().BeEquivalentTo(new MyValueType { Value = 2 }); + + act.Should().Throw(); + } + } + + internal class MyValueType + { + public int Value { get; set; } + + public override bool Equals(object obj) => true; + + public override int GetHashCode() => 0; + } + + [Collection("AssertionOptionsSpecs")] + public class When_modifying_global_value_type_settings_a_previous_assertion_should_not_have_any_effect + : Given_temporary_global_assertion_options + { + public When_modifying_global_value_type_settings_a_previous_assertion_should_not_have_any_effect() { Given(() => { diff --git a/Tests/FluentAssertions.Specs/Collections/CollectionAssertionSpecs.ContainSingle.cs b/Tests/FluentAssertions.Specs/Collections/CollectionAssertionSpecs.ContainSingle.cs index e9ac1c1dc7..81a0eda408 100644 --- a/Tests/FluentAssertions.Specs/Collections/CollectionAssertionSpecs.ContainSingle.cs +++ b/Tests/FluentAssertions.Specs/Collections/CollectionAssertionSpecs.ContainSingle.cs @@ -246,6 +246,32 @@ public void When_single_item_is_found_it_should_allow_continuation() act.Should().Throw().WithMessage(expectedMessage); } + [Fact] + public void When_collection_is_IEnumerable_it_should_be_evaluated_only_once_with_predicate() + { + // Arrange + IEnumerable collection = new OneTimeEnumerable(1); + + // Act + Action act = () => collection.Should().ContainSingle(_ => true); + + // Assert + act.Should().NotThrow(); + } + + [Fact] + public void When_collection_is_IEnumerable_it_should_be_evaluated_only_once() + { + // Arrange + IEnumerable collection = new OneTimeEnumerable(1); + + // Act + Action act = () => collection.Should().ContainSingle(); + + // Assert + act.Should().NotThrow(); + } + #endregion } } diff --git a/Tests/FluentAssertions.Specs/Collections/CollectionAssertionSpecs.HaveCount.cs b/Tests/FluentAssertions.Specs/Collections/CollectionAssertionSpecs.HaveCount.cs index fc179a2ad8..fb9710a3c5 100644 --- a/Tests/FluentAssertions.Specs/Collections/CollectionAssertionSpecs.HaveCount.cs +++ b/Tests/FluentAssertions.Specs/Collections/CollectionAssertionSpecs.HaveCount.cs @@ -46,7 +46,7 @@ public void When_collection_has_a_count_that_is_different_from_the_number_of_ite // Assert action.Should().Throw() - .WithMessage("Expected collection*1*2*3* to contain 4 item(s) because we want to test the failure message, but found 3."); + .WithMessage("Expected collection to contain 4 item(s) because we want to test the failure message, but found 3: {1, 2, 3}."); } [Fact] @@ -70,7 +70,7 @@ public void When_collection_has_a_count_that_not_matches_the_predicate_it_should // Assert act.Should().Throw().WithMessage( - "Expected collection {1, 2, 3} to have a count (c >= 4) because a minimum of 4 is required, but count is 3."); + "Expected collection to have a count (c >= 4) because a minimum of 4 is required, but count is 3: {1, 2, 3}."); } [Fact] diff --git a/Tests/FluentAssertions.Specs/Collections/CollectionAssertionSpecs.HaveCountGreaterThan.cs b/Tests/FluentAssertions.Specs/Collections/CollectionAssertionSpecs.HaveCountGreaterThan.cs index 21970a52e5..627551d3fa 100644 --- a/Tests/FluentAssertions.Specs/Collections/CollectionAssertionSpecs.HaveCountGreaterThan.cs +++ b/Tests/FluentAssertions.Specs/Collections/CollectionAssertionSpecs.HaveCountGreaterThan.cs @@ -47,7 +47,7 @@ public void When_collection_has_a_count_greater_than_the_number_of_items_it_shou // Assert action.Should().Throw() - .WithMessage("*more than*3*because we want to test the failure message*3*"); + .WithMessage("Expected collection to contain more than 3 item(s) because we want to test the failure message, but found 3: {1, 2, 3}."); } [Fact] diff --git a/Tests/FluentAssertions.Specs/Collections/CollectionAssertionSpecs.HaveCountGreaterThanOrEqualTo.cs b/Tests/FluentAssertions.Specs/Collections/CollectionAssertionSpecs.HaveCountGreaterThanOrEqualTo.cs index 3e42d4625c..3d58081a19 100644 --- a/Tests/FluentAssertions.Specs/Collections/CollectionAssertionSpecs.HaveCountGreaterThanOrEqualTo.cs +++ b/Tests/FluentAssertions.Specs/Collections/CollectionAssertionSpecs.HaveCountGreaterThanOrEqualTo.cs @@ -46,7 +46,7 @@ public void When_collection_has_a_count_greater_than_or_equal_to_the_number_of_i // Assert action.Should().Throw() - .WithMessage("*at least*4*because we want to test the failure message*3*"); + .WithMessage("Expected collection to contain at least 4 item(s) because we want to test the failure message, but found 3: {1, 2, 3}."); } [Fact] diff --git a/Tests/FluentAssertions.Specs/Collections/CollectionAssertionSpecs.HaveCountLessThan.cs b/Tests/FluentAssertions.Specs/Collections/CollectionAssertionSpecs.HaveCountLessThan.cs index 15dd4f6285..121f52a30f 100644 --- a/Tests/FluentAssertions.Specs/Collections/CollectionAssertionSpecs.HaveCountLessThan.cs +++ b/Tests/FluentAssertions.Specs/Collections/CollectionAssertionSpecs.HaveCountLessThan.cs @@ -46,7 +46,7 @@ public void When_collection_has_a_count_less_than_the_number_of_items_it_should_ // Assert action.Should().Throw() - .WithMessage("*fewer than*3*because we want to test the failure message*3*"); + .WithMessage("Expected collection to contain fewer than 3 item(s) because we want to test the failure message, but found 3: {1, 2, 3}."); } [Fact] diff --git a/Tests/FluentAssertions.Specs/Collections/CollectionAssertionSpecs.HaveCountLessThanOrEqualTo.cs b/Tests/FluentAssertions.Specs/Collections/CollectionAssertionSpecs.HaveCountLessThanOrEqualTo.cs index f308100d53..e7858c6663 100644 --- a/Tests/FluentAssertions.Specs/Collections/CollectionAssertionSpecs.HaveCountLessThanOrEqualTo.cs +++ b/Tests/FluentAssertions.Specs/Collections/CollectionAssertionSpecs.HaveCountLessThanOrEqualTo.cs @@ -46,7 +46,7 @@ public void When_collection_has_a_count_less_than_or_equal_to_the_number_of_item // Assert action.Should().Throw() - .WithMessage("*at most*2*because we want to test the failure message*3*"); + .WithMessage("Expected collection to contain at most 2 item(s) because we want to test the failure message, but found 3: {1, 2, 3}."); } [Fact] diff --git a/Tests/FluentAssertions.Specs/Collections/GenericCollectionAssertionOfStringSpecs.cs b/Tests/FluentAssertions.Specs/Collections/GenericCollectionAssertionOfStringSpecs.cs index da537fd411..bc5ececcc1 100644 --- a/Tests/FluentAssertions.Specs/Collections/GenericCollectionAssertionOfStringSpecs.cs +++ b/Tests/FluentAssertions.Specs/Collections/GenericCollectionAssertionOfStringSpecs.cs @@ -1075,7 +1075,7 @@ public void // Assert action.Should().Throw() .WithMessage( - "Expected collection {\"one\", \"two\", \"three\"} to contain 4 item(s) because we want to test the failure message, but found 3."); + "Expected collection to contain 4 item(s) because we want to test the failure message, but found 3: {\"one\", \"two\", \"three\"}."); } [Fact] @@ -1089,7 +1089,7 @@ public void When_collection_has_a_count_that_not_matches_the_predicate_it_should // Assert act.Should().Throw().WithMessage( - "Expected collection {\"one\", \"two\", \"three\"} to have a count (c >= 4) because a minimum of 4 is required, but count is 3."); + "Expected collection to have a count (c >= 4) because a minimum of 4 is required, but count is 3: {\"one\", \"two\", \"three\"}."); } [Fact] @@ -1664,6 +1664,7 @@ public void When_using_StringCollectionAssertions_the_AndConstraint_should_have_ from method in methodInfo where !method.IsSpecialName // Exclude Properties where method.DeclaringType != typeof(object) + where method.Name != "Equals" select new { method.Name, method.ReturnType }; // Assert diff --git a/Tests/FluentAssertions.Specs/Collections/GenericDictionaryAssertionSpecs.cs b/Tests/FluentAssertions.Specs/Collections/GenericDictionaryAssertionSpecs.cs index dcc60efcd1..a60f261f50 100644 --- a/Tests/FluentAssertions.Specs/Collections/GenericDictionaryAssertionSpecs.cs +++ b/Tests/FluentAssertions.Specs/Collections/GenericDictionaryAssertionSpecs.cs @@ -172,7 +172,7 @@ public void // Assert action.Should().Throw() - .WithMessage("Expected dictionary {[1] = \"One\", [2] = \"Two\", [3] = \"Three\"} to contain 4 item(s) because we want to test the failure message, but found 3."); + .WithMessage("Expected dictionary to contain 4 item(s) because we want to test the failure message, but found 3: {[1] = \"One\", [2] = \"Two\", [3] = \"Three\"}."); } [Fact] @@ -206,7 +206,7 @@ public void When_dictionary_has_a_count_that_not_matches_the_predicate_it_should // Assert act.Should().Throw().WithMessage( - "Expected dictionary {[1] = \"One\", [2] = \"Two\", [3] = \"Three\"} to have a count (c >= 4) because a minimum of 4 is required, but count is 3."); + "Expected dictionary to have a count (c >= 4) because a minimum of 4 is required, but count is 3: {[1] = \"One\", [2] = \"Two\", [3] = \"Three\"}."); } [Fact] @@ -378,7 +378,7 @@ public void When_dictionary_has_a_count_greater_than_the_number_of_items_it_shou // Assert action.Should().Throw() - .WithMessage("*more than*3*because we want to test the failure message*3*"); + .WithMessage("Expected dictionary to contain more than 3 item(s) because we want to test the failure message, but found 3: {[1] = \"One\", [2] = \"Two\", [3] = \"Three\"}."); } [Fact] @@ -447,7 +447,7 @@ public void When_dictionary_has_a_count_greater_than_or_equal_to_the_number_of_i // Assert action.Should().Throw() - .WithMessage("*at least*4*because we want to test the failure message*3*"); + .WithMessage("Expected dictionary to contain at least 4 item(s) because we want to test the failure message, but found 3: {[1] = \"One\", [2] = \"Two\", [3] = \"Three\"}."); } [Fact] @@ -516,7 +516,7 @@ public void When_dictionary_has_a_count_less_than_the_number_of_items_it_should_ // Assert action.Should().Throw() - .WithMessage("*fewer than*3*because we want to test the failure message*3*"); + .WithMessage("Expected dictionary to contain fewer than 3 item(s) because we want to test the failure message, but found 3: {[1] = \"One\", [2] = \"Two\", [3] = \"Three\"}."); } [Fact] @@ -585,7 +585,7 @@ public void When_dictionary_has_a_count_less_than_or_equal_to_the_number_of_item // Assert action.Should().Throw() - .WithMessage("*at most*2*because we want to test the failure message*3*"); + .WithMessage("Expected dictionary to contain at most 2 item(s) because we want to test the failure message, but found 3: {[1] = \"One\", [2] = \"Two\", [3] = \"Three\"}."); } [Fact] diff --git a/Tests/FluentAssertions.Specs/CultureAwareTesting/DictionaryExtensions.cs b/Tests/FluentAssertions.Specs/CultureAwareTesting/DictionaryExtensions.cs index 0c505d6d69..ec13b58de9 100644 --- a/Tests/FluentAssertions.Specs/CultureAwareTesting/DictionaryExtensions.cs +++ b/Tests/FluentAssertions.Specs/CultureAwareTesting/DictionaryExtensions.cs @@ -10,7 +10,7 @@ public static void Add(this IDictionary> dictio public static TValue GetOrAdd(this IDictionary dictionary, TKey key) where TValue : new() => - dictionary.GetOrAdd(key, () => new TValue()); + dictionary.GetOrAdd(key, static () => new TValue()); public static TValue GetOrAdd(this IDictionary dictionary, TKey key, Func newValue) { diff --git a/Tests/FluentAssertions.Specs/Specialized/TaskAssertionSpecs.cs b/Tests/FluentAssertions.Specs/Specialized/TaskAssertionSpecs.cs index c0bd5d5873..3f6f5237f9 100644 --- a/Tests/FluentAssertions.Specs/Specialized/TaskAssertionSpecs.cs +++ b/Tests/FluentAssertions.Specs/Specialized/TaskAssertionSpecs.cs @@ -1,6 +1,7 @@ using System; using System.Threading; using System.Threading.Tasks; +using FluentAssertions.Common; using FluentAssertions.Extensions; using Xunit; using Xunit.Sdk; @@ -26,7 +27,6 @@ public void When_getting_the_subject_it_should_remain_unchanged() public async Task When_subject_is_null_when_expecting_to_complete_async_it_should_throw() { // Arrange - var timer = new FakeClock(); var timeSpan = 0.Milliseconds(); Func action = null; @@ -55,6 +55,30 @@ public async Task When_task_completes_fast_async_it_should_succeed() await action.Should().NotThrowAsync(); } + [Fact] + public async Task Sync_work_in_async_method_is_taken_into_account() + { + // Arrange + var timer = new FakeClock(); + var taskFactory = new TaskCompletionSource(); + + // Act + Func action = () => taskFactory + .Awaiting(t => + { + timer.Delay(101.Milliseconds()); + return (Task)t.Task; + }) + .Should(timer) + .CompleteWithinAsync(100.Milliseconds()); + + taskFactory.SetResult(true); + timer.Complete(); + + // Assert + await action.Should().ThrowAsync(); + } + [UIFact] public async Task When_task_completes_on_UI_thread_fast_async_it_should_succeed() { diff --git a/Tests/FluentAssertions.Specs/Specialized/TaskOfTAssertionSpecs.cs b/Tests/FluentAssertions.Specs/Specialized/TaskOfTAssertionSpecs.cs index 37d8734710..cac0b519ae 100644 --- a/Tests/FluentAssertions.Specs/Specialized/TaskOfTAssertionSpecs.cs +++ b/Tests/FluentAssertions.Specs/Specialized/TaskOfTAssertionSpecs.cs @@ -122,6 +122,32 @@ public async Task When_task_completes_slow_async_it_should_fail() await action.Should().ThrowAsync(); } + [Fact] + public async Task Sync_work_in_async_method_is_taken_into_account() + { + // Arrange + var timer = new FakeClock(); + var taskFactory = new TaskCompletionSource(); + + // Act + Func action = () => + { + Func> func = () => + { + timer.Delay(101.Milliseconds()); + return taskFactory.Task; + }; + + return func.Should(timer).CompleteWithinAsync(100.Milliseconds()); + }; + + taskFactory.SetResult(99); + timer.Complete(); + + // Assert + await action.Should().ThrowAsync(); + } + #endregion #region NotThrowAfterAsync diff --git a/Tests/FluentAssertions.Specs/Types/MethodInfoSelectorSpecs.cs b/Tests/FluentAssertions.Specs/Types/MethodInfoSelectorSpecs.cs index b4969f8e4a..f32f2c9911 100644 --- a/Tests/FluentAssertions.Specs/Types/MethodInfoSelectorSpecs.cs +++ b/Tests/FluentAssertions.Specs/Types/MethodInfoSelectorSpecs.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Reflection; +using System.Threading.Tasks; using FluentAssertions.Types; using Internal.Main.Test; using Xunit; @@ -272,6 +273,66 @@ public void When_selecting_methods_not_decorated_with_a_noninheritable_attribute methods.Should().ContainSingle(); } + [Fact] + public void When_selecting_methods_that_are_async_it_should_only_return_the_applicable_methods() + { + // Arrange + Type type = typeof(TestClassForMethodSelectorWithAsyncAndNonAsyncMethod); + + // Act + MethodInfo[] methods = type.Methods().ThatAreAsync().ToArray(); + + // Assert + methods.Should().ContainSingle() + .Which.Name.Should().Be("PublicAsyncMethod"); + } + + [Fact] + public void When_selecting_methods_that_are_not_async_it_should_only_return_the_applicable_methods() + { + // Arrange + Type type = typeof(TestClassForMethodSelectorWithAsyncAndNonAsyncMethod); + + // Act + MethodInfo[] methods = type.Methods().ThatAreNotAsync().ToArray(); + + // Assert + methods.Should().ContainSingle() + .Which.Name.Should().Be("PublicNonAsyncMethod"); + } + + [Fact] + public void When_selecting_methods_that_are_virtual_it_should_only_return_the_applicable_methods() + { + // Arrange + Type type = typeof(TestClassForMethodSelector); + + // Act + MethodInfo[] methods = type.Methods().ThatAreVirtual().ToArray(); + + // Assert + methods.Should() + .NotBeEmpty() + .And.Contain(m => m.Name == "PublicVirtualVoidMethodWithAttribute") + .And.Contain(m => m.Name == "ProtectedVirtualVoidMethodWithAttribute"); + } + + [Fact] + public void When_selecting_methods_that_are_not_virtual_it_should_only_return_the_applicable_methods() + { + // Arrange + Type type = typeof(TestClassForMethodSelector); + + // Act + MethodInfo[] methods = type.Methods().ThatAreNotVirtual().ToArray(); + + // Assert + methods.Should() + .NotBeEmpty() + .And.NotContain(m => m.Name == "PublicVirtualVoidMethodWithAttribute") + .And.NotContain(m => m.Name == "ProtectedVirtualVoidMethodWithAttribute"); + } + [Fact] public void When_selecting_methods_not_decorated_with_or_inheriting_a_noninheritable_attribute_it_should_only_return_the_applicable_methods() { @@ -367,6 +428,13 @@ internal class TestClassForMethodSelectorWithNonInheritableAttributeDerived : Te public override void PublicVirtualVoidMethodWithAttribute() { } } + internal class TestClassForMethodSelectorWithAsyncAndNonAsyncMethod + { + public async Task PublicAsyncMethod() => await Task.Yield(); + + public Task PublicNonAsyncMethod() => Task.CompletedTask; + } + internal class TestClassForMethodReturnTypesSelector { public void SomeMethod() { } diff --git a/Tests/TestFrameworks/MSTestV2.Specs/MSTestV2.Specs.csproj b/Tests/TestFrameworks/MSTestV2.Specs/MSTestV2.Specs.csproj index d2374ab93b..d60bf9ca56 100644 --- a/Tests/TestFrameworks/MSTestV2.Specs/MSTestV2.Specs.csproj +++ b/Tests/TestFrameworks/MSTestV2.Specs/MSTestV2.Specs.csproj @@ -1,6 +1,6 @@  - netcoreapp2.1 + net5.0 MSTestV2.Specs MSTestV2.Specs ..\..\..\TestRules.ruleset diff --git a/Tests/TestFrameworks/MSpec.Specs/MSpec.Specs.csproj b/Tests/TestFrameworks/MSpec.Specs/MSpec.Specs.csproj index 7ffdb8cd3b..b826bbc1f0 100644 --- a/Tests/TestFrameworks/MSpec.Specs/MSpec.Specs.csproj +++ b/Tests/TestFrameworks/MSpec.Specs/MSpec.Specs.csproj @@ -1,6 +1,6 @@  - netcoreapp2.1 + net5.0 MSpec.Specs MSpec.Specs Rules.ruleset diff --git a/Tests/TestFrameworks/NUnit3.Specs/NUnit3.Specs.csproj b/Tests/TestFrameworks/NUnit3.Specs/NUnit3.Specs.csproj index cb12710ce5..4403e37741 100644 --- a/Tests/TestFrameworks/NUnit3.Specs/NUnit3.Specs.csproj +++ b/Tests/TestFrameworks/NUnit3.Specs/NUnit3.Specs.csproj @@ -1,6 +1,6 @@  - netcoreapp2.1 + net5.0 NUnit3.Specs NUnit3.Specs ..\..\..\TestRules.ruleset diff --git a/Tests/TestFrameworks/XUnit2.Specs/XUnit2.Specs.csproj b/Tests/TestFrameworks/XUnit2.Specs/XUnit2.Specs.csproj index a63c9f07e9..98ff65410f 100644 --- a/Tests/TestFrameworks/XUnit2.Specs/XUnit2.Specs.csproj +++ b/Tests/TestFrameworks/XUnit2.Specs/XUnit2.Specs.csproj @@ -1,6 +1,6 @@  - net47;netcoreapp2.1 + net47;net5.0 XUnit2.Specs XUnit2.Specs ..\..\..\TestRules.ruleset diff --git a/build.sh b/build.sh index d287496012..435dac52bc 100755 --- a/build.sh +++ b/build.sh @@ -9,7 +9,7 @@ SCRIPT_DIR=$(cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd) # CONFIGURATION ########################################################################### -BUILD_PROJECT_FILE="$SCRIPT_DIR/build/_build.csproj" +BUILD_PROJECT_FILE="$SCRIPT_DIR/Build/_build.csproj" TEMP_DIRECTORY="$SCRIPT_DIR//.nuke/temp" DOTNET_GLOBAL_FILE="$SCRIPT_DIR//global.json" diff --git a/docs/_pages/collections.md b/docs/_pages/collections.md index e47f528a49..4874c4a858 100644 --- a/docs/_pages/collections.md +++ b/docs/_pages/collections.md @@ -11,7 +11,7 @@ A collection object in .NET is so versatile that the number of assertions on the Most, if not all, are so self-explanatory that we'll just list them here. ```csharp -IEnumerable collection = new[] { 1, 2, 5, 8 }; +IEnumerable collection = new[] { 1, 2, 5, 8 }; collection.Should().NotBeEmpty() .And.HaveCount(4) @@ -76,8 +76,8 @@ collection.Should().BeEmpty(); collection.Should().BeNullOrEmpty(); collection.Should().NotBeNullOrEmpty(); -IEnumerable otherCollection = new[] { 1, 2, 5, 8, 1 }; -IEnumerable anotherCollection = new[] { 10, 20, 50, 80, 10 }; +IEnumerable otherCollection = new[] { 1, 2, 5, 8, 1 }; +IEnumerable anotherCollection = new[] { 10, 20, 50, 80, 10 }; collection.Should().IntersectWith(otherCollection); collection.Should().NotIntersectWith(anotherCollection); ``` diff --git a/docs/_pages/objectgraphs.md b/docs/_pages/objectgraphs.md index 20f0f0239a..7d43564de1 100644 --- a/docs/_pages/objectgraphs.md +++ b/docs/_pages/objectgraphs.md @@ -181,7 +181,7 @@ In addition to influencing the members that are including in the comparison, you ```csharp orderDto.Should().BeEquivalentTo(order, options => options .Using(ctx => ctx.Subject.Should().BeCloseTo(ctx.Expectation, 1.Seconds())) - .When(info => info.Name == "Date")); + .When(info => info.Path.EndsWith("Date"))); ``` If you want to do this for all members of a certain type, you can shorten the above call like this. diff --git a/docs/_pages/releases.md b/docs/_pages/releases.md index d4663db0a4..b7846665a0 100644 --- a/docs/_pages/releases.md +++ b/docs/_pages/releases.md @@ -10,8 +10,14 @@ sidebar: ## Unreleased ### What's New +* Adding `ThatAreAsync()` and `ThatAreNotAsync()` for filtering in method assertions - [#1725](https://github.com/fluentassertions/fluentassertions/pull/1725) +* Adding `ThatAreVirtual()` and `ThatAreNotVirtual()` for filtering in method assertions - [#1744](https://github.com/fluentassertions/fluentassertions/pull/1744) +* Adding collection content to assertion messages for `HaveCountGreaterThan()`, `HaveCountGreaterThanOrEqualTo()`, `HaveCountLessThan()` and `HaveCountLessThanOrEqualTo()` - [#1760](https://github.com/fluentassertions/fluentassertions/pull/1760) ### Fixes +* Prevent multiple enumeration of `IEnumerable`s in parameter-less `ContainSingle()` - [#1753](https://github.com/fluentassertions/fluentassertions/pull/1753) +* Change `HaveCount()` assertion message order to state expected and actual collection count before dumping its content` - [#1760](https://github.com/fluentassertions/fluentassertions/pull/1760) +* `CompleteWithinAsync` did not take initial sync computation into account when measuring execution time - [1762](https://github.com/fluentassertions/fluentassertions/pull/1762). ## 6.2.0 @@ -26,7 +32,7 @@ sidebar: * `At` now retains the `DateTimeKind` and keeps sub-second precision when using a `TimeSpan` - [#1687](https://github.com/fluentassertions/fluentassertions/pull/1687). * Removed iteration over enumerable when generating the `BeEmpty` assertion failure message - [#1692](https://github.com/fluentassertions/fluentassertions/pull/1692). * Prevent `ArgumentNullException` when formatting a lambda expression containing an extension method - [#1696](https://github.com/fluentassertions/fluentassertions/pull/1696) -* `IgnoringCyclicReferences` in `BeEquivalentTo` now works while comparing value types using `ComparingByMembers` - [#1708](https://github.com/fluentassertions/fluentassertions/pull/1708) +* `IgnoringCyclicReferences` in `BeEquivalentTo` now works while comparing value types using `ComparingByMembers` - [#1708](https://github.com/fluentassertions/fluentassertions/pull/1708) * Using `BeEquivalentTo` on a collection with nested collections would complain about missing members - [#1713](https://github.com/fluentassertions/fluentassertions/pull/1713) * Formatting a lambda expression containing lifted operators - [#1714](https://github.com/fluentassertions/fluentassertions/pull/1714). * Performance improvements in `BeEquivalentTo` by caching expensive Reflection operations - [#1719](https://github.com/fluentassertions/fluentassertions/pull/1719) diff --git a/docs/index.html b/docs/index.html index b71cf8c233..c5349dcddc 100644 --- a/docs/index.html +++ b/docs/index.html @@ -10,12 +10,13 @@ cta_url: "https://www.continuousimprover.com/2021/08/fluent-assertions-v6" caption: "Logo by [**IUserName**](https://github.com/IUsername) and icons by [**Zlatko Najdenovski**](https://www.flaticon.com/authors/zlatko-najdenovski) from [Flaticon](https://www.flaticon.com/) " -excerpt: '_"With Fluent Assertions, the assertions look beautiful, natural and, most importantly, extremely readable"_ - [Girish](https://twitter.com/girishracharya) -
+excerpt: '_"There''s a life before Fluent Assertions, and there''s a life after it"_ - [Meisam Alifallahi](https://www.linkedin.com/in/meisam-alifallahi/) +
![](https://img.shields.io/nuget/dt/FluentAssertions.svg?style=for-the-badge) [![](https://img.shields.io/github/release/fluentassertions/fluentassertions.svg?style=for-the-badge&label=Latest)](https://github.com/fluentassertions/fluentassertions/releases/latest) [![](https://img.shields.io/github/stars/fluentassertions/fluentassertions.svg?style=for-the-badge&label=Star)](https://github.com/fluentassertions/fluentassertions/stargazers) [![](https://img.shields.io/github/forks/fluentassertions/fluentassertions.svg?style=for-the-badge&label=Fork)](https://github.com/fluentassertions/fluentassertions/fork) +[![](https://img.shields.io/github/sponsors/fluentassertions?style=for-the-badge&label=Sponsors)](https://github.com/sponsors/fluentassertions) ' intro: - excerpt: '