From a100ffec39fddfa43d277492986e36183b8527ff Mon Sep 17 00:00:00 2001 From: Dennis Doomen Date: Sat, 21 Jan 2023 14:00:58 +0100 Subject: [PATCH] Regrouping and formatting of the selection rule specs --- .../SelectionRulesSpecs.cs | 3574 +++++++++-------- 1 file changed, 1917 insertions(+), 1657 deletions(-) diff --git a/Tests/FluentAssertions.Equivalency.Specs/SelectionRulesSpecs.cs b/Tests/FluentAssertions.Equivalency.Specs/SelectionRulesSpecs.cs index d17b109b17..f1ad0b2239 100644 --- a/Tests/FluentAssertions.Equivalency.Specs/SelectionRulesSpecs.cs +++ b/Tests/FluentAssertions.Equivalency.Specs/SelectionRulesSpecs.cs @@ -12,2045 +12,2309 @@ namespace FluentAssertions.Equivalency.Specs; public class SelectionRulesSpecs { - private enum LocalOtherType : byte + public class Basic { - Default, - NonDefault - } - - private enum LocalType : byte - { - Default, - NonDefault - } - - [Fact] - public void When_specific_properties_have_been_specified_it_should_ignore_the_other_properties() - { - // Arrange - var subject = new + [Fact] + public void When_a_property_is_an_indexer_it_should_be_ignored() { - Age = 36, - Birthdate = new DateTime(1973, 9, 20), - Name = "John" - }; + // Arrange + var expected = new ClassWithIndexer + { + Foo = "test" + }; - var customer = new - { - Age = 36, - Birthdate = new DateTime(1973, 9, 20), - Name = "Dennis" - }; + var result = new ClassWithIndexer + { + Foo = "test" + }; - // Act - Action act = () => subject.Should().BeEquivalentTo(customer, options => options - .Including(d => d.Age) - .Including(d => d.Birthdate)); + // Act + Action act = () => result.Should().BeEquivalentTo(expected); - // Assert - act.Should().NotThrow(); - } + // Assert + act.Should().NotThrow(); + } - [Fact] - public void A_member_included_by_path_is_described_in_the_failure_message() - { - // Arrange - var subject = new + public class ClassWithIndexer { - Name = "John" - }; + public object Foo { get; set; } + + public string this[int n] => + n.ToString( + CultureInfo.InvariantCulture); + } - var customer = new + [Fact] + public void When_the_expected_object_has_a_property_not_available_on_the_subject_it_should_throw() { - Name = "Jack" - }; + // Arrange + var subject = new + { + }; - // Act - Action act = () => subject.Should().BeEquivalentTo(customer, options => options - .Including(d => d.Name)); + var other = new + { + // ReSharper disable once StringLiteralTypo + City = "Rijswijk" + }; - // Assert - act.Should().Throw() - .WithMessage("*Include*Name*"); - } + // Act + Action act = () => subject.Should().BeEquivalentTo(other); - [Fact] - public void A_member_included_by_predicate_is_described_in_the_failure_message() - { - // Arrange - var subject = new - { - Name = "John" - }; + // Assert + act.Should().Throw().WithMessage( + "Expectation has property subject.City that the other object does not have*"); + } - var customer = new + [Fact] + public void When_equally_named_properties_are_type_incompatible_it_should_throw() { - Name = "Jack" - }; + // Arrange + var subject = new + { + Type = "A" + }; - // Act - Action act = () => subject.Should().BeEquivalentTo(customer, options => options - .Including(ctx => ctx.Path == "Name")); + var other = new + { + Type = 36 + }; - // Assert - act.Should().Throw() - .WithMessage("*Include member when*Name*"); - } + // Act + Action act = () => subject.Should().BeEquivalentTo(other); - [Fact] - public void A_member_excluded_by_path_is_described_in_the_failure_message() - { - // Arrange - var subject = new - { - Name = "John", - Age = 13 - }; + // Assert + act + .Should().Throw() + .WithMessage("Expected property subject.Type to be 36, but found*\"A\"*"); + } - var customer = new + [Fact] + public void When_multiple_properties_mismatch_it_should_report_all_of_them() { - Name = "Jack", - Age = 37 - }; + // Arrange + var subject = new + { + Property1 = "A", + Property2 = "B", + SubType1 = new + { + SubProperty1 = "C", + SubProperty2 = "D" + } + }; - // Act - Action act = () => subject.Should().BeEquivalentTo(customer, options => options - .Excluding(d => d.Age)); + var other = new + { + Property1 = "1", + Property2 = "2", + SubType1 = new + { + SubProperty1 = "3", + SubProperty2 = "D" + } + }; - // Assert - act.Should().Throw() - .WithMessage("*Exclude*Age*"); - } + // Act + Action act = () => subject.Should().BeEquivalentTo(other); - [Fact] - public void A_member_excluded_by_predicate_is_described_in_the_failure_message() - { - // Arrange - var subject = new - { - Name = "John", - Age = 13 - }; + // Assert + act + .Should().Throw() + .WithMessage("*property subject.Property1*to be \"1\", but \"A\" differs near \"A\"*") + .WithMessage("*property subject.Property2*to be \"2\", but \"B\" differs near \"B\"*") + .WithMessage("*property subject.SubType1.SubProperty1*to be \"3\", but \"C\" differs near \"C\"*"); + } - var customer = new + [Fact] + [SuppressMessage("ReSharper", "StringLiteralTypo")] + public void Including_all_declared_properties_excludes_all_fields() { - Name = "Jack", - Age = 37 - }; + // Arrange + var class1 = new ClassWithSomeFieldsAndProperties + { + Field1 = "Lorem", + Field2 = "ipsum", + Field3 = "dolor", + Property1 = "sit", + Property2 = "amet", + Property3 = "consectetur" + }; - // Act - Action act = () => subject.Should().BeEquivalentTo(customer, options => options - .Excluding(ctx => ctx.Path == "Age")); + var class2 = new ClassWithSomeFieldsAndProperties + { + Property1 = "sit", + Property2 = "amet", + Property3 = "consectetur" + }; - // Assert - act.Should().Throw() - .WithMessage("*Exclude member when*Age*"); - } + // Act + Action act = + () => class1.Should().BeEquivalentTo(class2, opts => opts.IncludingAllDeclaredProperties()); - [Fact] - public void When_a_predicate_for_properties_to_include_has_been_specified_it_should_ignore_the_other_properties() - { - // Arrange - var subject = new - { - Age = 36, - Birthdate = new DateTime(1973, 9, 20), - Name = "John" - }; + // Assert + act.Should().NotThrow(); + } - var customer = new + [Fact] + [SuppressMessage("ReSharper", "StringLiteralTypo")] + public void Including_all_runtime_properties_excludes_all_fields() { - Age = 36, - Birthdate = new DateTime(1973, 9, 20), - Name = "Dennis" - }; + // Arrange + object class1 = new ClassWithSomeFieldsAndProperties + { + Field1 = "Lorem", + Field2 = "ipsum", + Field3 = "dolor", + Property1 = "sit", + Property2 = "amet", + Property3 = "consectetur" + }; - // Act - Action act = () => subject.Should().BeEquivalentTo(customer, options => options - .Including(info => info.Path.EndsWith("Age", StringComparison.Ordinal)) - .Including(info => info.Path.EndsWith("Birthdate", StringComparison.Ordinal))); + object class2 = new ClassWithSomeFieldsAndProperties + { + Property1 = "sit", + Property2 = "amet", + Property3 = "consectetur" + }; - // Assert - act.Should().NotThrow(); - } + // Act + Action act = + () => class1.Should().BeEquivalentTo(class2, opts => opts.IncludingAllRuntimeProperties()); - [Fact] - public void When_a_non_property_expression_is_provided_it_should_throw() - { - // Arrange - var dto = new CustomerDto(); + // Assert + act.Should().NotThrow(); + } + + [Fact] + [SuppressMessage("ReSharper", "StringLiteralTypo")] + public void Respecting_the_runtime_type_includes_both_properties_and_fields_included() + { + // Arrange + object class1 = new ClassWithSomeFieldsAndProperties + { + Field1 = "Lorem", + Property1 = "sit" + }; - // Act - Action act = () => dto.Should().BeEquivalentTo(dto, options => options.Including(d => d.GetType())); + object class2 = new ClassWithSomeFieldsAndProperties(); - // Assert - act.Should().Throw() - .WithMessage("Expression cannot be used to select a member.*") - .WithParameterName("expression"); - } + // Act + Action act = + () => class1.Should().BeEquivalentTo(class2, opts => opts.RespectingRuntimeTypes()); - [Fact] - public void When_including_a_property_it_should_exactly_match_the_property() - { - // Arrange - var actual = new - { - DeclaredType = LocalOtherType.NonDefault, - Type = LocalType.NonDefault - }; + // Assert + act.Should().Throw().Which.Message.Should().Contain("Field1").And.Contain("Property1"); + } - var expectation = new + [Fact] + public void A_nested_class_without_properties_inside_a_collection_is_fine() { - DeclaredType = LocalOtherType.NonDefault - }; + // Arrange + var sut = new List + { + new BaseClassPointingToClassWithoutProperties + { + Name = "theName" + } + }; - // Act - Action act = () => actual.Should().BeEquivalentTo(expectation, - config => config.Including(o => o.DeclaredType)); + // Act / Assert + sut.Should().BeEquivalentTo(new[] + { + new BaseClassPointingToClassWithoutProperties + { + Name = "theName" + } + }); + } - // Assert - act.Should().NotThrow(); - } + internal class BaseClassPointingToClassWithoutProperties + { + public string Name { get; set; } - public class CustomType - { - public string Name { get; set; } - } + public ClassWithoutProperty ClassWithoutProperty { get; } = new ClassWithoutProperty(); + } - public class ClassA - { - public List ListOfCustomTypes { get; set; } + internal class ClassWithoutProperty + { + } } - [Fact] - public void When_including_a_property_using_an_expression_it_should_evaluate_it_from_the_root() + public class Including { - // Arrange - var list1 = new List - { - new CustomType { Name = "A" }, - new CustomType { Name = "B" } - }; - - var list2 = new List + [Fact] + public void When_specific_properties_have_been_specified_it_should_ignore_the_other_properties() { - new CustomType { Name = "C" }, - new CustomType { Name = "D" } - }; - - var objectA = new ClassA { ListOfCustomTypes = list1 }; - var objectB = new ClassA { ListOfCustomTypes = list2 }; + // Arrange + var subject = new + { + Age = 36, + Birthdate = new DateTime(1973, 9, 20), + Name = "John" + }; - // Act - Action act = () => objectA.Should().BeEquivalentTo(objectB, options => options.Including(x => x.ListOfCustomTypes)); + var customer = new + { + Age = 36, + Birthdate = new DateTime(1973, 9, 20), + Name = "Dennis" + }; - // Assert - act.Should().Throw(). - WithMessage("*C*but*A*D*but*B*"); - } + // Act + Action act = () => subject.Should().BeEquivalentTo(customer, options => options + .Including(d => d.Age) + .Including(d => d.Birthdate)); - [Fact] - public void When_null_is_provided_as_property_expression_it_should_throw() - { - // Arrange - var dto = new CustomerDto(); + // Assert + act.Should().NotThrow(); + } - // Act - Action act = - () => dto.Should().BeEquivalentTo(dto, options => options.Including(null)); + [Fact] + public void A_member_included_by_path_is_described_in_the_failure_message() + { + // Arrange + var subject = new + { + Name = "John" + }; - // Assert - act.Should().Throw().WithMessage( - "Expected an expression, but found .*"); - } + var customer = new + { + Name = "Jack" + }; - [Fact] - [SuppressMessage("ReSharper", "StringLiteralTypo")] - public void When_including_fields_it_should_succeed_if_just_the_included_field_match() - { - // Arrange - var class1 = new ClassWithSomeFieldsAndProperties - { - Field1 = "Lorem", - Field2 = "ipsum", - Field3 = "dolor", - Property1 = "sit", - Property2 = "amet", - Property3 = "consectetur" - }; - - var class2 = new ClassWithSomeFieldsAndProperties { Field1 = "Lorem", Field2 = "ipsum" }; - - // Act - Action act = - () => - class1.Should().BeEquivalentTo(class2, opts => opts.Including(_ => _.Field1).Including(_ => _.Field2)); - - // Assert - act.Should().NotThrow("the only selected fields have the same value"); - } + // Act + Action act = () => subject.Should().BeEquivalentTo(customer, options => options + .Including(d => d.Name)); - [Fact] - [SuppressMessage("ReSharper", "StringLiteralTypo")] - public void When_including_fields_it_should_fail_if_any_included_field_do_not_match() - { - // Arrange - var class1 = new ClassWithSomeFieldsAndProperties - { - Field1 = "Lorem", - Field2 = "ipsum", - Field3 = "dolor", - Property1 = "sit", - Property2 = "amet", - Property3 = "consectetur" - }; - - var class2 = new ClassWithSomeFieldsAndProperties { Field1 = "Lorem", Field2 = "ipsum" }; - - // Act - Action act = - () => - class1.Should().BeEquivalentTo(class2, - opts => opts.Including(_ => _.Field1).Including(_ => _.Field2).Including(_ => _.Field3)); - - // Assert - act.Should().Throw().WithMessage("Expected field class1.Field3*"); - } + // Assert + act.Should().Throw() + .WithMessage("*Include*Name*"); + } - [Fact] - public void When_only_the_excluded_property_doesnt_match_it_should_not_throw() - { - // Arrange - var dto = new CustomerDto + [Fact] + public void A_member_included_by_predicate_is_described_in_the_failure_message() { - Age = 36, - Birthdate = new DateTime(1973, 9, 20), - Name = "John" - }; + // Arrange + var subject = new + { + Name = "John" + }; - var customer = new Customer - { - Age = 36, - Birthdate = new DateTime(1973, 9, 20), - Name = "Dennis" - }; + var customer = new + { + Name = "Jack" + }; - // Act / Assert - dto.Should().BeEquivalentTo(customer, options => options - .Excluding(d => d.Name) - .Excluding(d => d.Id)); - } + // Act + Action act = () => subject.Should().BeEquivalentTo(customer, options => options + .Including(ctx => ctx.Path == "Name")); - [Fact] - [SuppressMessage("ReSharper", "StringLiteralTypo")] - public void When_excluding_members_it_should_pass_if_only_the_excluded_members_are_different() - { - // Arrange - var class1 = new ClassWithSomeFieldsAndProperties + // Assert + act.Should().Throw() + .WithMessage("*Include member when*Name*"); + } + + [Fact] + public void When_a_predicate_for_properties_to_include_has_been_specified_it_should_ignore_the_other_properties() { - Field1 = "Lorem", - Field2 = "ipsum", - Field3 = "dolor", - Property1 = "sit" - }; + // Arrange + var subject = new + { + Age = 36, + Birthdate = new DateTime(1973, 9, 20), + Name = "John" + }; - var class2 = new ClassWithSomeFieldsAndProperties { Field1 = "Lorem", Field2 = "ipsum" }; + var customer = new + { + Age = 36, + Birthdate = new DateTime(1973, 9, 20), + Name = "Dennis" + }; - // Act - Action act = - () => - class1.Should().BeEquivalentTo(class2, - opts => opts.Excluding(_ => _.Field3).Excluding(_ => _.Property1)); + // Act + Action act = () => subject.Should().BeEquivalentTo(customer, options => options + .Including(info => info.Path.EndsWith("Age", StringComparison.Ordinal)) + .Including(info => info.Path.EndsWith("Birthdate", StringComparison.Ordinal))); - // Assert - act.Should().NotThrow("the non-excluded fields have the same value"); - } + // Assert + act.Should().NotThrow(); + } - [Fact] - [SuppressMessage("ReSharper", "StringLiteralTypo")] - public void When_excluding_members_it_should_fail_if_any_non_excluded_members_are_different() - { - // Arrange - var class1 = new ClassWithSomeFieldsAndProperties + [Fact] + public void When_a_non_property_expression_is_provided_it_should_throw() { - Field1 = "Lorem", - Field2 = "ipsum", - Field3 = "dolor", - Property1 = "sit" - }; - - var class2 = new ClassWithSomeFieldsAndProperties { Field1 = "Lorem", Field2 = "ipsum" }; + // Arrange + var dto = new CustomerDto(); - // Act - Action act = - () => class1.Should().BeEquivalentTo(class2, opts => opts.Excluding(_ => _.Property1)); + // Act + Action act = () => dto.Should().BeEquivalentTo(dto, options => options.Including(d => d.GetType())); - // Assert - act.Should().Throw().WithMessage("Expected*Field3*"); - } + // Assert + act.Should().Throw() + .WithMessage("Expression cannot be used to select a member.*") + .WithParameterName("expression"); + } - [Fact] - public void When_all_shared_properties_match_it_should_not_throw() - { - // Arrange - var dto = new CustomerDto + [Fact] + public void When_including_a_property_it_should_exactly_match_the_property() { - Age = 36, - Birthdate = new DateTime(1973, 9, 20), - Name = "John" - }; + // Arrange + var actual = new + { + DeclaredType = LocalOtherType.NonDefault, + Type = LocalType.NonDefault + }; - var customer = new Customer - { - Id = 1, - Age = 36, - Birthdate = new DateTime(1973, 9, 20), - Name = "John" - }; + var expectation = new + { + DeclaredType = LocalOtherType.NonDefault + }; - // Act - Action act = () => dto.Should().BeEquivalentTo(customer, options => options.ExcludingMissingMembers()); + // Act + Action act = () => actual.Should().BeEquivalentTo(expectation, + config => config.Including(o => o.DeclaredType)); - // Assert - act.Should().NotThrow(); - } + // Assert + act.Should().NotThrow(); + } - [Fact] - public void When_a_property_is_write_only_it_should_be_ignored() - { - // Arrange - var subject = new ClassWithWriteOnlyProperty + private enum LocalOtherType : byte { - WriteOnlyProperty = 123, - SomeOtherProperty = "whatever" - }; + Default, + NonDefault + } - var expected = new + private enum LocalType : byte { - SomeOtherProperty = "whatever" - }; - - // Act - Action action = () => subject.Should().BeEquivalentTo(expected); - - // Assert - action.Should().NotThrow(); - } + Default, + NonDefault + } - [Fact] - public void When_a_property_is_private_it_should_be_ignored() - { - // Arrange - var subject = new Customer("MyPassword") + public class CustomType { - Age = 36, - Birthdate = new DateTime(1973, 9, 20), - Name = "John" - }; + public string Name { get; set; } + } - var other = new Customer("SomeOtherPassword") + [Fact] + public void When_including_a_property_using_an_expression_it_should_evaluate_it_from_the_root() { - Age = 36, - Birthdate = new DateTime(1973, 9, 20), - Name = "John" - }; - - // Act - Action act = () => subject.Should().BeEquivalentTo(other); + // Arrange + var list1 = new List + { + new CustomType + { + Name = "A" + }, + new CustomType + { + Name = "B" + } + }; - // Assert - act.Should().NotThrow(); - } + var list2 = new List + { + new CustomType + { + Name = "C" + }, + new CustomType + { + Name = "D" + } + }; - [Fact] - public void When_a_field_is_private_it_should_be_ignored() - { - // Arrange - var subject = new ClassWithAPrivateField(1234) { Value = 1 }; + var objectA = new ClassA + { + ListOfCustomTypes = list1 + }; - var other = new ClassWithAPrivateField(54321) { Value = 1 }; + var objectB = new ClassA + { + ListOfCustomTypes = list2 + }; - // Act - Action act = () => subject.Should().BeEquivalentTo(other); + // Act + Action act = () => objectA.Should().BeEquivalentTo(objectB, options => options.Including(x => x.ListOfCustomTypes)); - // Assert - act.Should().NotThrow(); - } + // Assert + act.Should().Throw().WithMessage("*C*but*A*D*but*B*"); + } - [Fact] - public void When_a_property_is_protected_it_should_be_ignored() - { - // Arrange - var subject = new Customer + private class ClassA { - Age = 36, - Birthdate = new DateTime(1973, 9, 20), - Name = "John" - }; - - subject.SetProtected("ActualValue"); + public List ListOfCustomTypes { get; set; } + } - var expected = new Customer + [Fact] + public void When_null_is_provided_as_property_expression_it_should_throw() { - Age = 36, - Birthdate = new DateTime(1973, 9, 20), - Name = "John" - }; - - expected.SetProtected("ExpectedValue"); + // Arrange + var dto = new CustomerDto(); - // Act - Action act = () => subject.Should().BeEquivalentTo(expected); + // Act + Action act = + () => dto.Should().BeEquivalentTo(dto, options => options.Including(null)); - // Assert - act.Should().NotThrow(); - } + // Assert + act.Should().Throw().WithMessage( + "Expected an expression, but found .*"); + } - public class MemberHiding - { [Fact] - public void Ignores_properties_hidden_by_the_derived_class() + [SuppressMessage("ReSharper", "StringLiteralTypo")] + public void When_including_fields_it_should_succeed_if_just_the_included_field_match() { // Arrange - var subject = new SubclassAHidingProperty + var class1 = new ClassWithSomeFieldsAndProperties { - Property = "DerivedValue" + Field1 = "Lorem", + Field2 = "ipsum", + Field3 = "dolor", + Property1 = "sit", + Property2 = "amet", + Property3 = "consectetur" }; - ((BaseWithProperty)subject).Property = "ActualBaseValue"; - - var expectation = new SubclassBHidingProperty + var class2 = new ClassWithSomeFieldsAndProperties { - Property = "DerivedValue" + Field1 = "Lorem", + Field2 = "ipsum" }; - ((AnotherBaseWithProperty)expectation).Property = "ExpectedBaseValue"; + // Act + Action act = + () => + class1.Should().BeEquivalentTo(class2, opts => opts.Including(_ => _.Field1).Including(_ => _.Field2)); - // Act / Assert - subject.Should().BeEquivalentTo(expectation); + // Assert + act.Should().NotThrow("the only selected fields have the same value"); } [Fact] - public void Ignores_properties_of_the_same_runtime_types_hidden_by_the_derived_class() + [SuppressMessage("ReSharper", "StringLiteralTypo")] + public void When_including_fields_it_should_fail_if_any_included_field_do_not_match() { // Arrange - var subject = new SubclassHidingStringProperty + var class1 = new ClassWithSomeFieldsAndProperties { - Property = "DerivedValue" + Field1 = "Lorem", + Field2 = "ipsum", + Field3 = "dolor", + Property1 = "sit", + Property2 = "amet", + Property3 = "consectetur" }; - ((BaseWithStringProperty)subject).Property = "ActualBaseValue"; - - var expectation = new SubclassHidingStringProperty + var class2 = new ClassWithSomeFieldsAndProperties { - Property = "DerivedValue" + Field1 = "Lorem", + Field2 = "ipsum" }; - ((BaseWithStringProperty)expectation).Property = "ExpectedBaseValue"; + // Act + Action act = + () => + class1.Should().BeEquivalentTo(class2, + opts => opts.Including(_ => _.Field1).Including(_ => _.Field2).Including(_ => _.Field3)); - // Act / Assert - subject.Should().BeEquivalentTo(expectation); + // Assert + act.Should().Throw().WithMessage("Expected field class1.Field3*"); } [Fact] - public void Includes_hidden_property_of_the_base_when_using_a_reference_to_the_base() + [SuppressMessage("ReSharper", "StringLiteralTypo")] + public void When_both_field_and_properties_are_configured_for_inclusion_both_should_be_included() { // Arrange - BaseWithProperty subject = new SubclassAHidingProperty + var class1 = new ClassWithSomeFieldsAndProperties { - Property = "ActualDerivedValue" + Field1 = "Lorem", + Property1 = "sit" }; - // FA doesn't know the compile-time type of the subject, so even though we pass a reference to the base-class, - // at run-time, it'll start finding the property on the subject starting from the run-time type, and thus ignore the - // hidden base-class field - ((SubclassAHidingProperty)subject).Property = "BaseValue"; + var class2 = new ClassWithSomeFieldsAndProperties(); - AnotherBaseWithProperty expectation = new SubclassBHidingProperty + // Act + Action act = + () => class1.Should().BeEquivalentTo(class2, opts => opts.IncludingFields().IncludingProperties()); + + // Assert + act.Should().Throw().Which.Message.Should().Contain("Field1").And.Contain("Property1"); + } + } + + public class Excluding + { + [Fact] + public void A_member_excluded_by_path_is_described_in_the_failure_message() + { + // Arrange + var subject = new { - Property = "ExpectedDerivedValue" + Name = "John", + Age = 13 }; - expectation.Property = "BaseValue"; + var customer = new + { + Name = "Jack", + Age = 37 + }; - // Act / Assert - subject.Should().BeEquivalentTo(expectation); + // Act + Action act = () => subject.Should().BeEquivalentTo(customer, options => options + .Excluding(d => d.Age)); + + // Assert + act.Should().Throw() + .WithMessage("*Exclude*Age*"); } [Fact] - public void Run_type_typing_ignores_hidden_properties_even_when_using_a_reference_to_the_base_class() + public void A_member_excluded_by_predicate_is_described_in_the_failure_message() { // Arrange - var subject = new SubclassAHidingProperty + var subject = new { - Property = "DerivedValue" + Name = "John", + Age = 13 }; - ((BaseWithProperty)subject).Property = "ActualBaseValue"; - - AnotherBaseWithProperty expectation = new SubclassBHidingProperty + var customer = new { - Property = "DerivedValue" + Name = "Jack", + Age = 37 }; - expectation.Property = "ExpectedBaseValue"; + // Act + Action act = () => subject.Should().BeEquivalentTo(customer, options => options + .Excluding(ctx => ctx.Path == "Age")); - // Act / Assert - subject.Should().BeEquivalentTo(expectation, _ => _.RespectingRuntimeTypes()); + // Assert + act.Should().Throw() + .WithMessage("*Exclude member when*Age*"); } [Fact] - public void Including_the_derived_property_excludes_the_hidden_property() + public void When_only_the_excluded_property_doesnt_match_it_should_not_throw() { // Arrange - var subject = new SubclassAHidingProperty + var dto = new CustomerDto { - Property = "DerivedValue" + Age = 36, + Birthdate = new DateTime(1973, 9, 20), + Name = "John" }; - ((BaseWithProperty)subject).Property = "ActualBaseValue"; - - var expectation = new SubclassBHidingProperty + var customer = new Customer { - Property = "DerivedValue" + Age = 36, + Birthdate = new DateTime(1973, 9, 20), + Name = "Dennis" }; - ((AnotherBaseWithProperty)expectation).Property = "ExpectedBaseValue"; - // Act / Assert - subject.Should().BeEquivalentTo(expectation, _ => _ - .Including(_ => _.Property)); + dto.Should().BeEquivalentTo(customer, options => options + .Excluding(d => d.Name) + .Excluding(d => d.Id)); } [Fact] - public void Excluding_the_property_hiding_the_base_class_one_does_not_reveal_the_latter() + [SuppressMessage("ReSharper", "StringLiteralTypo")] + public void When_excluding_members_it_should_pass_if_only_the_excluded_members_are_different() { // Arrange - var subject = new SubclassAHidingProperty(); - - ((BaseWithProperty)subject).Property = "ActualBaseValue"; - - var expectation = new SubclassBHidingProperty(); + var class1 = new ClassWithSomeFieldsAndProperties + { + Field1 = "Lorem", + Field2 = "ipsum", + Field3 = "dolor", + Property1 = "sit" + }; - ((AnotherBaseWithProperty)expectation).Property = "ExpectedBaseValue"; + var class2 = new ClassWithSomeFieldsAndProperties + { + Field1 = "Lorem", + Field2 = "ipsum" + }; // Act - Action act = () => subject.Should().BeEquivalentTo(expectation, _ => _ - .Excluding(b => b.Property)); + Action act = + () => + class1.Should().BeEquivalentTo(class2, + opts => opts.Excluding(_ => _.Field3).Excluding(_ => _.Property1)); // Assert - act.Should().Throw().WithMessage("*No members were found *"); + act.Should().NotThrow("the non-excluded fields have the same value"); } - private class BaseWithProperty + [Fact] + [SuppressMessage("ReSharper", "StringLiteralTypo")] + public void When_excluding_members_it_should_fail_if_any_non_excluded_members_are_different() { - public object Property { get; set; } - } + // Arrange + var class1 = new ClassWithSomeFieldsAndProperties + { + Field1 = "Lorem", + Field2 = "ipsum", + Field3 = "dolor", + Property1 = "sit" + }; - private class SubclassAHidingProperty : BaseWithProperty - { - public new T Property { get; set; } - } + var class2 = new ClassWithSomeFieldsAndProperties + { + Field1 = "Lorem", + Field2 = "ipsum" + }; - private class BaseWithStringProperty - { - public string Property { get; set; } - } + // Act + Action act = + () => class1.Should().BeEquivalentTo(class2, opts => opts.Excluding(_ => _.Property1)); - private class SubclassHidingStringProperty : BaseWithStringProperty - { - public new string Property { get; set; } + // Assert + act.Should().Throw().WithMessage("Expected*Field3*"); } - private class AnotherBaseWithProperty + [Fact] + public void When_all_shared_properties_match_it_should_not_throw() { - public object Property { get; set; } - } + // Arrange + var dto = new CustomerDto + { + Age = 36, + Birthdate = new DateTime(1973, 9, 20), + Name = "John" + }; - private class SubclassBHidingProperty : AnotherBaseWithProperty - { - public new T Property + var customer = new Customer { - get; set; - } + Id = 1, + Age = 36, + Birthdate = new DateTime(1973, 9, 20), + Name = "John" + }; + + // Act + Action act = () => dto.Should().BeEquivalentTo(customer, options => options.ExcludingMissingMembers()); + + // Assert + act.Should().NotThrow(); } [Fact] - public void Ignores_fields_hidden_by_the_derived_class() + public void When_a_deeply_nested_property_with_a_value_mismatch_is_excluded_it_should_not_throw() { // Arrange - var subject = new SubclassAHidingField + var subject = new Root { - Field = "DerivedValue" + Text = "Root", + Level = new Level1 + { + Text = "Level1", + Level = new Level2 + { + Text = "Mismatch" + } + } }; - ((BaseWithField)subject).Field = "ActualBaseValue"; - - var expectation = new SubclassBHidingField + var expected = new RootDto { - Field = "DerivedValue" + Text = "Root", + Level = new Level1Dto + { + Text = "Level1", + Level = new Level2Dto + { + Text = "Level2" + } + } }; - ((AnotherBaseWithField)expectation).Field = "ExpectedBaseValue"; + // Act + Action act = () => subject.Should().BeEquivalentTo(expected, + options => options.Excluding(r => r.Level.Level.Text)); - // Act / Assert - subject.Should().BeEquivalentTo(expectation, options => options.IncludingFields()); + // Assert + act.Should().NotThrow(); } [Fact] - public void Includes_hidden_field_of_the_base_when_using_a_reference_to_the_base() + public void When_a_property_with_a_value_mismatch_is_excluded_using_a_predicate_it_should_not_throw() { // Arrange - BaseWithField subject = new SubclassAHidingField + var subject = new Root { - Field = "BaseValueFromSubject" + Text = "Root", + Level = new Level1 + { + Text = "Level1", + Level = new Level2 + { + Text = "Mismatch" + } + } }; - // FA doesn't know the compile-time type of the subject, so even though we pass a reference to the base-class, - // at run-time, it'll start finding the field on the subject starting from the run-time type, and thus ignore the - // hidden base-class field - ((SubclassAHidingField)subject).Field = "BaseValueFromExpectation"; - - AnotherBaseWithField expectation = new SubclassBHidingField + var expected = new RootDto { - Field = "ExpectedDerivedValue" + Text = "Root", + Level = new Level1Dto + { + Text = "Level1", + Level = new Level2Dto + { + Text = "Level2" + } + } }; - expectation.Field = "BaseValueFromExpectation"; + // Act + Action act = () => subject.Should().BeEquivalentTo(expected, config => + config.Excluding(ctx => ctx.Path == "Level.Level.Text")); - // Act / Assert - subject.Should().BeEquivalentTo(expectation, options => options.IncludingFields()); + // Assert + act.Should().NotThrow(); } [Fact] - public void Run_type_typing_ignores_hidden_fields_even_when_using_a_reference_to_the_base_class() + public void When_members_are_excluded_by_the_access_modifier_of_the_getter_using_a_predicate_they_should_be_ignored() { // Arrange - var subject = new SubclassAHidingField + var subject = new ClassWithAllAccessModifiersForMembers("public", "protected", + "internal", "protected-internal", "private", "private-protected"); + + var expected = new ClassWithAllAccessModifiersForMembers("public", "protected", + "ignored-internal", "ignored-protected-internal", "private", "ignore-private-protected"); + + // Act + Action act = () => subject.Should().BeEquivalentTo(expected, config => + config.Excluding(ctx => ctx.WhichGetterHas(CSharpAccessModifier.Internal) || + ctx.WhichGetterHas(CSharpAccessModifier.ProtectedInternal) || + ctx.WhichGetterHas(CSharpAccessModifier.PrivateProtected))); + + // Assert + act.Should().NotThrow(); + } + + [Fact] + public void When_members_are_excluded_by_the_access_modifier_of_the_setter_using_a_predicate_they_should_be_ignored() + { + // Arrange + var subject = new ClassWithAllAccessModifiersForMembers("public", "protected", + "internal", "protected-internal", "private", "private-protected"); + + var expected = new ClassWithAllAccessModifiersForMembers("public", "protected", + "ignored-internal", "ignored-protected-internal", "ignored-private", "ignore-private-protected"); + + // Act + Action act = () => subject.Should().BeEquivalentTo(expected, config => + config.Excluding(ctx => ctx.WhichSetterHas(CSharpAccessModifier.Internal) || + ctx.WhichSetterHas(CSharpAccessModifier.ProtectedInternal) || + ctx.WhichSetterHas(CSharpAccessModifier.Private) || + ctx.WhichSetterHas(CSharpAccessModifier.PrivateProtected))); + + // Assert + act.Should().NotThrow(); + } + + [Fact] + [SuppressMessage("ReSharper", "StringLiteralTypo")] + public void When_excluding_properties_it_should_still_compare_fields() + { + // Arrange + var class1 = new ClassWithSomeFieldsAndProperties { - Field = "DerivedValue" + Field1 = "Lorem", + Field2 = "ipsum", + Field3 = "dolor", + Property1 = "sit", + Property2 = "amet", + Property3 = "consectetur" }; - ((BaseWithField)subject).Field = "ActualBaseValue"; - - AnotherBaseWithField expectation = new SubclassBHidingField + var class2 = new ClassWithSomeFieldsAndProperties { - Field = "DerivedValue" + Field1 = "Lorem", + Field2 = "ipsum", + Field3 = "color" }; - expectation.Field = "ExpectedBaseValue"; + // Act + Action act = + () => class1.Should().BeEquivalentTo(class2, opts => opts.ExcludingProperties()); - // Act / Assert - subject.Should().BeEquivalentTo(expectation, options => options.IncludingFields().RespectingRuntimeTypes()); + // Assert + act.Should().Throw().WithMessage("*color*dolor*"); } [Fact] - public void Including_the_derived_field_excludes_the_hidden_field() + public void When_excluding_properties_via_non_array_indexers_it_should_exclude_the_specified_paths() { // Arrange - var subject = new SubclassAHidingField + var subject = new { - Field = "DerivedValue" + List = new[] + { + new + { + Foo = 1, + Bar = 2 + }, + new + { + Foo = 3, + Bar = 4 + } + }.ToList(), + Dictionary = new Dictionary + { + ["Foo"] = new ClassWithOnlyAProperty + { + Value = 1 + }, + ["Bar"] = new ClassWithOnlyAProperty + { + Value = 2 + } + } }; - ((BaseWithField)subject).Field = "ActualBaseValue"; - - var expectation = new SubclassBHidingField + var expected = new { - Field = "DerivedValue" + List = new[] + { + new + { + Foo = 1, + Bar = 2 + }, + new + { + Foo = 2, + Bar = 4 + } + }.ToList(), + Dictionary = new Dictionary + { + ["Foo"] = new ClassWithOnlyAProperty + { + Value = 1 + }, + ["Bar"] = new ClassWithOnlyAProperty + { + Value = 3 + } + } }; - ((AnotherBaseWithField)expectation).Field = "ExpectedBaseValue"; + // Act + Action act = () => + subject.Should().BeEquivalentTo(expected, + options => options + .Excluding(x => x.List[1].Foo) + .Excluding(x => x.Dictionary["Bar"].Value)); - // Act / Assert - subject.Should().BeEquivalentTo(expectation, options => options - .IncludingFields() - .Including(_ => _.Field)); + // Assert + act.Should().NotThrow(); } [Fact] - public void Excluding_the_field_hiding_the_base_class_one_does_not_reveal_the_latter() + public void When_excluding_properties_via_non_array_indexers_it_should_not_exclude_paths_with_different_indexes() { // Arrange - var subject = new SubclassAHidingField(); - - ((BaseWithField)subject).Field = "ActualBaseValue"; - - var expectation = new SubclassBHidingField(); + var subject = new + { + List = new[] + { + new + { + Foo = 1, + Bar = 2 + }, + new + { + Foo = 3, + Bar = 4 + } + }.ToList(), + Dictionary = new Dictionary + { + ["Foo"] = new ClassWithOnlyAProperty + { + Value = 1 + }, + ["Bar"] = new ClassWithOnlyAProperty + { + Value = 2 + } + } + }; - ((AnotherBaseWithField)expectation).Field = "ExpectedBaseValue"; + var expected = new + { + List = new[] + { + new + { + Foo = 5, + Bar = 2 + }, + new + { + Foo = 2, + Bar = 4 + } + }.ToList(), + Dictionary = new Dictionary + { + ["Foo"] = new ClassWithOnlyAProperty + { + Value = 6 + }, + ["Bar"] = new ClassWithOnlyAProperty + { + Value = 3 + } + } + }; // Act - Action act = () => subject.Should().BeEquivalentTo(expectation, options => options - .IncludingFields() - .Excluding(b => b.Field)); + Action act = () => + subject.Should().BeEquivalentTo(expected, + options => options + .Excluding(x => x.List[1].Foo) + .Excluding(x => x.Dictionary["Bar"].Value)); // Assert - act.Should().Throw().WithMessage("*No members were found *"); + act.Should().Throw(); } - private class BaseWithField + [Fact] + [SuppressMessage("ReSharper", "StringLiteralTypo")] + public void + When_configured_for_runtime_typing_and_properties_are_excluded_the_runtime_type_should_be_used_and_properties_should_be_ignored() { - public string Field; - } + // Arrange + object class1 = new ClassWithSomeFieldsAndProperties + { + Field1 = "Lorem", + Field2 = "ipsum", + Field3 = "dolor", + Property1 = "sit", + Property2 = "amet", + Property3 = "consectetur" + }; - private class SubclassAHidingField : BaseWithField - { - public new string Field; - } + object class2 = new ClassWithSomeFieldsAndProperties + { + Field1 = "Lorem", + Field2 = "ipsum", + Field3 = "dolor" + }; - private class AnotherBaseWithField - { - public string Field; + // Act + Action act = + () => class1.Should().BeEquivalentTo(class2, opts => opts.ExcludingProperties().RespectingRuntimeTypes()); + + // Assert + act.Should().NotThrow(); } - private class SubclassBHidingField : AnotherBaseWithField + [Fact] + public void When_excluding_virtual_or_abstract_property_exclusion_works_properly() { - public new string Field; + var obj1 = new Derived + { + DerivedProperty1 = "Something", + DerivedProperty2 = "A" + }; + + var obj2 = new Derived + { + DerivedProperty1 = "Something", + DerivedProperty2 = "B" + }; + + obj1.Should().BeEquivalentTo(obj2, opt => opt + .Excluding(o => o.AbstractProperty) + .Excluding(o => o.VirtualProperty) + .Excluding(o => o.DerivedProperty2)); } } - [Fact] - public void When_a_property_is_internal_it_should_be_excluded_from_the_comparison() + public class Accessibility { - // Arrange - var actual = new ClassWithInternalProperty + [Fact] + public void When_a_property_is_write_only_it_should_be_ignored() { - PublicProperty = "public", - InternalProperty = "internal", - ProtectedInternalProperty = "internal" - }; + // Arrange + var subject = new ClassWithWriteOnlyProperty + { + WriteOnlyProperty = 123, + SomeOtherProperty = "whatever" + }; + + var expected = new + { + SomeOtherProperty = "whatever" + }; + + // Act + Action action = () => subject.Should().BeEquivalentTo(expected); + + // Assert + action.Should().NotThrow(); + } - var expected = new ClassWithInternalProperty + [Fact] + public void When_a_property_is_private_it_should_be_ignored() { - PublicProperty = "public", - InternalProperty = "also internal", - ProtectedInternalProperty = "also internal" - }; + // Arrange + var subject = new Customer("MyPassword") + { + Age = 36, + Birthdate = new DateTime(1973, 9, 20), + Name = "John" + }; - // Act / Assert - actual.Should().BeEquivalentTo(expected); - } + var other = new Customer("SomeOtherPassword") + { + Age = 36, + Birthdate = new DateTime(1973, 9, 20), + Name = "John" + }; - [Fact] - public void When_a_property_is_internal_and_it_should_be_included_it_should_fail_the_assertion() - { - // Arrange - var actual = new ClassWithInternalProperty + // Act + Action act = () => subject.Should().BeEquivalentTo(other); + + // Assert + act.Should().NotThrow(); + } + + [Fact] + public void When_a_field_is_private_it_should_be_ignored() { - PublicProperty = "public", - InternalProperty = "internal", - ProtectedInternalProperty = "internal" - }; + // Arrange + var subject = new ClassWithAPrivateField(1234) + { + Value = 1 + }; - var expected = new ClassWithInternalProperty + var other = new ClassWithAPrivateField(54321) + { + Value = 1 + }; + + // Act + Action act = () => subject.Should().BeEquivalentTo(other); + + // Assert + act.Should().NotThrow(); + } + + [Fact] + public void When_a_property_is_protected_it_should_be_ignored() { - PublicProperty = "public", - InternalProperty = "also internal", - ProtectedInternalProperty = "also internal" - }; + // Arrange + var subject = new Customer + { + Age = 36, + Birthdate = new DateTime(1973, 9, 20), + Name = "John" + }; - // Act - Action act = () => actual.Should().BeEquivalentTo(expected, options => options.IncludingInternalProperties()); + subject.SetProtected("ActualValue"); - // Assert - act.Should().Throw().WithMessage("*InternalProperty*also internal*internal*ProtectedInternalProperty*"); - } + var expected = new Customer + { + Age = 36, + Birthdate = new DateTime(1973, 9, 20), + Name = "John" + }; - private class ClassWithInternalProperty - { - public string PublicProperty { get; set; } + expected.SetProtected("ExpectedValue"); - internal string InternalProperty { get; set; } + // Act + Action act = () => subject.Should().BeEquivalentTo(expected); - protected internal string ProtectedInternalProperty { get; set; } - } + // Assert + act.Should().NotThrow(); + } - [Fact] - public void When_a_field_is_internal_it_should_be_excluded_from_the_comparison() - { - // Arrange - var actual = new ClassWithInternalField + [Fact] + public void When_a_property_is_internal_and_it_should_be_included_it_should_fail_the_assertion() { - PublicField = "public", - InternalField = "internal", - ProtectedInternalField = "internal" - }; + // Arrange + var actual = new ClassWithInternalProperty + { + PublicProperty = "public", + InternalProperty = "internal", + ProtectedInternalProperty = "internal" + }; - var expected = new ClassWithInternalField - { - PublicField = "public", - InternalField = "also internal", - ProtectedInternalField = "also internal" - }; + var expected = new ClassWithInternalProperty + { + PublicProperty = "public", + InternalProperty = "also internal", + ProtectedInternalProperty = "also internal" + }; - // Act / Assert - actual.Should().BeEquivalentTo(expected); - } + // Act + Action act = () => actual.Should().BeEquivalentTo(expected, options => options.IncludingInternalProperties()); - [Fact] - public void When_a_field_is_internal_and_it_should_be_included_it_should_fail_the_assertion() - { - // Arrange - var actual = new ClassWithInternalField - { - PublicField = "public", - InternalField = "internal", - ProtectedInternalField = "internal" - }; + // Assert + act.Should().Throw() + .WithMessage("*InternalProperty*also internal*internal*ProtectedInternalProperty*"); + } - var expected = new ClassWithInternalField + private class ClassWithInternalProperty { - PublicField = "public", - InternalField = "also internal", - ProtectedInternalField = "also internal" - }; + public string PublicProperty { get; set; } - // Act - Action act = () => actual.Should().BeEquivalentTo(expected, options => options.IncludingInternalFields()); + internal string InternalProperty { get; set; } - // Assert - act.Should().Throw().WithMessage("*InternalField*also internal*internal*ProtectedInternalField*"); - } + protected internal string ProtectedInternalProperty { get; set; } + } - private class ClassWithInternalField - { - public string PublicField; + [Fact] + public void When_a_field_is_internal_it_should_be_excluded_from_the_comparison() + { + // Arrange + var actual = new ClassWithInternalField + { + PublicField = "public", + InternalField = "internal", + ProtectedInternalField = "internal" + }; - internal string InternalField; + var expected = new ClassWithInternalField + { + PublicField = "public", + InternalField = "also internal", + ProtectedInternalField = "also internal" + }; - protected internal string ProtectedInternalField; - } + // Act / Assert + actual.Should().BeEquivalentTo(expected); + } - [Fact] - public void When_a_property_is_an_indexer_it_should_be_ignored() - { - // Arrange - var expected = new ClassWithIndexer { Foo = "test" }; - var result = new ClassWithIndexer { Foo = "test" }; + [Fact] + public void When_a_field_is_internal_and_it_should_be_included_it_should_fail_the_assertion() + { + // Arrange + var actual = new ClassWithInternalField + { + PublicField = "public", + InternalField = "internal", + ProtectedInternalField = "internal" + }; - // Act - Action act = () => result.Should().BeEquivalentTo(expected); + var expected = new ClassWithInternalField + { + PublicField = "public", + InternalField = "also internal", + ProtectedInternalField = "also internal" + }; - // Assert - act.Should().NotThrow(); - } + // Act + Action act = () => actual.Should().BeEquivalentTo(expected, options => options.IncludingInternalFields()); - public class BaseWithFoo - { - public object Foo { get; set; } - } + // Assert + act.Should().Throw().WithMessage("*InternalField*also internal*internal*ProtectedInternalField*"); + } - public class SubclassA : BaseWithFoo - { - public new T Foo + private class ClassWithInternalField { - get { return (T)base.Foo; } + public string PublicField; - set { base.Foo = value; } - } - } + internal string InternalField; - public class D - { - public object Foo { get; set; } - } + protected internal string ProtectedInternalField; + } - public class SubclassB : D - { - public new T Foo + [Fact] + public void When_a_property_is_internal_it_should_be_excluded_from_the_comparison() { - get { return (T)base.Foo; } + // Arrange + var actual = new ClassWithInternalProperty + { + PublicProperty = "public", + InternalProperty = "internal", + ProtectedInternalProperty = "internal" + }; + + var expected = new ClassWithInternalProperty + { + PublicProperty = "public", + InternalProperty = "also internal", + ProtectedInternalProperty = "also internal" + }; - set { base.Foo = value; } + // Act / Assert + actual.Should().BeEquivalentTo(expected); } } - public class ClassWithIndexer + public class MemberHiding { - public object Foo { get; set; } - - public string this[int n] + [Fact] + public void Ignores_properties_hidden_by_the_derived_class() { - get + // Arrange + var subject = new SubclassAHidingProperty { - return - n.ToString( - CultureInfo.InvariantCulture); - } + Property = "DerivedValue" + }; + + ((BaseWithProperty)subject).Property = "ActualBaseValue"; + + var expectation = new SubclassBHidingProperty + { + Property = "DerivedValue" + }; + + ((AnotherBaseWithProperty)expectation).Property = "ExpectedBaseValue"; + + // Act / Assert + subject.Should().BeEquivalentTo(expectation); } - } - [Fact] - public void When_an_interface_hierarchy_is_used_it_should_include_all_inherited_properties() - { - // Arrange - ICar subject = new Car + [Fact] + public void Ignores_properties_of_the_same_runtime_types_hidden_by_the_derived_class() { - VehicleId = 1, - Wheels = 4 - }; + // Arrange + var subject = new SubclassHidingStringProperty + { + Property = "DerivedValue" + }; - ICar expected = new Car - { - VehicleId = 99999, - Wheels = 4 - }; + ((BaseWithStringProperty)subject).Property = "ActualBaseValue"; - // Act - Action action = () => subject.Should().BeEquivalentTo(expected); + var expectation = new SubclassHidingStringProperty + { + Property = "DerivedValue" + }; - // Assert - action - .Should().Throw() - .WithMessage("Expected*VehicleId*99999*but*1*"); - } + ((BaseWithStringProperty)expectation).Property = "ExpectedBaseValue"; - [Fact] - public void When_a_reference_to_an_interface_is_provided_it_should_only_include_those_properties() - { - // Arrange - IVehicle expected = new Car + // Act / Assert + subject.Should().BeEquivalentTo(expectation); + } + + [Fact] + public void Includes_hidden_property_of_the_base_when_using_a_reference_to_the_base() { - VehicleId = 1, - Wheels = 4 - }; + // Arrange + BaseWithProperty subject = new SubclassAHidingProperty + { + Property = "ActualDerivedValue" + }; - IVehicle subject = new Car + // FA doesn't know the compile-time type of the subject, so even though we pass a reference to the base-class, + // at run-time, it'll start finding the property on the subject starting from the run-time type, and thus ignore the + // hidden base-class field + ((SubclassAHidingProperty)subject).Property = "BaseValue"; + + AnotherBaseWithProperty expectation = new SubclassBHidingProperty + { + Property = "ExpectedDerivedValue" + }; + + expectation.Property = "BaseValue"; + + // Act / Assert + subject.Should().BeEquivalentTo(expectation); + } + + [Fact] + public void Run_type_typing_ignores_hidden_properties_even_when_using_a_reference_to_the_base_class() { - VehicleId = 1, - Wheels = 99999 - }; + // Arrange + var subject = new SubclassAHidingProperty + { + Property = "DerivedValue" + }; - // Act - Action action = () => subject.Should().BeEquivalentTo(expected); + ((BaseWithProperty)subject).Property = "ActualBaseValue"; - // Assert - action.Should().NotThrow(); - } + AnotherBaseWithProperty expectation = new SubclassBHidingProperty + { + Property = "DerivedValue" + }; - [Fact] - public void When_a_reference_to_an_explicit_interface_impl_is_provided_it_should_only_include_those_properties() - { - // Arrange - IVehicle expected = new ExplicitCar + expectation.Property = "ExpectedBaseValue"; + + // Act / Assert + subject.Should().BeEquivalentTo(expectation, _ => _.RespectingRuntimeTypes()); + } + + [Fact] + public void Including_the_derived_property_excludes_the_hidden_property() { - Wheels = 4 - }; + // Arrange + var subject = new SubclassAHidingProperty + { + Property = "DerivedValue" + }; + + ((BaseWithProperty)subject).Property = "ActualBaseValue"; + + var expectation = new SubclassBHidingProperty + { + Property = "DerivedValue" + }; + + ((AnotherBaseWithProperty)expectation).Property = "ExpectedBaseValue"; + + // Act / Assert + subject.Should().BeEquivalentTo(expectation, _ => _ + .Including(_ => _.Property)); + } - IVehicle subject = new ExplicitCar + [Fact] + public void Excluding_the_property_hiding_the_base_class_one_does_not_reveal_the_latter() { - Wheels = 99999 - }; + // Arrange + var subject = new SubclassAHidingProperty(); - // Act - Action action = () => subject.Should().BeEquivalentTo(expected); + ((BaseWithProperty)subject).Property = "ActualBaseValue"; - // Assert - action.Should().NotThrow(); - } + var expectation = new SubclassBHidingProperty(); - [Fact] - public void When_respecting_declared_types_explicit_interface_member_on_interfaced_subject_should_be_used() - { - // Arrange - IVehicle expected = new Vehicle + ((AnotherBaseWithProperty)expectation).Property = "ExpectedBaseValue"; + + // Act + Action act = () => subject.Should().BeEquivalentTo(expectation, _ => _ + .Excluding(b => b.Property)); + + // Assert + act.Should().Throw().WithMessage("*No members were found *"); + } + + private class BaseWithProperty { - VehicleId = 1 - }; + public object Property { get; set; } + } - IVehicle subject = new ExplicitVehicle + private class SubclassAHidingProperty : BaseWithProperty { - VehicleId = 2 // instance member - }; - subject.VehicleId = 1; // interface member + public new T Property { get; set; } + } - // Act - Action action = () => subject.Should().BeEquivalentTo(expected, opt => opt.RespectingDeclaredTypes()); + private class BaseWithStringProperty + { + public string Property { get; set; } + } - // Assert - action.Should().NotThrow(); - } + private class SubclassHidingStringProperty : BaseWithStringProperty + { + public new string Property { get; set; } + } - [Fact] - public void When_respecting_declared_types_explicit_interface_member_on_interfaced_expectation_should_be_used() - { - // Arrange - IVehicle expected = new ExplicitVehicle + private class AnotherBaseWithProperty + { + public object Property { get; set; } + } + + private class SubclassBHidingProperty : AnotherBaseWithProperty { - VehicleId = 2 // instance member - }; - expected.VehicleId = 1; // interface member + public new T Property + { + get; + set; + } + } - IVehicle subject = new Vehicle + [Fact] + public void Ignores_fields_hidden_by_the_derived_class() { - VehicleId = 1 - }; + // Arrange + var subject = new SubclassAHidingField + { + Field = "DerivedValue" + }; - // Act - Action action = () => subject.Should().BeEquivalentTo(expected, opt => opt.RespectingDeclaredTypes()); + ((BaseWithField)subject).Field = "ActualBaseValue"; - // Assert - action.Should().NotThrow(); - } + var expectation = new SubclassBHidingField + { + Field = "DerivedValue" + }; - [Fact] - public void When_respecting_runtime_types_explicit_interface_member_on_interfaced_subject_should_not_be_used() - { - // Arrange - IVehicle expected = new Vehicle + ((AnotherBaseWithField)expectation).Field = "ExpectedBaseValue"; + + // Act / Assert + subject.Should().BeEquivalentTo(expectation, options => options.IncludingFields()); + } + + [Fact] + public void Includes_hidden_field_of_the_base_when_using_a_reference_to_the_base() { - VehicleId = 1 - }; + // Arrange + BaseWithField subject = new SubclassAHidingField + { + Field = "BaseValueFromSubject" + }; + + // FA doesn't know the compile-time type of the subject, so even though we pass a reference to the base-class, + // at run-time, it'll start finding the field on the subject starting from the run-time type, and thus ignore the + // hidden base-class field + ((SubclassAHidingField)subject).Field = "BaseValueFromExpectation"; + + AnotherBaseWithField expectation = new SubclassBHidingField + { + Field = "ExpectedDerivedValue" + }; + + expectation.Field = "BaseValueFromExpectation"; + + // Act / Assert + subject.Should().BeEquivalentTo(expectation, options => options.IncludingFields()); + } - IVehicle subject = new ExplicitVehicle + [Fact] + public void Run_type_typing_ignores_hidden_fields_even_when_using_a_reference_to_the_base_class() { - VehicleId = 2 // instance member - }; - subject.VehicleId = 1; // interface member + // Arrange + var subject = new SubclassAHidingField + { + Field = "DerivedValue" + }; - // Act - Action action = () => subject.Should().BeEquivalentTo(expected, opt => opt.RespectingRuntimeTypes()); + ((BaseWithField)subject).Field = "ActualBaseValue"; - // Assert - action.Should().Throw(); - } + AnotherBaseWithField expectation = new SubclassBHidingField + { + Field = "DerivedValue" + }; - [Fact] - public void When_respecting_runtime_types_explicit_interface_member_on_interfaced_expectation_should_not_be_used() - { - // Arrange - IVehicle expected = new ExplicitVehicle + expectation.Field = "ExpectedBaseValue"; + + // Act / Assert + subject.Should().BeEquivalentTo(expectation, options => options.IncludingFields().RespectingRuntimeTypes()); + } + + [Fact] + public void Including_the_derived_field_excludes_the_hidden_field() { - VehicleId = 2 // instance member - }; - expected.VehicleId = 1; // interface member + // Arrange + var subject = new SubclassAHidingField + { + Field = "DerivedValue" + }; + + ((BaseWithField)subject).Field = "ActualBaseValue"; + + var expectation = new SubclassBHidingField + { + Field = "DerivedValue" + }; - IVehicle subject = new Vehicle + ((AnotherBaseWithField)expectation).Field = "ExpectedBaseValue"; + + // Act / Assert + subject.Should().BeEquivalentTo(expectation, options => options + .IncludingFields() + .Including(_ => _.Field)); + } + + [Fact] + public void Excluding_the_field_hiding_the_base_class_one_does_not_reveal_the_latter() { - VehicleId = 1 - }; + // Arrange + var subject = new SubclassAHidingField(); - // Act - Action action = () => subject.Should().BeEquivalentTo(expected, opt => opt.RespectingRuntimeTypes()); + ((BaseWithField)subject).Field = "ActualBaseValue"; - // Assert - action.Should().Throw(); - } + var expectation = new SubclassBHidingField(); - [Fact] - public void When_respecting_declared_types_explicit_interface_member_on_subject_should_not_be_used() - { - // Arrange - var expected = new Vehicle + ((AnotherBaseWithField)expectation).Field = "ExpectedBaseValue"; + + // Act + Action act = () => subject.Should().BeEquivalentTo(expectation, options => options + .IncludingFields() + .Excluding(b => b.Field)); + + // Assert + act.Should().Throw().WithMessage("*No members were found *"); + } + + private class BaseWithField + { + public string Field; + } + + private class SubclassAHidingField : BaseWithField { - VehicleId = 1 - }; + public new string Field; + } - var subject = new ExplicitVehicle + private class AnotherBaseWithField { - VehicleId = 2 - }; - ((IVehicle)subject).VehicleId = 1; - - // Act - Action action = () => subject.Should().BeEquivalentTo(expected, opt => opt.RespectingDeclaredTypes()); + public string Field; + } - // Assert - action.Should().Throw(); + private class SubclassBHidingField : AnotherBaseWithField + { + public new string Field; + } } - [Fact] - public void When_respecting_declared_types_explicit_interface_member_on_expectation_should_not_be_used() + public class Interfaces { - // Arrange - var expected = new ExplicitVehicle + [Fact] + public void When_an_interface_hierarchy_is_used_it_should_include_all_inherited_properties() { - VehicleId = 2 - }; - ((IVehicle)expected).VehicleId = 1; + // Arrange + ICar subject = new Car + { + VehicleId = 1, + Wheels = 4 + }; - var subject = new Vehicle - { - VehicleId = 1 - }; + ICar expected = new Car + { + VehicleId = 99999, + Wheels = 4 + }; - // Act - Action action = () => subject.Should().BeEquivalentTo(expected, opt => opt.RespectingDeclaredTypes()); + // Act + Action action = () => subject.Should().BeEquivalentTo(expected); - // Assert - action.Should().Throw(); - } + // Assert + action + .Should().Throw() + .WithMessage("Expected*VehicleId*99999*but*1*"); + } - [Fact] - public void When_respecting_runtime_types_explicit_interface_member_on_subject_should_not_be_used() - { - // Arrange - var expected = new Vehicle + [Fact] + public void When_a_reference_to_an_interface_is_provided_it_should_only_include_those_properties() { - VehicleId = 1 - }; + // Arrange + IVehicle expected = new Car + { + VehicleId = 1, + Wheels = 4 + }; - var subject = new ExplicitVehicle - { - VehicleId = 2 - }; - ((IVehicle)subject).VehicleId = 1; + IVehicle subject = new Car + { + VehicleId = 1, + Wheels = 99999 + }; - // Act - Action action = () => subject.Should().BeEquivalentTo(expected, opt => opt.RespectingRuntimeTypes()); + // Act + Action action = () => subject.Should().BeEquivalentTo(expected); - // Assert - action.Should().Throw(); - } + // Assert + action.Should().NotThrow(); + } - [Fact] - public void When_respecting_runtime_types_explicit_interface_member_on_expectation_should_not_be_used() - { - // Arrange - var expected = new ExplicitVehicle + [Fact] + public void When_a_reference_to_an_explicit_interface_impl_is_provided_it_should_only_include_those_properties() { - VehicleId = 2 - }; - ((IVehicle)expected).VehicleId = 1; + // Arrange + IVehicle expected = new ExplicitCar + { + Wheels = 4 + }; - var subject = new Vehicle - { - VehicleId = 1 - }; + IVehicle subject = new ExplicitCar + { + Wheels = 99999 + }; - // Act - Action action = () => subject.Should().BeEquivalentTo(expected, opt => opt.RespectingRuntimeTypes()); + // Act + Action action = () => subject.Should().BeEquivalentTo(expected); - // Assert - action.Should().Throw(); - } + // Assert + action.Should().NotThrow(); + } - [Fact] - public void When_a_deeply_nested_property_with_a_value_mismatch_is_excluded_it_should_not_throw() - { - // Arrange - var subject = new Root + [Fact] + public void When_respecting_declared_types_explicit_interface_member_on_interfaced_subject_should_be_used() { - Text = "Root", - Level = new Level1 + // Arrange + IVehicle expected = new Vehicle { - Text = "Level1", - Level = new Level2 - { - Text = "Mismatch" - } - } - }; + VehicleId = 1 + }; - var expected = new RootDto - { - Text = "Root", - Level = new Level1Dto + IVehicle subject = new ExplicitVehicle { - Text = "Level1", - Level = new Level2Dto - { - Text = "Level2" - } - } - }; + VehicleId = 2 // instance member + }; - // Act - Action act = () => subject.Should().BeEquivalentTo(expected, - options => options.Excluding(r => r.Level.Level.Text)); + subject.VehicleId = 1; // interface member - // Assert - act.Should().NotThrow(); - } + // Act + Action action = () => subject.Should().BeEquivalentTo(expected, opt => opt.RespectingDeclaredTypes()); - [Fact] - public void When_a_property_with_a_value_mismatch_is_excluded_using_a_predicate_it_should_not_throw() - { - // Arrange - var subject = new Root - { - Text = "Root", - Level = new Level1 - { - Text = "Level1", - Level = new Level2 - { - Text = "Mismatch" - } - } - }; + // Assert + action.Should().NotThrow(); + } - var expected = new RootDto + [Fact] + public void When_respecting_declared_types_explicit_interface_member_on_interfaced_expectation_should_be_used() { - Text = "Root", - Level = new Level1Dto + // Arrange + IVehicle expected = new ExplicitVehicle { - Text = "Level1", - Level = new Level2Dto - { - Text = "Level2" - } - } - }; + VehicleId = 2 // instance member + }; - // Act - Action act = () => subject.Should().BeEquivalentTo(expected, config => - config.Excluding(ctx => ctx.Path == "Level.Level.Text")); + expected.VehicleId = 1; // interface member - // Assert - act.Should().NotThrow(); - } + IVehicle subject = new Vehicle + { + VehicleId = 1 + }; - [Fact] - public void When_members_are_excluded_by_the_access_modifier_of_the_getter_using_a_predicate_they_should_be_ignored() - { - // Arrange - var subject = new ClassWithAllAccessModifiersForMembers( - "public", - "protected", - "internal", - "protected-internal", - "private", - "private-protected"); - - var expected = new ClassWithAllAccessModifiersForMembers( - "public", - "protected", - "ignored-internal", - "ignored-protected-internal", - "private", - "ignore-private-protected"); - - // Act - Action act = () => subject.Should().BeEquivalentTo(expected, config => - config.Excluding(ctx => ctx.WhichGetterHas(CSharpAccessModifier.Internal) || - ctx.WhichGetterHas(CSharpAccessModifier.ProtectedInternal) || - ctx.WhichGetterHas(CSharpAccessModifier.PrivateProtected))); - - // Assert - act.Should().NotThrow(); - } + // Act + Action action = () => subject.Should().BeEquivalentTo(expected, opt => opt.RespectingDeclaredTypes()); - [Fact] - public void When_members_are_excluded_by_the_access_modifier_of_the_setter_using_a_predicate_they_should_be_ignored() - { - // Arrange - var subject = new ClassWithAllAccessModifiersForMembers( - "public", - "protected", - "internal", - "protected-internal", - "private", - "private-protected"); - - var expected = new ClassWithAllAccessModifiersForMembers( - "public", - "protected", - "ignored-internal", - "ignored-protected-internal", - "ignored-private", - "ignore-private-protected"); - - // Act - Action act = () => subject.Should().BeEquivalentTo(expected, config => - config.Excluding(ctx => ctx.WhichSetterHas(CSharpAccessModifier.Internal) || - ctx.WhichSetterHas(CSharpAccessModifier.ProtectedInternal) || - ctx.WhichSetterHas(CSharpAccessModifier.Private) || - ctx.WhichSetterHas(CSharpAccessModifier.PrivateProtected))); - - // Assert - act.Should().NotThrow(); - } + // Assert + action.Should().NotThrow(); + } - [Fact] - public void When_the_expected_object_has_a_property_not_available_on_the_subject_it_should_throw() - { - // Arrange - var subject = new + [Fact] + public void When_respecting_runtime_types_explicit_interface_member_on_interfaced_subject_should_not_be_used() { - }; + // Arrange + IVehicle expected = new Vehicle + { + VehicleId = 1 + }; - var other = new - { - // ReSharper disable once StringLiteralTypo - City = "Rijswijk" - }; + IVehicle subject = new ExplicitVehicle + { + VehicleId = 2 // instance member + }; - // Act - Action act = () => subject.Should().BeEquivalentTo(other); + subject.VehicleId = 1; // interface member - // Assert - act.Should().Throw().WithMessage( - "Expectation has property subject.City that the other object does not have*"); - } + // Act + Action action = () => subject.Should().BeEquivalentTo(expected, opt => opt.RespectingRuntimeTypes()); - [Fact] - public void When_equally_named_properties_are_type_incompatible_it_should_throw() - { - // Arrange - var subject = new - { - Type = "A" - }; + // Assert + action.Should().Throw(); + } - var other = new + [Fact] + public void When_respecting_runtime_types_explicit_interface_member_on_interfaced_expectation_should_not_be_used() { - Type = 36 - }; + // Arrange + IVehicle expected = new ExplicitVehicle + { + VehicleId = 2 // instance member + }; - // Act - Action act = () => subject.Should().BeEquivalentTo(other); + expected.VehicleId = 1; // interface member - // Assert - act - .Should().Throw() - .WithMessage("Expected property subject.Type to be 36, but found*\"A\"*"); - } + IVehicle subject = new Vehicle + { + VehicleId = 1 + }; - [Fact] - public void When_multiple_properties_mismatch_it_should_report_all_of_them() - { - // Arrange - var subject = new + // Act + Action action = () => subject.Should().BeEquivalentTo(expected, opt => opt.RespectingRuntimeTypes()); + + // Assert + action.Should().Throw(); + } + + [Fact] + public void When_respecting_declared_types_explicit_interface_member_on_subject_should_not_be_used() { - Property1 = "A", - Property2 = "B", - SubType1 = new + // Arrange + var expected = new Vehicle { - SubProperty1 = "C", - SubProperty2 = "D" - } - }; + VehicleId = 1 + }; - var other = new - { - Property1 = "1", - Property2 = "2", - SubType1 = new + var subject = new ExplicitVehicle { - SubProperty1 = "3", - SubProperty2 = "D" - } - }; + VehicleId = 2 + }; - // Act - Action act = () => subject.Should().BeEquivalentTo(other); + ((IVehicle)subject).VehicleId = 1; - // Assert - act - .Should().Throw() - .WithMessage("*property subject.Property1*to be \"1\", but \"A\" differs near \"A\"*") - .WithMessage("*property subject.Property2*to be \"2\", but \"B\" differs near \"B\"*") - .WithMessage("*property subject.SubType1.SubProperty1*to be \"3\", but \"C\" differs near \"C\"*"); - } + // Act + Action action = () => subject.Should().BeEquivalentTo(expected, opt => opt.RespectingDeclaredTypes()); - [Fact] - [SuppressMessage("ReSharper", "StringLiteralTypo")] - public void When_excluding_properties_it_should_still_compare_fields() - { - // Arrange - var class1 = new ClassWithSomeFieldsAndProperties + // Assert + action.Should().Throw(); + } + + [Fact] + public void When_respecting_declared_types_explicit_interface_member_on_expectation_should_not_be_used() { - Field1 = "Lorem", - Field2 = "ipsum", - Field3 = "dolor", - Property1 = "sit", - Property2 = "amet", - Property3 = "consectetur" - }; + // Arrange + var expected = new ExplicitVehicle + { + VehicleId = 2 + }; + + ((IVehicle)expected).VehicleId = 1; - var class2 = new ClassWithSomeFieldsAndProperties { Field1 = "Lorem", Field2 = "ipsum", Field3 = "color" }; + var subject = new Vehicle + { + VehicleId = 1 + }; - // Act - Action act = - () => class1.Should().BeEquivalentTo(class2, opts => opts.ExcludingProperties()); + // Act + Action action = () => subject.Should().BeEquivalentTo(expected, opt => opt.RespectingDeclaredTypes()); - // Assert - act.Should().Throw().WithMessage("*color*dolor*"); - } + // Assert + action.Should().Throw(); + } - [Fact] - public void When_excluding_properties_via_non_array_indexers_it_should_exclude_the_specified_paths() - { - // Arrange - var subject = new + [Fact] + public void When_respecting_runtime_types_explicit_interface_member_on_subject_should_not_be_used() { - List = new[] { new { Foo = 1, Bar = 2 }, new { Foo = 3, Bar = 4 } }.ToList(), - Dictionary = new Dictionary + // Arrange + var expected = new Vehicle { - ["Foo"] = new ClassWithOnlyAProperty { Value = 1 }, - ["Bar"] = new ClassWithOnlyAProperty { Value = 2 } - } - }; + VehicleId = 1 + }; - var expected = new - { - List = new[] { new { Foo = 1, Bar = 2 }, new { Foo = 2, Bar = 4 } }.ToList(), - Dictionary = new Dictionary + var subject = new ExplicitVehicle { - ["Foo"] = new ClassWithOnlyAProperty { Value = 1 }, - ["Bar"] = new ClassWithOnlyAProperty { Value = 3 } - } - }; + VehicleId = 2 + }; - // Act - Action act = () => - subject.Should().BeEquivalentTo(expected, - options => options - .Excluding(x => x.List[1].Foo) - .Excluding(x => x.Dictionary["Bar"].Value)); + ((IVehicle)subject).VehicleId = 1; - // Assert - act.Should().NotThrow(); - } + // Act + Action action = () => subject.Should().BeEquivalentTo(expected, opt => opt.RespectingRuntimeTypes()); - [Fact] - public void When_excluding_properties_via_non_array_indexers_it_should_not_exclude_paths_with_different_indexes() - { - // Arrange - var subject = new - { - List = new[] { new { Foo = 1, Bar = 2 }, new { Foo = 3, Bar = 4 } }.ToList(), - Dictionary = new Dictionary - { - ["Foo"] = new ClassWithOnlyAProperty { Value = 1 }, - ["Bar"] = new ClassWithOnlyAProperty { Value = 2 } - } - }; + // Assert + action.Should().Throw(); + } - var expected = new + [Fact] + public void When_respecting_runtime_types_explicit_interface_member_on_expectation_should_not_be_used() { - List = new[] { new { Foo = 5, Bar = 2 }, new { Foo = 2, Bar = 4 } }.ToList(), - Dictionary = new Dictionary + // Arrange + var expected = new ExplicitVehicle { - ["Foo"] = new ClassWithOnlyAProperty { Value = 6 }, - ["Bar"] = new ClassWithOnlyAProperty { Value = 3 } - } - }; - - // Act - Action act = () => - subject.Should().BeEquivalentTo(expected, - options => options - .Excluding(x => x.List[1].Foo) - .Excluding(x => x.Dictionary["Bar"].Value)); + VehicleId = 2 + }; - // Assert - act.Should().Throw(); - } + ((IVehicle)expected).VehicleId = 1; - [Fact] - [SuppressMessage("ReSharper", "StringLiteralTypo")] - public void When_configured_for_runtime_typing_and_properties_are_excluded_the_runtime_type_should_be_used_and_properties_should_be_ignored() - { - // Arrange - object class1 = new ClassWithSomeFieldsAndProperties - { - Field1 = "Lorem", - Field2 = "ipsum", - Field3 = "dolor", - Property1 = "sit", - Property2 = "amet", - Property3 = "consectetur" - }; + var subject = new Vehicle + { + VehicleId = 1 + }; - object class2 = new ClassWithSomeFieldsAndProperties { Field1 = "Lorem", Field2 = "ipsum", Field3 = "dolor" }; + // Act + Action action = () => subject.Should().BeEquivalentTo(expected, opt => opt.RespectingRuntimeTypes()); - // Act - Action act = - () => class1.Should().BeEquivalentTo(class2, opts => opts.ExcludingProperties().RespectingRuntimeTypes()); + // Assert + action.Should().Throw(); + } - // Assert - act.Should().NotThrow(); - } + [Fact] + public void Excluding_an_interface_property_through_inheritance_should_work() + { + // Arrange + IInterfaceWithTwoProperties[] actual = + { + new DerivedClassImplementingInterface + { + Value1 = 1, + Value2 = 2 + } + }; - [Fact] - [SuppressMessage("ReSharper", "StringLiteralTypo")] - public void When_using_IncludingAllDeclaredProperties_fields_should_be_ignored() - { - // Arrange - var class1 = new ClassWithSomeFieldsAndProperties - { - Field1 = "Lorem", - Field2 = "ipsum", - Field3 = "dolor", - Property1 = "sit", - Property2 = "amet", - Property3 = "consectetur" - }; - - var class2 = new ClassWithSomeFieldsAndProperties - { - Property1 = "sit", - Property2 = "amet", - Property3 = "consectetur" - }; - - // Act - Action act = - () => class1.Should().BeEquivalentTo(class2, opts => opts.IncludingAllDeclaredProperties()); - - // Assert - act.Should().NotThrow(); - } + IInterfaceWithTwoProperties[] expected = + { + new DerivedClassImplementingInterface + { + Value1 = 999, + Value2 = 2 + } + }; - [Fact] - [SuppressMessage("ReSharper", "StringLiteralTypo")] - public void When_using_IncludingAllRuntimeProperties_the_runtime_type_should_be_used_and_fields_should_be_ignored() - { - // Arrange - object class1 = new ClassWithSomeFieldsAndProperties - { - Field1 = "Lorem", - Field2 = "ipsum", - Field3 = "dolor", - Property1 = "sit", - Property2 = "amet", - Property3 = "consectetur" - }; - - object class2 = new ClassWithSomeFieldsAndProperties - { - Property1 = "sit", - Property2 = "amet", - Property3 = "consectetur" - }; - - // Act - Action act = - () => class1.Should().BeEquivalentTo(class2, opts => opts.IncludingAllRuntimeProperties()); - - // Assert - act.Should().NotThrow(); - } + // Act / Assert + actual.Should().BeEquivalentTo(expected, options => options + .Excluding(a => a.Value1) + .RespectingRuntimeTypes()); + } - [Fact] - [SuppressMessage("ReSharper", "StringLiteralTypo")] - public void When_both_field_and_properties_are_configured_for_inclusion_both_should_be_included() - { - // Arrange - var class1 = new ClassWithSomeFieldsAndProperties + [Fact] + public void Including_an_interface_property_through_inheritance_should_work() { - Field1 = "Lorem", - Property1 = "sit" - }; - - var class2 = new ClassWithSomeFieldsAndProperties(); + // Arrange + IInterfaceWithTwoProperties[] actual = + { + new DerivedClassImplementingInterface + { + Value1 = 1, + Value2 = 2 + } + }; - // Act - Action act = - () => class1.Should().BeEquivalentTo(class2, opts => opts.IncludingFields().IncludingProperties()); + IInterfaceWithTwoProperties[] expected = + { + new DerivedClassImplementingInterface + { + Value1 = 999, + Value2 = 2 + } + }; - // Assert - act.Should().Throw().Which.Message.Should().Contain("Field1").And.Contain("Property1"); - } + // Act / Assert + actual.Should().BeEquivalentTo(expected, options => options + .Including(a => a.Value2) + .RespectingRuntimeTypes()); + } - [Fact] - [SuppressMessage("ReSharper", "StringLiteralTypo")] - public void When_respecting_the_runtime_type_is_configured_the_runtime_type_should_be_used_and_both_properties_and_fields_included() - { - // Arrange - object class1 = new ClassWithSomeFieldsAndProperties + public interface IInterfaceWithTwoProperties { - Field1 = "Lorem", - Property1 = "sit" - }; - - object class2 = new ClassWithSomeFieldsAndProperties(); + int Value1 { get; set; } - // Act - Action act = - () => class1.Should().BeEquivalentTo(class2, opts => opts.RespectingRuntimeTypes()); + int Value2 { get; set; } + } - // Assert - act.Should().Throw().Which.Message.Should().Contain("Field1").And.Contain("Property1"); - } + public class BaseProvidingSamePropertiesAsInterface + { + public int Value1 { get; set; } - [Fact] - public void When_excluding_virtual_or_abstract_property_exclusion_works_properly() - { - var obj1 = new Derived { DerivedProperty1 = "Something", DerivedProperty2 = "A" }; - var obj2 = new Derived { DerivedProperty1 = "Something", DerivedProperty2 = "B" }; + public int Value2 { get; set; } + } - obj1.Should().BeEquivalentTo(obj2, opt => opt - .Excluding(o => o.AbstractProperty) - .Excluding(o => o.VirtualProperty) - .Excluding(o => o.DerivedProperty2)); + public class DerivedClassImplementingInterface : BaseProvidingSamePropertiesAsInterface, IInterfaceWithTwoProperties + { + } } - [Fact] - public void A_nested_class_without_properties_inside_a_collection_is_fine() +#if NET5_0_OR_GREATER + public class Covariance { - // Arrange - var sut = new List + [Fact] + public void Excluding_a_covariant_property_should_work() { - new() + // Arrange + var actual = new DerivedWithCovariantOverride(new DerivedWithProperty { - Name = "theName" - } - }; + DerivedProperty = "a", + BaseProperty = "a_base" + }) + { + OtherProp = "other" + }; - // Act / Assert - sut.Should().BeEquivalentTo(new[] - { - new BaseClassPointingToClassWithoutProperties + var expectation = new DerivedWithCovariantOverride(new DerivedWithProperty { - Name = "theName" - } - }); - } + DerivedProperty = "b", + BaseProperty = + "b_base" + }) + { + OtherProp = "other" + }; - internal class BaseClassPointingToClassWithoutProperties - { - public string Name { get; set; } + // Act / Assert + actual.Should().BeEquivalentTo(expectation, opts => opts + .Excluding(d => d.Property)); + } - public ClassWithoutProperty ClassWithoutProperty { get; } = new ClassWithoutProperty(); - } + [Fact] + public void Excluding_a_covariant_property_through_the_base_class_excludes_the_base_class_property() + { + // Arrange + var actual = new DerivedWithCovariantOverride(new DerivedWithProperty + { + DerivedProperty = "a", + BaseProperty = "a_base" + }) + { + OtherProp = "other" + }; - internal class ClassWithoutProperty - { - } + BaseWithAbstractProperty expectation = new DerivedWithCovariantOverride(new DerivedWithProperty + { + DerivedProperty = + "b", + BaseProperty = "b_base" + }) + { + OtherProp = "other" + }; -#if NET5_0_OR_GREATER + // Act + Action act = () => actual.Should().BeEquivalentTo(expectation, opts => opts + .Excluding(d => d.Property)); - [Fact] - public void Excluding_a_covariant_property_should_work() - { - // Arrange - var actual = new DerivedWithCovariantOverride(new DerivedWithProperty { DerivedProperty = "a", BaseProperty = "a_base" }) - { - OtherProp = "other" - }; + // Assert + act.Should().Throw().WithMessage("No members*"); + } - var expectation = new DerivedWithCovariantOverride(new DerivedWithProperty { DerivedProperty = "b", BaseProperty = "b_base" }) + private class BaseWithProperty { - OtherProp = "other" - }; + public string BaseProperty { get; set; } + } - // Act / Assert - actual.Should().BeEquivalentTo(expectation, opts => opts - .Excluding(d => d.Property)); - } + private class DerivedWithProperty : BaseWithProperty + { + public string DerivedProperty { get; set; } + } - [Fact] - public void Excluding_a_covariant_property_through_the_base_class_excludes_the_base_class_property() - { - // Arrange - var actual = new DerivedWithCovariantOverride(new DerivedWithProperty { DerivedProperty = "a", BaseProperty = "a_base" }) + private abstract class BaseWithAbstractProperty { - OtherProp = "other" - }; + public abstract BaseWithProperty Property { get; } + } - BaseWithAbstractProperty expectation = new DerivedWithCovariantOverride(new DerivedWithProperty { DerivedProperty = "b", BaseProperty = "b_base" }) + private sealed class DerivedWithCovariantOverride : BaseWithAbstractProperty { - OtherProp = "other" - }; + public override DerivedWithProperty Property { get; } - // Act - Action act = () => actual.Should().BeEquivalentTo(expectation, opts => opts - .Excluding(d => d.Property)); + public string OtherProp { get; set; } - // Assert - act.Should().Throw().WithMessage("No members*"); + public DerivedWithCovariantOverride(DerivedWithProperty prop) + { + Property = prop; + } + } } - private class BaseWithProperty - { - public string BaseProperty { get; set; } - } +#endif - private class DerivedWithProperty : BaseWithProperty + public class Browsability { - public string DerivedProperty { get; set; } - } + [Fact] + public void When_browsable_field_differs_excluding_non_browsable_members_should_not_affect_result() + { + // Arrange + var subject = new ClassWithNonBrowsableMembers + { + BrowsableField = 0 + }; - private abstract class BaseWithAbstractProperty - { - public abstract BaseWithProperty Property { get; } - } + var expectation = new ClassWithNonBrowsableMembers + { + BrowsableField = 1 + }; - private sealed class DerivedWithCovariantOverride : BaseWithAbstractProperty - { - public override DerivedWithProperty Property { get; } + // Act + Action action = + () => subject.Should().BeEquivalentTo(expectation, config => config.ExcludingNonBrowsableMembers()); - public string OtherProp { get; set; } + // Assert + action.Should().Throw(); + } - public DerivedWithCovariantOverride(DerivedWithProperty prop) + [Fact] + public void When_browsable_property_differs_excluding_non_browsable_members_should_not_affect_result() { - Property = prop; - } - } + // Arrange + var subject = new ClassWithNonBrowsableMembers + { + BrowsableProperty = 0 + }; -#endif + var expectation = new ClassWithNonBrowsableMembers + { + BrowsableProperty = 1 + }; - public interface IInterfaceWithTwoProperties - { - int Value1 { get; set; } + // Act + Action action = + () => subject.Should().BeEquivalentTo(expectation, config => config.ExcludingNonBrowsableMembers()); - int Value2 { get; set; } - } + // Assert + action.Should().Throw(); + } - public class BaseProvidingSamePropertiesAsInterface - { - public int Value1 { get; set; } + [Fact] + public void When_advanced_browsable_field_differs_excluding_non_browsable_members_should_not_affect_result() + { + // Arrange + var subject = new ClassWithNonBrowsableMembers + { + AdvancedBrowsableField = 0 + }; - public int Value2 { get; set; } - } + var expectation = new ClassWithNonBrowsableMembers + { + AdvancedBrowsableField = 1 + }; - public class DerivedClassImplementingInterface : BaseProvidingSamePropertiesAsInterface, IInterfaceWithTwoProperties - { - } + // Act + Action action = + () => subject.Should().BeEquivalentTo(expectation, config => config.ExcludingNonBrowsableMembers()); - [Fact] - public void Excluding_an_interface_property_through_inheritance_should_work() - { - // Arrange - var actual = new IInterfaceWithTwoProperties[] - { - new DerivedClassImplementingInterface { Value1 = 1, Value2 = 2 } - }; + // Assert + action.Should().Throw(); + } - var expected = new IInterfaceWithTwoProperties[] + [Fact] + public void When_advanced_browsable_property_differs_excluding_non_browsable_members_should_not_affect_result() { - new DerivedClassImplementingInterface { Value1 = 999, Value2 = 2 } - }; + // Arrange + var subject = new ClassWithNonBrowsableMembers + { + AdvancedBrowsableProperty = 0 + }; - // Act / Assert - actual.Should().BeEquivalentTo(expected, options => options - .Excluding(a => a.Value1) - .RespectingRuntimeTypes()); - } + var expectation = new ClassWithNonBrowsableMembers + { + AdvancedBrowsableProperty = 1 + }; - [Fact] - public void Including_an_interface_property_through_inheritance_should_work() - { - // Arrange - var actual = new IInterfaceWithTwoProperties[] - { - new DerivedClassImplementingInterface { Value1 = 1, Value2 = 2 } - }; + // Act + Action action = + () => subject.Should().BeEquivalentTo(expectation, config => config.ExcludingNonBrowsableMembers()); - var expected = new IInterfaceWithTwoProperties[] + // Assert + action.Should().Throw(); + } + + [Fact] + public void When_explicitly_browsable_field_differs_excluding_non_browsable_members_should_not_affect_result() { - new DerivedClassImplementingInterface { Value1 = 999, Value2 = 2 } - }; + // Arrange + var subject = new ClassWithNonBrowsableMembers + { + ExplicitlyBrowsableField = 0 + }; - // Act / Assert - actual.Should().BeEquivalentTo(expected, options => options - .Including(a => a.Value2) - .RespectingRuntimeTypes()); - } + var expectation = new ClassWithNonBrowsableMembers + { + ExplicitlyBrowsableField = 1 + }; - [Fact] - public void When_browsable_field_differs_excluding_non_browsable_members_should_not_affect_result() - { - // Arrange - var subject = new ClassWithNonBrowsableMembers() { BrowsableField = 0 }; - var expectation = new ClassWithNonBrowsableMembers() { BrowsableField = 1 }; + // Act + Action action = + () => subject.Should().BeEquivalentTo(expectation, config => config.ExcludingNonBrowsableMembers()); - // Act - Action action = - () => subject.Should().BeEquivalentTo(expectation, config => config.ExcludingNonBrowsableMembers()); + // Assert + action.Should().Throw(); + } - // Assert - action.Should().Throw(); - } + [Fact] + public void When_explicitly_browsable_property_differs_excluding_non_browsable_members_should_not_affect_result() + { + // Arrange + var subject = new ClassWithNonBrowsableMembers + { + ExplicitlyBrowsableProperty = 0 + }; - [Fact] - public void When_browsable_property_differs_excluding_non_browsable_members_should_not_affect_result() - { - // Arrange - var subject = new ClassWithNonBrowsableMembers() { BrowsableProperty = 0 }; - var expectation = new ClassWithNonBrowsableMembers() { BrowsableProperty = 1 }; + var expectation = new ClassWithNonBrowsableMembers + { + ExplicitlyBrowsableProperty = 1 + }; - // Act - Action action = - () => subject.Should().BeEquivalentTo(expectation, config => config.ExcludingNonBrowsableMembers()); + // Act + Action action = + () => subject.Should().BeEquivalentTo(expectation, config => config.ExcludingNonBrowsableMembers()); - // Assert - action.Should().Throw(); - } + // Assert + action.Should().Throw(); + } - [Fact] - public void When_advanced_browsable_field_differs_excluding_non_browsable_members_should_not_affect_result() - { - // Arrange - var subject = new ClassWithNonBrowsableMembers() { AdvancedBrowsableField = 0 }; - var expectation = new ClassWithNonBrowsableMembers() { AdvancedBrowsableField = 1 }; + [Fact] + public void When_non_browsable_field_differs_excluding_non_browsable_members_should_make_it_succeed() + { + // Arrange + var subject = new ClassWithNonBrowsableMembers + { + NonBrowsableField = 0 + }; - // Act - Action action = - () => subject.Should().BeEquivalentTo(expectation, config => config.ExcludingNonBrowsableMembers()); + var expectation = new ClassWithNonBrowsableMembers + { + NonBrowsableField = 1 + }; - // Assert - action.Should().Throw(); - } + // Act & Assert + subject.Should().BeEquivalentTo(expectation, config => config.ExcludingNonBrowsableMembers()); + } - [Fact] - public void When_advanced_browsable_property_differs_excluding_non_browsable_members_should_not_affect_result() - { - // Arrange - var subject = new ClassWithNonBrowsableMembers() { AdvancedBrowsableProperty = 0 }; - var expectation = new ClassWithNonBrowsableMembers() { AdvancedBrowsableProperty = 1 }; + [Fact] + public void When_non_browsable_property_differs_excluding_non_browsable_members_should_make_it_succeed() + { + // Arrange + var subject = new ClassWithNonBrowsableMembers + { + NonBrowsableProperty = 0 + }; - // Act - Action action = - () => subject.Should().BeEquivalentTo(expectation, config => config.ExcludingNonBrowsableMembers()); + var expectation = new ClassWithNonBrowsableMembers + { + NonBrowsableProperty = 1 + }; - // Assert - action.Should().Throw(); - } + // Act & Assert + subject.Should().BeEquivalentTo(expectation, config => config.ExcludingNonBrowsableMembers()); + } - [Fact] - public void When_explicitly_browsable_field_differs_excluding_non_browsable_members_should_not_affect_result() - { - // Arrange - var subject = new ClassWithNonBrowsableMembers() { ExplicitlyBrowsableField = 0 }; - var expectation = new ClassWithNonBrowsableMembers() { ExplicitlyBrowsableField = 1 }; + [Fact] + public void When_property_is_non_browsable_only_in_subject_excluding_non_browsable_members_should_not_make_it_succeed() + { + // Arrange + var subject = + new ClassWhereMemberThatCouldBeNonBrowsableIsNonBrowsable + { + PropertyThatMightBeNonBrowsable = 0 + }; - // Act - Action action = - () => subject.Should().BeEquivalentTo(expectation, config => config.ExcludingNonBrowsableMembers()); + var expectation = + new ClassWhereMemberThatCouldBeNonBrowsableIsBrowsable + { + PropertyThatMightBeNonBrowsable = 1 + }; - // Assert - action.Should().Throw(); - } + // Act + Action action = + () => subject.Should().BeEquivalentTo(expectation, config => config.ExcludingNonBrowsableMembers()); - [Fact] - public void When_explicitly_browsable_property_differs_excluding_non_browsable_members_should_not_affect_result() - { - // Arrange - var subject = new ClassWithNonBrowsableMembers() { ExplicitlyBrowsableProperty = 0 }; - var expectation = new ClassWithNonBrowsableMembers() { ExplicitlyBrowsableProperty = 1 }; + // Assert + action.Should().Throw() + .WithMessage("Expected property subject.PropertyThatMightBeNonBrowsable to be 1, but found 0.*"); + } - // Act - Action action = - () => subject.Should().BeEquivalentTo(expectation, config => config.ExcludingNonBrowsableMembers()); + [Fact] + public void + When_property_is_non_browsable_only_in_subject_ignoring_non_browsable_members_on_subject_should_make_it_succeed() + { + // Arrange + var subject = + new ClassWhereMemberThatCouldBeNonBrowsableIsNonBrowsable + { + PropertyThatMightBeNonBrowsable = 0 + }; - // Assert - action.Should().Throw(); - } + var expectation = + new ClassWhereMemberThatCouldBeNonBrowsableIsBrowsable + { + PropertyThatMightBeNonBrowsable = 1 + }; - [Fact] - public void When_non_browsable_field_differs_excluding_non_browsable_members_should_make_it_succeed() - { - // Arrange - var subject = new ClassWithNonBrowsableMembers() { NonBrowsableField = 0 }; - var expectation = new ClassWithNonBrowsableMembers() { NonBrowsableField = 1 }; + // Act & Assert + subject.Should().BeEquivalentTo( + expectation, + config => config.IgnoringNonBrowsableMembersOnSubject().ExcludingMissingMembers()); + } - // Act & Assert - subject.Should().BeEquivalentTo(expectation, config => config.ExcludingNonBrowsableMembers()); - } + [Fact] + public void When_non_browsable_property_on_subject_is_ignored_but_is_present_on_expectation_it_should_fail() + { + // Arrange + var subject = + new ClassWhereMemberThatCouldBeNonBrowsableIsNonBrowsable + { + PropertyThatMightBeNonBrowsable = 0 + }; - [Fact] - public void When_non_browsable_property_differs_excluding_non_browsable_members_should_make_it_succeed() - { - // Arrange - var subject = new ClassWithNonBrowsableMembers() { NonBrowsableProperty = 0 }; - var expectation = new ClassWithNonBrowsableMembers() { NonBrowsableProperty = 1 }; + var expectation = + new ClassWhereMemberThatCouldBeNonBrowsableIsBrowsable + { + PropertyThatMightBeNonBrowsable = 1 + }; - // Act & Assert - subject.Should().BeEquivalentTo(expectation, config => config.ExcludingNonBrowsableMembers()); - } + // Act + Action action = + () => subject.Should().BeEquivalentTo(expectation, config => config.IgnoringNonBrowsableMembersOnSubject()); - [Fact] - public void When_property_is_non_browsable_only_in_subject_excluding_non_browsable_members_should_not_make_it_succeed() - { - // Arrange - var subject = new ClassWhereMemberThatCouldBeNonBrowsableIsNonBrowsable() { PropertyThatMightBeNonBrowsable = 0 }; - var expectation = new ClassWhereMemberThatCouldBeNonBrowsableIsBrowsable() { PropertyThatMightBeNonBrowsable = 1 }; + // Assert + action.Should().Throw().WithMessage( + "Expectation has * subject.*ThatMightBeNonBrowsable that is non-browsable in the other object, and non-browsable " + + "members on the subject are ignored with the current configuration*"); + } - // Act - Action action = - () => subject.Should().BeEquivalentTo(expectation, config => config.ExcludingNonBrowsableMembers()); + [Fact] + public void When_property_is_non_browsable_only_in_expectation_excluding_non_browsable_members_should_make_it_succeed() + { + // Arrange + var subject = new ClassWhereMemberThatCouldBeNonBrowsableIsBrowsable + { + PropertyThatMightBeNonBrowsable = 0 + }; - // Assert - action.Should().Throw().WithMessage("Expected property subject.PropertyThatMightBeNonBrowsable to be 1, but found 0.*"); - } + var expectation = + new ClassWhereMemberThatCouldBeNonBrowsableIsNonBrowsable + { + PropertyThatMightBeNonBrowsable = 1 + }; - [Fact] - public void When_property_is_non_browsable_only_in_subject_ignoring_non_browsable_members_on_subject_should_make_it_succeed() - { - // Arrange - var subject = new ClassWhereMemberThatCouldBeNonBrowsableIsNonBrowsable() { PropertyThatMightBeNonBrowsable = 0 }; - var expectation = new ClassWhereMemberThatCouldBeNonBrowsableIsBrowsable() { PropertyThatMightBeNonBrowsable = 1 }; - - // Act & Assert - subject.Should().BeEquivalentTo( - expectation, - config => config.IgnoringNonBrowsableMembersOnSubject().ExcludingMissingMembers()); - } + // Act & Assert + subject.Should().BeEquivalentTo(expectation, config => config.ExcludingNonBrowsableMembers()); + } - [Fact] - public void When_non_browsable_property_on_subject_is_ignored_but_is_present_on_expectation_it_should_fail() - { - // Arrange - var subject = new ClassWhereMemberThatCouldBeNonBrowsableIsNonBrowsable() { PropertyThatMightBeNonBrowsable = 0 }; - var expectation = new ClassWhereMemberThatCouldBeNonBrowsableIsBrowsable() { PropertyThatMightBeNonBrowsable = 1 }; - - // Act - Action action = - () => subject.Should().BeEquivalentTo(expectation, config => config.IgnoringNonBrowsableMembersOnSubject()); - - // Assert - action.Should().Throw().WithMessage( - $"Expectation has * subject.*ThatMightBeNonBrowsable that is non-browsable in the other object, and non-browsable " + - $"members on the subject are ignored with the current configuration*"); - } + [Fact] + public void When_field_is_non_browsable_only_in_subject_excluding_non_browsable_members_should_not_make_it_succeed() + { + // Arrange + var subject = + new ClassWhereMemberThatCouldBeNonBrowsableIsNonBrowsable + { + FieldThatMightBeNonBrowsable = 0 + }; - [Fact] - public void When_property_is_non_browsable_only_in_expectation_excluding_non_browsable_members_should_make_it_succeed() - { - // Arrange - var subject = new ClassWhereMemberThatCouldBeNonBrowsableIsBrowsable() { PropertyThatMightBeNonBrowsable = 0 }; - var expectation = new ClassWhereMemberThatCouldBeNonBrowsableIsNonBrowsable() { PropertyThatMightBeNonBrowsable = 1 }; + var expectation = + new ClassWhereMemberThatCouldBeNonBrowsableIsBrowsable + { + FieldThatMightBeNonBrowsable = 1 + }; - // Act & Assert - subject.Should().BeEquivalentTo(expectation, config => config.ExcludingNonBrowsableMembers()); - } + // Act + Action action = + () => subject.Should().BeEquivalentTo(expectation, config => config.ExcludingNonBrowsableMembers()); - [Fact] - public void When_field_is_non_browsable_only_in_subject_excluding_non_browsable_members_should_not_make_it_succeed() - { - // Arrange - var subject = new ClassWhereMemberThatCouldBeNonBrowsableIsNonBrowsable() { FieldThatMightBeNonBrowsable = 0 }; - var expectation = new ClassWhereMemberThatCouldBeNonBrowsableIsBrowsable() { FieldThatMightBeNonBrowsable = 1 }; + // Assert + action.Should().Throw() + .WithMessage("Expected field subject.FieldThatMightBeNonBrowsable to be 1, but found 0.*"); + } - // Act - Action action = - () => subject.Should().BeEquivalentTo(expectation, config => config.ExcludingNonBrowsableMembers()); + [Fact] + public void When_field_is_non_browsable_only_in_subject_ignoring_non_browsable_members_on_subject_should_make_it_succeed() + { + // Arrange + var subject = + new ClassWhereMemberThatCouldBeNonBrowsableIsNonBrowsable + { + FieldThatMightBeNonBrowsable = 0 + }; - // Assert - action.Should().Throw().WithMessage("Expected field subject.FieldThatMightBeNonBrowsable to be 1, but found 0.*"); - } + var expectation = + new ClassWhereMemberThatCouldBeNonBrowsableIsBrowsable + { + FieldThatMightBeNonBrowsable = 1 + }; - [Fact] - public void When_field_is_non_browsable_only_in_subject_ignoring_non_browsable_members_on_subject_should_make_it_succeed() - { - // Arrange - var subject = new ClassWhereMemberThatCouldBeNonBrowsableIsNonBrowsable() { FieldThatMightBeNonBrowsable = 0 }; - var expectation = new ClassWhereMemberThatCouldBeNonBrowsableIsBrowsable() { FieldThatMightBeNonBrowsable = 1 }; - - // Act & Assert - subject.Should().BeEquivalentTo( - expectation, - config => config.IgnoringNonBrowsableMembersOnSubject().ExcludingMissingMembers()); - } + // Act & Assert + subject.Should().BeEquivalentTo( + expectation, + config => config.IgnoringNonBrowsableMembersOnSubject().ExcludingMissingMembers()); + } - [Fact] - public void When_field_is_non_browsable_only_in_expectation_excluding_non_browsable_members_should_make_it_succeed() - { - // Arrange - var subject = new ClassWhereMemberThatCouldBeNonBrowsableIsBrowsable() { FieldThatMightBeNonBrowsable = 0 }; - var expectation = new ClassWhereMemberThatCouldBeNonBrowsableIsNonBrowsable() { FieldThatMightBeNonBrowsable = 1 }; + [Fact] + public void When_field_is_non_browsable_only_in_expectation_excluding_non_browsable_members_should_make_it_succeed() + { + // Arrange + var subject = new ClassWhereMemberThatCouldBeNonBrowsableIsBrowsable + { + FieldThatMightBeNonBrowsable = 0 + }; - // Act & Assert - subject.Should().BeEquivalentTo(expectation, config => config.ExcludingNonBrowsableMembers()); - } + var expectation = + new ClassWhereMemberThatCouldBeNonBrowsableIsNonBrowsable + { + FieldThatMightBeNonBrowsable = 1 + }; + + // Act & Assert + subject.Should().BeEquivalentTo(expectation, config => config.ExcludingNonBrowsableMembers()); + } - public class NonBrowsableOnOneButMissingFromTheOther - { [Fact] public void When_property_is_missing_from_subject_excluding_non_browsable_members_should_make_it_succeed() { @@ -2064,22 +2328,21 @@ public void When_property_is_missing_from_subject_excluding_non_browsable_member ExplicitlyBrowsableProperty = 1, AdvancedBrowsableField = 1, AdvancedBrowsableProperty = 1, - NonBrowsableField = 2, + NonBrowsableField = 2 /* NonBrowsableProperty missing */ }; - var expected = - new ClassWithNonBrowsableMembers - { - BrowsableField = 1, - BrowsableProperty = 1, - ExplicitlyBrowsableField = 1, - ExplicitlyBrowsableProperty = 1, - AdvancedBrowsableField = 1, - AdvancedBrowsableProperty = 1, - NonBrowsableField = 2, - NonBrowsableProperty = 2, - }; + var expected = new ClassWithNonBrowsableMembers + { + BrowsableField = 1, + BrowsableProperty = 1, + ExplicitlyBrowsableField = 1, + ExplicitlyBrowsableProperty = 1, + AdvancedBrowsableField = 1, + AdvancedBrowsableProperty = 1, + NonBrowsableField = 2, + NonBrowsableProperty = 2 + }; // Act & Assert subject.Should().BeEquivalentTo(expected, opt => opt.ExcludingNonBrowsableMembers()); @@ -2099,21 +2362,20 @@ public void When_field_is_missing_from_subject_excluding_non_browsable_members_s AdvancedBrowsableField = 1, AdvancedBrowsableProperty = 1, /* NonBrowsableField missing */ - NonBrowsableProperty = 2, + NonBrowsableProperty = 2 }; - var expected = - new ClassWithNonBrowsableMembers - { - BrowsableField = 1, - BrowsableProperty = 1, - ExplicitlyBrowsableField = 1, - ExplicitlyBrowsableProperty = 1, - AdvancedBrowsableField = 1, - AdvancedBrowsableProperty = 1, - NonBrowsableField = 2, - NonBrowsableProperty = 2, - }; + var expected = new ClassWithNonBrowsableMembers + { + BrowsableField = 1, + BrowsableProperty = 1, + ExplicitlyBrowsableField = 1, + ExplicitlyBrowsableProperty = 1, + AdvancedBrowsableField = 1, + AdvancedBrowsableProperty = 1, + NonBrowsableField = 2, + NonBrowsableProperty = 2 + }; // Act & Assert subject.Should().BeEquivalentTo(expected, opt => opt.ExcludingNonBrowsableMembers()); @@ -2123,18 +2385,17 @@ public void When_field_is_missing_from_subject_excluding_non_browsable_members_s public void When_property_is_missing_from_expectation_excluding_non_browsable_members_should_make_it_succeed() { // Arrange - var subject = - new ClassWithNonBrowsableMembers - { - BrowsableField = 1, - BrowsableProperty = 1, - ExplicitlyBrowsableField = 1, - ExplicitlyBrowsableProperty = 1, - AdvancedBrowsableField = 1, - AdvancedBrowsableProperty = 1, - NonBrowsableField = 2, - NonBrowsableProperty = 2, - }; + var subject = new ClassWithNonBrowsableMembers + { + BrowsableField = 1, + BrowsableProperty = 1, + ExplicitlyBrowsableField = 1, + ExplicitlyBrowsableProperty = 1, + AdvancedBrowsableField = 1, + AdvancedBrowsableProperty = 1, + NonBrowsableField = 2, + NonBrowsableProperty = 2 + }; var expected = new @@ -2145,7 +2406,7 @@ public void When_property_is_missing_from_expectation_excluding_non_browsable_me ExplicitlyBrowsableProperty = 1, AdvancedBrowsableField = 1, AdvancedBrowsableProperty = 1, - NonBrowsableField = 2, + NonBrowsableField = 2 /* NonBrowsableProperty missing */ }; @@ -2157,18 +2418,17 @@ public void When_property_is_missing_from_expectation_excluding_non_browsable_me public void When_field_is_missing_from_expectation_excluding_non_browsable_members_should_make_it_succeed() { // Arrange - var subject = - new ClassWithNonBrowsableMembers - { - BrowsableField = 1, - BrowsableProperty = 1, - ExplicitlyBrowsableField = 1, - ExplicitlyBrowsableProperty = 1, - AdvancedBrowsableField = 1, - AdvancedBrowsableProperty = 1, - NonBrowsableField = 2, - NonBrowsableProperty = 2, - }; + var subject = new ClassWithNonBrowsableMembers + { + BrowsableField = 1, + BrowsableProperty = 1, + ExplicitlyBrowsableField = 1, + ExplicitlyBrowsableProperty = 1, + AdvancedBrowsableField = 1, + AdvancedBrowsableProperty = 1, + NonBrowsableField = 2, + NonBrowsableProperty = 2 + }; var expected = new @@ -2180,7 +2440,7 @@ public void When_field_is_missing_from_expectation_excluding_non_browsable_membe AdvancedBrowsableField = 1, AdvancedBrowsableProperty = 1, /* NonBrowsableField missing */ - NonBrowsableProperty = 2, + NonBrowsableProperty = 2 }; // Act & Assert @@ -2188,20 +2448,19 @@ public void When_field_is_missing_from_expectation_excluding_non_browsable_membe } [Fact] - public void When_non_browsable_members_are_excluded_it_should_still_be_possible_to_explicitly_include_non_browsable_field() + public void + When_non_browsable_members_are_excluded_it_should_still_be_possible_to_explicitly_include_non_browsable_field() { // Arrange - var subject = - new ClassWithNonBrowsableMembers() - { - NonBrowsableField = 1, - }; + var subject = new ClassWithNonBrowsableMembers + { + NonBrowsableField = 1 + }; - var expectation = - new ClassWithNonBrowsableMembers() - { - NonBrowsableField = 2, - }; + var expectation = new ClassWithNonBrowsableMembers + { + NonBrowsableField = 2 + }; // Act Action action = @@ -2210,24 +2469,24 @@ public void When_non_browsable_members_are_excluded_it_should_still_be_possible_ opt => opt.IncludingFields().ExcludingNonBrowsableMembers().Including(e => e.NonBrowsableField)); // Assert - action.Should().Throw().WithMessage("Expected field subject.NonBrowsableField to be 2, but found 1.*"); + action.Should().Throw() + .WithMessage("Expected field subject.NonBrowsableField to be 2, but found 1.*"); } [Fact] - public void When_non_browsable_members_are_excluded_it_should_still_be_possible_to_explicitly_include_non_browsable_property() + public void + When_non_browsable_members_are_excluded_it_should_still_be_possible_to_explicitly_include_non_browsable_property() { // Arrange - var subject = - new ClassWithNonBrowsableMembers() - { - NonBrowsableProperty = 1, - }; + var subject = new ClassWithNonBrowsableMembers + { + NonBrowsableProperty = 1 + }; - var expectation = - new ClassWithNonBrowsableMembers() - { - NonBrowsableProperty = 2, - }; + var expectation = new ClassWithNonBrowsableMembers + { + NonBrowsableProperty = 2 + }; // Act Action action = @@ -2236,56 +2495,57 @@ public void When_non_browsable_members_are_excluded_it_should_still_be_possible_ opt => opt.IncludingProperties().ExcludingNonBrowsableMembers().Including(e => e.NonBrowsableProperty)); // Assert - action.Should().Throw().WithMessage("Expected property subject.NonBrowsableProperty to be 2, but found 1.*"); + action.Should().Throw() + .WithMessage("Expected property subject.NonBrowsableProperty to be 2, but found 1.*"); } - } - private class ClassWithNonBrowsableMembers - { - public int BrowsableField = -1; + private class ClassWithNonBrowsableMembers + { + public int BrowsableField = -1; - public int BrowsableProperty { get; set; } + public int BrowsableProperty { get; set; } - [EditorBrowsable(EditorBrowsableState.Always)] - public int ExplicitlyBrowsableField = -1; + [EditorBrowsable(EditorBrowsableState.Always)] + public int ExplicitlyBrowsableField = -1; - [EditorBrowsable(EditorBrowsableState.Always)] - public int ExplicitlyBrowsableProperty { get; set; } + [EditorBrowsable(EditorBrowsableState.Always)] + public int ExplicitlyBrowsableProperty { get; set; } - [EditorBrowsable(EditorBrowsableState.Advanced)] - public int AdvancedBrowsableField = -1; + [EditorBrowsable(EditorBrowsableState.Advanced)] + public int AdvancedBrowsableField = -1; - [EditorBrowsable(EditorBrowsableState.Advanced)] - public int AdvancedBrowsableProperty { get; set; } + [EditorBrowsable(EditorBrowsableState.Advanced)] + public int AdvancedBrowsableProperty { get; set; } - [EditorBrowsable(EditorBrowsableState.Never)] - public int NonBrowsableField = -1; + [EditorBrowsable(EditorBrowsableState.Never)] + public int NonBrowsableField = -1; - [EditorBrowsable(EditorBrowsableState.Never)] - public int NonBrowsableProperty { get; set; } - } + [EditorBrowsable(EditorBrowsableState.Never)] + public int NonBrowsableProperty { get; set; } + } - private class ClassWhereMemberThatCouldBeNonBrowsableIsBrowsable - { - public int BrowsableField = -1; + private class ClassWhereMemberThatCouldBeNonBrowsableIsBrowsable + { + public int BrowsableField = -1; - public int BrowsableProperty { get; set; } + public int BrowsableProperty { get; set; } - public int FieldThatMightBeNonBrowsable = -1; + public int FieldThatMightBeNonBrowsable = -1; - public int PropertyThatMightBeNonBrowsable { get; set; } - } + public int PropertyThatMightBeNonBrowsable { get; set; } + } - private class ClassWhereMemberThatCouldBeNonBrowsableIsNonBrowsable - { - public int BrowsableField = -1; + private class ClassWhereMemberThatCouldBeNonBrowsableIsNonBrowsable + { + public int BrowsableField = -1; - public int BrowsableProperty { get; set; } + public int BrowsableProperty { get; set; } - [EditorBrowsable(EditorBrowsableState.Never)] - public int FieldThatMightBeNonBrowsable = -1; + [EditorBrowsable(EditorBrowsableState.Never)] + public int FieldThatMightBeNonBrowsable = -1; - [EditorBrowsable(EditorBrowsableState.Never)] - public int PropertyThatMightBeNonBrowsable { get; set; } + [EditorBrowsable(EditorBrowsableState.Never)] + public int PropertyThatMightBeNonBrowsable { get; set; } + } } }