From 179fe62b67dfabc4e38c34e9f62afe2d2ead91c8 Mon Sep 17 00:00:00 2001 From: Dennis Doomen Date: Sun, 9 Sep 2018 19:15:43 +0200 Subject: [PATCH] Comparing an object graph against IEnumerable works now as expected --- .../Collections/CollectionAssertions.cs | 65 ++++++++++++++++++ .../NonGenericCollectionAssertions.cs | 67 ------------------- .../CollectionEquivalencySpecs.cs | 40 +++++++++++ 3 files changed, 105 insertions(+), 67 deletions(-) diff --git a/Src/FluentAssertions/Collections/CollectionAssertions.cs b/Src/FluentAssertions/Collections/CollectionAssertions.cs index b795e0a79d..8f16f4c2f2 100644 --- a/Src/FluentAssertions/Collections/CollectionAssertions.cs +++ b/Src/FluentAssertions/Collections/CollectionAssertions.cs @@ -349,6 +349,71 @@ public AndConstraint BeEquivalentTo(params object[] expectations) return new AndConstraint((TAssertions)this); } + /// + /// Asserts that a collection of objects is equivalent to another collection of objects. + /// + /// + /// Objects within the collections are equivalent when both object graphs have equally named properties with the same + /// value, irrespective of the type of those objects. Two properties are also equal if one type can be converted to another + /// and the result is equal. + /// The type of a collection property is ignored as long as the collection implements and all + /// items in the collection are structurally equal. + /// Notice that actual behavior is determined by the global defaults managed by . + /// + public AndConstraint BeEquivalentTo(IEnumerable expectation, string because = "", params object[] becauseArgs) + { + BeEquivalentTo(expectation, config => config, because, becauseArgs); + + return new AndConstraint((TAssertions)this); + } + + /// + /// Asserts that a collection of objects is equivalent to another collection of objects. + /// + /// + /// Objects within the collections are equivalent when both object graphs have equally named properties with the same + /// value, irrespective of the type of those objects. Two properties are also equal if one type can be converted to another + /// and the result is equal. + /// The type of a collection property is ignored as long as the collection implements and all + /// items in the collection are structurally equal. + /// Notice that actual behavior is determined by the global defaults managed by . + /// + /// + /// A reference to the configuration object that can be used + /// to influence the way the object graphs are compared. You can also provide an alternative instance of the + /// class. The global defaults are determined by the + /// class. + /// + /// + /// An optional formatted phrase as is supported by explaining why the + /// assertion is needed. If the phrase does not start with the word because, it is prepended automatically. + /// + /// + /// Zero or more objects to format using the placeholders in . + /// + public AndConstraint BeEquivalentTo(IEnumerable expectation, + Func, EquivalencyAssertionOptions> config, string because = "", + params object[] becauseArgs) + { + EquivalencyAssertionOptions options = config(AssertionOptions.CloneDefaults()); + + var context = new EquivalencyValidationContext + { + Subject = Subject, + Expectation = expectation, + RootIsCollection = true, + CompileTimeType = typeof(IEnumerable), + Because = because, + BecauseArgs = becauseArgs, + Tracer = options.TraceWriter + }; + + var equivalencyValidator = new EquivalencyValidator(options); + equivalencyValidator.AssertEquality(context); + + return new AndConstraint((TAssertions)this); + } + /// /// Asserts that a collection of objects is equivalent to another collection of objects. /// diff --git a/Src/FluentAssertions/Collections/NonGenericCollectionAssertions.cs b/Src/FluentAssertions/Collections/NonGenericCollectionAssertions.cs index 89cb6d125d..7f462141d6 100644 --- a/Src/FluentAssertions/Collections/NonGenericCollectionAssertions.cs +++ b/Src/FluentAssertions/Collections/NonGenericCollectionAssertions.cs @@ -301,72 +301,5 @@ private int GetMostLocalCount() return base.NotContain(new[] { unexpected }, because, becauseArgs); } - - /// - /// Asserts that a collection of objects is equivalent to another collection of objects. - /// - /// - /// Objects within the collections are equivalent when both object graphs have equally named properties with the same - /// value, irrespective of the type of those objects. Two properties are also equal if one type can be converted to another - /// and the result is equal. - /// The type of a collection property is ignored as long as the collection implements and all - /// items in the collection are structurally equal. - /// Notice that actual behavior is determined by the global defaults managed by . - /// - /// - /// An optional formatted phrase as is supported by explaining why the - /// assertion is needed. If the phrase does not start with the word because, it is prepended automatically. - /// - /// - /// Zero or more objects to format using the placeholders in . - /// - public void BeEquivalentTo(IEnumerable expectation, string because = "", params object[] becauseArgs) - { - BeEquivalentTo(expectation, config => config, because, becauseArgs); - } - - /// - /// Asserts that a collection of objects is equivalent to another collection of objects. - /// - /// - /// Objects within the collections are equivalent when both object graphs have equally named properties with the same - /// value, irrespective of the type of those objects. Two properties are also equal if one type can be converted to another - /// and the result is equal. - /// The type of a collection property is ignored as long as the collection implements and all - /// items in the collection are structurally equal. - /// - /// - /// A reference to the configuration object that can be used - /// to influence the way the object graphs are compared. You can also provide an alternative instance of the - /// class. The global defaults are determined by the - /// class. - /// - /// - /// An optional formatted phrase as is supported by explaining why the - /// assertion is needed. If the phrase does not start with the word because, it is prepended automatically. - /// - /// - /// Zero or more objects to format using the placeholders in . - /// - public void BeEquivalentTo(IEnumerable expectation, - Func, EquivalencyAssertionOptions> config, string because = "", - params object[] becauseArgs) - { - EquivalencyAssertionOptions options = config(AssertionOptions.CloneDefaults()); - - var context = new EquivalencyValidationContext - { - Subject = Subject, - Expectation = expectation, - RootIsCollection = true, - CompileTimeType = typeof(IEnumerable), - Because = because, - BecauseArgs = becauseArgs, - Tracer = options.TraceWriter - }; - - var equivalencyValidator = new EquivalencyValidator(options); - equivalencyValidator.AssertEquality(context); - } } } diff --git a/Tests/Shared.Specs/CollectionEquivalencySpecs.cs b/Tests/Shared.Specs/CollectionEquivalencySpecs.cs index e34c9838e0..5d54449da8 100644 --- a/Tests/Shared.Specs/CollectionEquivalencySpecs.cs +++ b/Tests/Shared.Specs/CollectionEquivalencySpecs.cs @@ -1142,6 +1142,46 @@ public void When_asserting_equivalence_of_non_generic_collections_it_should_resp .WithMessage("*Wheels*not have*VehicleId*not have*"); } + [Fact] + public void When_comparing_against_a_non_generic_collection_it_should_treat_it_as_unordered_collection_of_objects() + { + //----------------------------------------------------------------------------------------------------------- + // Arrange + //----------------------------------------------------------------------------------------------------------- + List actual = new List { typeof(int), typeof(string) }; + IEnumerable expectation = new List { typeof(string), typeof(int) }; + + //----------------------------------------------------------------------------------------------------------- + // Act + //----------------------------------------------------------------------------------------------------------- + Action act = () => actual.Should().BeEquivalentTo(expectation); + + //----------------------------------------------------------------------------------------------------------- + // Assert + //----------------------------------------------------------------------------------------------------------- + act.Should().NotThrow(); + } + + [Fact] + public void When_comparing_against_a_non_generic_collection_it_should_treat_it_as_collection_of_objects() + { + //----------------------------------------------------------------------------------------------------------- + // Arrange + //----------------------------------------------------------------------------------------------------------- + List actual = new List { typeof(int), typeof(string) }; + IEnumerable expectation = new List { typeof(string), typeof(int) }; + + //----------------------------------------------------------------------------------------------------------- + // Act + //----------------------------------------------------------------------------------------------------------- + Action act = () => actual.Should().BeEquivalentTo(expectation); + + //----------------------------------------------------------------------------------------------------------- + // Assert + //----------------------------------------------------------------------------------------------------------- + act.Should().NotThrow(); + } + [Fact] public void When_custom_assertion_rules_are_utilized_the_rules_should_be_respected() {