From 8ced3f1f39ecd9e8c38f3c8652cd16b78578e8fa Mon Sep 17 00:00:00 2001 From: nemec Date: Mon, 2 Aug 2021 00:34:58 +0200 Subject: [PATCH 001/181] Add ComparisionContext, IContextableComparer, IComparableExtensions. Extend CalculateDifferences operation with current comparision context. --- .../ObjectsComparer.Tests/DaNComparerTests.cs | 510 ++++++++++++++++++ ObjectsComparer/ObjectsComparer/Comparer~1.cs | 2 +- .../ObjectsComparer/ComparisionContext.cs | 27 + .../CustomComparers/EnumerablesComparer.cs | 11 +- .../ObjectsComparer/IComparableExtensions.cs | 20 + .../ObjectsComparer/IContextableComparer.cs | 12 + 6 files changed, 579 insertions(+), 3 deletions(-) create mode 100644 ObjectsComparer/ObjectsComparer.Tests/DaNComparerTests.cs create mode 100644 ObjectsComparer/ObjectsComparer/ComparisionContext.cs create mode 100644 ObjectsComparer/ObjectsComparer/IComparableExtensions.cs create mode 100644 ObjectsComparer/ObjectsComparer/IContextableComparer.cs diff --git a/ObjectsComparer/ObjectsComparer.Tests/DaNComparerTests.cs b/ObjectsComparer/ObjectsComparer.Tests/DaNComparerTests.cs new file mode 100644 index 0000000..d0bd433 --- /dev/null +++ b/ObjectsComparer/ObjectsComparer.Tests/DaNComparerTests.cs @@ -0,0 +1,510 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using NSubstitute; +using NUnit.Framework; +using ObjectsComparer.Tests.TestClasses; + +namespace ObjectsComparer.Tests +{ + public class Driver + { + + } + + public class Car + { + //public IEnumerable Items1 { get; set; } + + //public IEnumerable Items2 { get; set; } + + public string[] Items3 { get; set; } + } + + [TestFixture] + public class DaNComparerTests + { + [Test] + public void TestEnumerablesComparer() + { + var car1 = new Car(); + //car1.Items1 = new int[] { 1, 2, 3 }; + //car1.Items2 = new List { "ahoj", "nazdar", "čau" }; + car1.Items3 = new string[] { "ahoj", "nazdar", "čau" }; + var car2 = new Car(); + //car2.Items1 = new int[] { -1, 2, 3 }; + //car2.Items2 = new List { "ahoj", "hello", "čau" }; + car1.Items3 = new string[] { "hi", "nazdar", "čau" }; + var comparer = new Comparer(); + var diffs = comparer.CalculateDifferences(typeof(Car), car1, car2).ToArray(); + //var member = car1.GetType().GetMember(nameof(car1.Items1)).Single(); + } + + [Test] + public void PropertyEquality() + { + var a1 = new A {IntProperty = 10, DateTimeProperty = new DateTime(2017, 1, 1), Property3 = 5}; + var a2 = new A {IntProperty = 10, DateTimeProperty = new DateTime(2017, 1, 1), Property3 = 8}; + var comparer = new Comparer(); + + var isEqual = comparer.Compare(a1, a2); + + Assert.IsTrue(isEqual); + } + + [Test] + public void PropertyInequality() + { + var date1 = new DateTime(2017, 1, 1); + var date2 = new DateTime(2017, 1, 2); + var a1 = new A {IntProperty = 10, DateTimeProperty = date1}; + var a2 = new A {IntProperty = 8, DateTimeProperty = date2}; + var comparer = new Comparer(); + + var differences = comparer.CalculateDifferences(a1, a2).ToList(); + + CollectionAssert.IsNotEmpty(differences); + Assert.AreEqual("IntProperty", differences[0].MemberPath); + Assert.AreEqual("10", differences[0].Value1); + Assert.AreEqual("8", differences[0].Value2); + Assert.AreEqual("DateTimeProperty", differences[1].MemberPath); + // ReSharper disable once SpecifyACultureInStringConversionExplicitly + Assert.AreEqual(date1.ToString(), differences[1].Value1); + // ReSharper disable once SpecifyACultureInStringConversionExplicitly + Assert.AreEqual(date2.ToString(), differences[1].Value2); + } + + [Test] + public void ReadOnlyPropertyEquality() + { + var a1 = new A(1.99); + var a2 = new A(1.99); + var comparer = new Comparer(); + + var isEqual = comparer.Compare(a1, a2); + + Assert.IsTrue(isEqual); + } + + [Test] + public void ReadOnlyPropertyInequality() + { + var a1 = new A(1.99); + var a2 = new A(0.89); + var comparer = new Comparer(); + + var differences = comparer.CalculateDifferences(a1, a2).ToList(); + + CollectionAssert.IsNotEmpty(differences); + Assert.AreEqual("ReadOnlyProperty", differences.First().MemberPath); + Assert.AreEqual("1.99", differences.First().Value1); + Assert.AreEqual("0.89", differences.First().Value2); + } + + [Test] + public void ProtectedProperty() + { + var a1 = new A(true); + var a2 = new A(false); + var comparer = new Comparer(); + + var isEqual = comparer.Compare(a1, a2); + + Assert.IsTrue(isEqual); + } + + [Test] + public void FieldEquality() + { + var a1 = new A {Field = 9}; + var a2 = new A {Field = 9}; + var comparer = new Comparer(); + + var isEqual = comparer.Compare(a1, a2); + + Assert.IsTrue(isEqual); + } + + [Test] + public void FieldInequality() + { + var a1 = new A {Field = 10}; + var a2 = new A {Field = 8}; + var comparer = new Comparer(); + + var differences = comparer.CalculateDifferences(a1, a2).ToList(); + + CollectionAssert.IsNotEmpty(differences); + Assert.AreEqual("Field", differences.First().MemberPath); + Assert.AreEqual("10", differences.First().Value1); + Assert.AreEqual("8", differences.First().Value2); + } + + [Test] + public void ReadOnlyFieldEquality() + { + var a1 = new A("Str1"); + var a2 = new A("Str1"); + var comparer = new Comparer(); + + var isEqual = comparer.Compare(a1, a2); + + Assert.IsTrue(isEqual); + } + + [Test] + public void ReadOnlyFieldInequality() + { + var a1 = new A("Str1"); + var a2 = new A("Str2"); + var comparer = new Comparer(); + + var differences = comparer.CalculateDifferences(a1, a2).ToList(); + + CollectionAssert.IsNotEmpty(differences); + Assert.AreEqual("ReadOnlyField", differences.First().MemberPath); + Assert.AreEqual("Str1", differences.First().Value1); + Assert.AreEqual("Str2", differences.First().Value2); + } + + [Test] + public void ProtectedField() + { + var a1 = new A(5); + var a2 = new A(6); + var comparer = new Comparer(); + + var isEqual = comparer.Compare(a1, a2); + + Assert.IsTrue(isEqual); + } + + [Test] + public void ClassPropertyEquality() + { + var a1 = new A {ClassB = new B {Property1 = "Str1"}}; + var a2 = new A {ClassB = new B {Property1 = "Str1"}}; + var comparer = new Comparer(); + + var isEqual = comparer.Compare(a1, a2); + + Assert.IsTrue(isEqual); + } + + [Test] + public void ClassPropertyInequality() + { + var a1 = new A {ClassB = new B {Property1 = "Str1"}}; + var a2 = new A {ClassB = new B {Property1 = "Str2"}}; + var comparer = new Comparer(); + + var differences = comparer.CalculateDifferences(a1, a2).ToList(); + + CollectionAssert.IsNotEmpty(differences); + Assert.AreEqual("ClassB.Property1", differences.First().MemberPath); + Assert.AreEqual("Str1", differences.First().Value1); + Assert.AreEqual("Str2", differences.First().Value2); + } + + [Test] + public void ClassPropertyInequalityFirstNull() + { + var a1 = new A(); + var a2 = new A {ClassB = new B {Property1 = "Str2"}}; + var comparer = new Comparer(); + + var differences = comparer.CalculateDifferences(a1, a2).ToList(); + + CollectionAssert.IsNotEmpty(differences); + Assert.AreEqual("ClassB", differences.First().MemberPath); + Assert.AreEqual("", differences.First().Value1); + Assert.AreEqual(a2.ClassB.ToString(), differences.First().Value2); + } + + [Test] + public void ClassPropertyInequalitySecondNull() + { + var a1 = new A {ClassB = new B {Property1 = "Str2"}}; + var a2 = new A(); + var comparer = new Comparer(); + + var differences = comparer.CalculateDifferences(a1, a2).ToList(); + + CollectionAssert.IsNotEmpty(differences); + Assert.AreEqual("ClassB", differences.First().MemberPath); + Assert.AreEqual(a1.ClassB.ToString(), differences.First().Value1); + Assert.AreEqual("", differences.First().Value2); + } + + [Test] + public void NoRecursiveComparison() + { + var a1 = new A {ClassB = new B {Property1 = "Str1"}}; + var a2 = new A {ClassB = new B {Property1 = "Str2"}}; + var comparer = new Comparer(new ComparisonSettings {RecursiveComparison = false}); + + var isEqual = comparer.Compare(a1, a2); + + Assert.IsTrue(isEqual); + } + + [Test] + public void InterfacePropertyEquality() + { + var a1 = new A {IntefaceProperty = new TestInterfaceImplementation1 {Property = "Str1"}}; + var a2 = new A + { + IntefaceProperty = new TestInterfaceImplementation2 {Property = "Str1", AnotherProperty = 50} + }; + var comparer = new Comparer(); + + var isEqual = comparer.Compare(a1, a2); + + Assert.IsTrue(isEqual); + } + + [Test] + public void InterfacePropertyInequality() + { + var a1 = new A {IntefaceProperty = new TestInterfaceImplementation1 {Property = "Str1"}}; + var a2 = new A + { + IntefaceProperty = new TestInterfaceImplementation2 {Property = "Str2", AnotherProperty = 50} + }; + var comparer = new Comparer(); + + var differences = comparer.CalculateDifferences(a1, a2).ToList(); + + CollectionAssert.IsNotEmpty(differences); + Assert.AreEqual("IntefaceProperty.Property", differences.First().MemberPath); + Assert.AreEqual("Str1", differences.First().Value1); + Assert.AreEqual("Str2", differences.First().Value2); + } + + [Test] + public void StructPropertyEquality() + { + var a1 = new A {StructProperty = new TestStruct {FieldA = "FA", FieldB = "FB"}}; + var a2 = new A {StructProperty = new TestStruct {FieldA = "FA", FieldB = "FB"}}; + var comparer = new Comparer(); + + var isEqual = comparer.Compare(a1, a2); + + Assert.IsTrue(isEqual); + } + + [Test] + public void StructPropertyInequality() + { + var a1 = new A {StructProperty = new TestStruct {FieldA = "FA", FieldB = "FB"}}; + var a2 = new A {StructProperty = new TestStruct {FieldA = "FA", FieldB = "FBB"}}; + var comparer = new Comparer(); + + var differences = comparer.CalculateDifferences(a1, a2).ToList(); + + CollectionAssert.IsNotEmpty(differences); + Assert.AreEqual("StructProperty.FieldB", differences.First().MemberPath); + Assert.AreEqual("FB", differences.First().Value1); + Assert.AreEqual("FBB", differences.First().Value2); + } + + [Test] + public void EnumPropertyEquality() + { + var a1 = new A {EnumProperty = TestEnum.Value1}; + var a2 = new A {EnumProperty = TestEnum.Value1}; + var comparer = new Comparer(); + + var isEqual = comparer.Compare(a1, a2); + + Assert.IsTrue(isEqual); + } + + [Test] + public void EnumPropertyInequality() + { + var a1 = new A {EnumProperty = TestEnum.Value1}; + var a2 = new A {EnumProperty = TestEnum.Value2}; + var comparer = new Comparer(); + + var differences = comparer.CalculateDifferences(a1, a2).ToList(); + + CollectionAssert.IsNotEmpty(differences); + Assert.AreEqual("EnumProperty", differences.First().MemberPath); + Assert.AreEqual("Value1", differences.First().Value1); + Assert.AreEqual("Value2", differences.First().Value2); + } + + [Test] + public void SetDefaultComparer() + { + var a1 = new A {TestProperty1 = "ABC", Field = 5}; + var a2 = new A {TestProperty1 = "BCD", Field = 6}; + var comparer = new Comparer(); + var valueComparer = Substitute.For(); + valueComparer.Compare(Arg.Any(), Arg.Any(), Arg.Any()).Returns(true); + comparer.SetDefaultComparer(valueComparer); + + var isEqual = comparer.Compare(a1, a2); + + Assert.IsTrue(isEqual); + valueComparer.Received().Compare(Arg.Any(), Arg.Any(), Arg.Any()); + } + + [Test] + public void SetDefaultComparerNullException() + { + var comparer = new Comparer(); + + Assert.Throws(() => comparer.SetDefaultComparer(null)); + } + + [Test] + public void InheritedAndBaseClassInequality() + { + var a1 = new A {ClassB = new B {Property1 = "Str1"}}; + var a2 = new A {ClassB = new InheritedFromB {Property1 = "Str2", NewProperty = "SomeValue"}}; + var comparer = new Comparer(); + + var isEqual = comparer.Compare(a1, a2, out var differencesEnum); + var differences = differencesEnum.ToList(); + + Assert.IsFalse(isEqual); + CollectionAssert.IsNotEmpty(differences); + Assert.AreEqual(1, differences.Count); + Assert.AreEqual("ClassB.Property1", differences.First().MemberPath); + Assert.AreEqual("Str1", differences.First().Value1); + Assert.AreEqual("Str2", differences.First().Value2); + } + + [Test] + public void InheritedAndBaseClassEquality() + { + var a1 = new A {ClassB = new B {Property1 = "Str1"}}; + var a2 = new A {ClassB = new InheritedFromB {Property1 = "Str1", NewProperty = "SomeValue"}}; + var comparer = new Comparer(); + + var isEqual = comparer.Compare(a1, a2); + + Assert.IsTrue(isEqual); + } + + [TestCase(FlagsEnum.Flag1 | FlagsEnum.Flag2, FlagsEnum.Flag1 | FlagsEnum.Flag3)] + [TestCase(FlagsEnum.Flag2, FlagsEnum.Flag3)] + [TestCase(FlagsEnum.Flag1, FlagsEnum.Flag1 | FlagsEnum.Flag2)] + public void FlagsInequality(FlagsEnum flags1, FlagsEnum flags2) + { + var a1 = new A {Flags = flags1}; + var a2 = new A {Flags = flags2}; + var comparer = new Comparer(); + + var isEqual = comparer.Compare(a1, a2, out var differencesEnum); + var differences = differencesEnum.ToList(); + + Assert.IsFalse(isEqual); + CollectionAssert.IsNotEmpty(differences); + Assert.AreEqual(1, differences.Count); + Assert.AreEqual("Flags", differences.First().MemberPath); + Assert.AreEqual(flags1.ToString(), differences.First().Value1); + Assert.AreEqual(flags2.ToString(), differences.First().Value2); + } + + [TestCase(FlagsEnum.Flag1 | FlagsEnum.Flag2, FlagsEnum.Flag1 | FlagsEnum.Flag2)] + [TestCase(FlagsEnum.Flag2, FlagsEnum.Flag2)] + public void FlagsEquality(FlagsEnum flags1, FlagsEnum flags2) + { + var a1 = new A {Flags = flags1}; + var a2 = new A {Flags = flags2}; + var comparer = new Comparer(); + + var isEqual = comparer.Compare(a1, a2); + + Assert.IsTrue(isEqual); + } + + [Test] + public void TypePropertyEquality() + { + var a1 = new A {TypeProperty = typeof(string)}; + var a2 = new A {TypeProperty = typeof(string)}; + var comparer = new Comparer(); + + var isEqual = comparer.Compare(a1, a2); + + Assert.IsTrue(isEqual); + } + + [Test] + public void TypePropertyInequality() + { + var a1 = new A {TypeProperty = typeof(string)}; + var a2 = new A {TypeProperty = typeof(int)}; + var comparer = new Comparer(); + + var isEqual = comparer.Compare(a1, a2, out var differencesEnum); + var differences = differencesEnum.ToList(); + + Assert.IsFalse(isEqual); + CollectionAssert.IsNotEmpty(differences); + Assert.AreEqual(1, differences.Count); + Assert.AreEqual("TypeProperty", differences.First().MemberPath); + } + + [Test] + public void TimeSpanEquality() + { + var a1 = new TimeSpan(123456789); + var a2 = new TimeSpan(123456789); + var comparer = new Comparer(); + + var isEqual = comparer.Compare(a1, a2); + + Assert.IsTrue(isEqual); + } + + [Test] + public void TimeSpanInequality() + { + var a1 = new TimeSpan(123456789); + var a2 = new TimeSpan(123456788); + var comparer = new Comparer(); + + var isEqual = comparer.Compare(a1, a2, out var differencesEnum); + var differences = differencesEnum.ToList(); + + Assert.IsFalse(isEqual); + CollectionAssert.IsNotEmpty(differences); + Assert.AreEqual(1, differences.Count); + Assert.AreEqual(string.Empty, differences.First().MemberPath); + } + + [Test] + public void GuidEquality() + { + var a1 = new Guid("01234567890123456789012345678912"); + var a2 = new Guid("01234567890123456789012345678912"); + var comparer = new Comparer(); + + var isEqual = comparer.Compare(a1, a2); + + Assert.IsTrue(isEqual); + } + + [Test] + public void GuidInequality() + { + var a1 = new Guid("01234567890123456789012345678912"); + var a2 = new Guid("01234567890123456789012345678913"); + var comparer = new Comparer(); + + var isEqual = comparer.Compare(a1, a2, out var differencesEnum); + var differences = differencesEnum.ToList(); + + Assert.IsFalse(isEqual); + CollectionAssert.IsNotEmpty(differences); + Assert.AreEqual(1, differences.Count); + Assert.AreEqual(string.Empty, differences.First().MemberPath); + } + } +} \ No newline at end of file diff --git a/ObjectsComparer/ObjectsComparer/Comparer~1.cs b/ObjectsComparer/ObjectsComparer/Comparer~1.cs index e248558..cf4b951 100644 --- a/ObjectsComparer/ObjectsComparer/Comparer~1.cs +++ b/ObjectsComparer/ObjectsComparer/Comparer~1.cs @@ -131,7 +131,7 @@ internal IEnumerable CalculateDifferences(T obj1, T obj2, MemberInfo { var objectDataComparer = Factory.GetObjectsComparer(type, Settings, this); - foreach (var failure in objectDataComparer.CalculateDifferences(type, value1, value2)) + foreach (var failure in objectDataComparer.CalculateDifferences(type, value1, value2, ComparisionContext.Create(currentMember: member))) { yield return failure.InsertPath(member.Name); } diff --git a/ObjectsComparer/ObjectsComparer/ComparisionContext.cs b/ObjectsComparer/ObjectsComparer/ComparisionContext.cs new file mode 100644 index 0000000..347d3cf --- /dev/null +++ b/ObjectsComparer/ObjectsComparer/ComparisionContext.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Reflection; + +namespace ObjectsComparer +{ + public class ComparisionContext + { + public static readonly ComparisionContext Undefined = new ComparisionContext(); + + private ComparisionContext() + { + } + + private ComparisionContext(MemberInfo currentMember) + { + CurrentMember = currentMember ?? throw new ArgumentNullException(nameof(currentMember)); + } + + public readonly MemberInfo CurrentMember; + + public static ComparisionContext Create(MemberInfo currentMember) + { + return new ComparisionContext(currentMember); + } + } +} \ No newline at end of file diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs index 11871cd..83fbad5 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs @@ -7,7 +7,7 @@ namespace ObjectsComparer { - internal class EnumerablesComparer : AbstractComparer, IComparerWithCondition + internal class EnumerablesComparer : AbstractComparer, IComparerWithCondition, IContextableComparer { public EnumerablesComparer(ComparisonSettings settings, BaseComparer parentComparer, IComparersFactory factory) : base(settings, parentComparer, factory) @@ -15,6 +15,11 @@ public EnumerablesComparer(ComparisonSettings settings, BaseComparer parentCompa } public override IEnumerable CalculateDifferences(Type type, object obj1, object obj2) + { + return CalculateDifferences(type, obj1, obj2, ComparisionContext.Undefined); + } + + public IEnumerable CalculateDifferences(Type type, object obj1, object obj2, ComparisionContext comparisionContext) { if (!Settings.EmptyAndNullEnumerablesEqual && (obj1 == null || obj2 == null) && obj1 != obj2) @@ -46,7 +51,7 @@ public override IEnumerable CalculateDifferences(Type type, object o if (array1.Length != array2.Length) { - yield return new Difference("", array1.Length.ToString(), array2.Length.ToString(), + yield return new Difference("", array1.Length.ToString(), array2.Length.ToString(), DifferenceTypes.NumberOfElementsMismatch); yield break; } @@ -88,6 +93,8 @@ public override IEnumerable CalculateDifferences(Type type, object o } } + + public bool IsMatch(Type type, object obj1, object obj2) { return type.InheritsFrom(typeof(IEnumerable)) && !type.InheritsFrom(typeof(IEnumerable<>)); diff --git a/ObjectsComparer/ObjectsComparer/IComparableExtensions.cs b/ObjectsComparer/ObjectsComparer/IComparableExtensions.cs new file mode 100644 index 0000000..de8310a --- /dev/null +++ b/ObjectsComparer/ObjectsComparer/IComparableExtensions.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; + +namespace ObjectsComparer +{ + public static class IComparableExtensions + { + public static IEnumerable CalculateDifferences(this IComparer comparer, Type type, object obj1, object obj2, ComparisionContext comparisionContext) + { + if (comparer is IContextableComparer contextableComparer) + { + return contextableComparer.CalculateDifferences(type, obj1, obj2, comparisionContext); + } + + return comparer.CalculateDifferences(type, obj1, obj2); + } + } + + +} \ No newline at end of file diff --git a/ObjectsComparer/ObjectsComparer/IContextableComparer.cs b/ObjectsComparer/ObjectsComparer/IContextableComparer.cs new file mode 100644 index 0000000..e96f160 --- /dev/null +++ b/ObjectsComparer/ObjectsComparer/IContextableComparer.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; + +namespace ObjectsComparer +{ + public interface IContextableComparer + { + IEnumerable CalculateDifferences(Type type, object obj1, object obj2, ComparisionContext comparisionContext); + } + + +} \ No newline at end of file From ae9e6826f0043cba5327cf0f7cb9d9b5a024190d Mon Sep 17 00:00:00 2001 From: nemec Date: Mon, 2 Aug 2021 00:34:58 +0200 Subject: [PATCH 002/181] Implement IContextableComparer to Comparer class. Add ComparisionContext, IContextableComparer, IComparableExtensions. Extend CalculateDifferences operation with current comparision context. --- .../ObjectsComparer.Tests/DaNComparerTests.cs | 523 ++++++++++++++++++ ObjectsComparer/ObjectsComparer/Comparer.cs | 37 +- ObjectsComparer/ObjectsComparer/Comparer~1.cs | 12 +- .../ObjectsComparer/ComparisionContext.cs | 35 ++ .../CustomComparers/EnumerablesComparer.cs | 11 +- .../ObjectsComparer/IComparableExtensions.cs | 20 + .../ObjectsComparer/IComparisionContext.cs | 12 + .../ObjectsComparer/IContextableComparer.cs | 13 + .../ObjectsComparer/IContextableComparer~1.cs | 13 + 9 files changed, 657 insertions(+), 19 deletions(-) create mode 100644 ObjectsComparer/ObjectsComparer.Tests/DaNComparerTests.cs create mode 100644 ObjectsComparer/ObjectsComparer/ComparisionContext.cs create mode 100644 ObjectsComparer/ObjectsComparer/IComparableExtensions.cs create mode 100644 ObjectsComparer/ObjectsComparer/IComparisionContext.cs create mode 100644 ObjectsComparer/ObjectsComparer/IContextableComparer.cs create mode 100644 ObjectsComparer/ObjectsComparer/IContextableComparer~1.cs diff --git a/ObjectsComparer/ObjectsComparer.Tests/DaNComparerTests.cs b/ObjectsComparer/ObjectsComparer.Tests/DaNComparerTests.cs new file mode 100644 index 0000000..675dcb7 --- /dev/null +++ b/ObjectsComparer/ObjectsComparer.Tests/DaNComparerTests.cs @@ -0,0 +1,523 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using NSubstitute; +using NUnit.Framework; +using ObjectsComparer.Tests.TestClasses; + +namespace ObjectsComparer.Tests +{ + public class Driver + { + + } + + public class Car + { + //public IEnumerable Items1 { get; set; } + + //public IEnumerable Items2 { get; set; } + + public string[] Items3 { get; set; } + } + + [TestFixture] + public class DaNComparerTests + { + [Test] + public void TestEnumerablesComparer() + { + var car1 = new Car(); + //car1.Items1 = new int[] { 1, 2, 3 }; + //car1.Items2 = new List { "ahoj", "nazdar", "čau" }; + car1.Items3 = new string[] { "ahoj", "nazdar", "čau" }; + var car2 = new Car(); + //car2.Items1 = new int[] { -1, 2, 3 }; + //car2.Items2 = new List { "ahoj", "hello", "čau" }; + car2.Items3 = new string[] { "hi", "nazdar", "čau" }; + //var comparer = new Comparer(); + var comparer = new Comparer(); + //var diffs = comparer.CalculateDifferences(typeof(Car), car1, car2).ToArray(); + var diffs = comparer.CalculateDifferences(car1, car2).ToArray(); + //var member = car1.GetType().GetMember(nameof(car1.Items1)).Single(); + } + + public class SubClassA + { + public bool BoolProperty { get; set; } + } + + [Test] + public void TestBug() + { + var comparer = new Comparer(); + } + + [Test] + public void PropertyEquality() + { + var a1 = new A {IntProperty = 10, DateTimeProperty = new DateTime(2017, 1, 1), Property3 = 5}; + var a2 = new A {IntProperty = 10, DateTimeProperty = new DateTime(2017, 1, 1), Property3 = 8}; + var comparer = new Comparer(); + + var isEqual = comparer.Compare(a1, a2); + + Assert.IsTrue(isEqual); + } + + [Test] + public void PropertyInequality() + { + var date1 = new DateTime(2017, 1, 1); + var date2 = new DateTime(2017, 1, 2); + var a1 = new A {IntProperty = 10, DateTimeProperty = date1}; + var a2 = new A {IntProperty = 8, DateTimeProperty = date2}; + var comparer = new Comparer(); + + var differences = comparer.CalculateDifferences(a1, a2).ToList(); + + CollectionAssert.IsNotEmpty(differences); + Assert.AreEqual("IntProperty", differences[0].MemberPath); + Assert.AreEqual("10", differences[0].Value1); + Assert.AreEqual("8", differences[0].Value2); + Assert.AreEqual("DateTimeProperty", differences[1].MemberPath); + // ReSharper disable once SpecifyACultureInStringConversionExplicitly + Assert.AreEqual(date1.ToString(), differences[1].Value1); + // ReSharper disable once SpecifyACultureInStringConversionExplicitly + Assert.AreEqual(date2.ToString(), differences[1].Value2); + } + + [Test] + public void ReadOnlyPropertyEquality() + { + var a1 = new A(1.99); + var a2 = new A(1.99); + var comparer = new Comparer(); + + var isEqual = comparer.Compare(a1, a2); + + Assert.IsTrue(isEqual); + } + + [Test] + public void ReadOnlyPropertyInequality() + { + var a1 = new A(1.99); + var a2 = new A(0.89); + var comparer = new Comparer(); + + var differences = comparer.CalculateDifferences(a1, a2).ToList(); + + CollectionAssert.IsNotEmpty(differences); + Assert.AreEqual("ReadOnlyProperty", differences.First().MemberPath); + Assert.AreEqual("1.99", differences.First().Value1); + Assert.AreEqual("0.89", differences.First().Value2); + } + + [Test] + public void ProtectedProperty() + { + var a1 = new A(true); + var a2 = new A(false); + var comparer = new Comparer(); + + var isEqual = comparer.Compare(a1, a2); + + Assert.IsTrue(isEqual); + } + + [Test] + public void FieldEquality() + { + var a1 = new A {Field = 9}; + var a2 = new A {Field = 9}; + var comparer = new Comparer(); + + var isEqual = comparer.Compare(a1, a2); + + Assert.IsTrue(isEqual); + } + + [Test] + public void FieldInequality() + { + var a1 = new A {Field = 10}; + var a2 = new A {Field = 8}; + var comparer = new Comparer(); + + var differences = comparer.CalculateDifferences(a1, a2).ToList(); + + CollectionAssert.IsNotEmpty(differences); + Assert.AreEqual("Field", differences.First().MemberPath); + Assert.AreEqual("10", differences.First().Value1); + Assert.AreEqual("8", differences.First().Value2); + } + + [Test] + public void ReadOnlyFieldEquality() + { + var a1 = new A("Str1"); + var a2 = new A("Str1"); + var comparer = new Comparer(); + + var isEqual = comparer.Compare(a1, a2); + + Assert.IsTrue(isEqual); + } + + [Test] + public void ReadOnlyFieldInequality() + { + var a1 = new A("Str1"); + var a2 = new A("Str2"); + var comparer = new Comparer(); + + var differences = comparer.CalculateDifferences(a1, a2).ToList(); + + CollectionAssert.IsNotEmpty(differences); + Assert.AreEqual("ReadOnlyField", differences.First().MemberPath); + Assert.AreEqual("Str1", differences.First().Value1); + Assert.AreEqual("Str2", differences.First().Value2); + } + + [Test] + public void ProtectedField() + { + var a1 = new A(5); + var a2 = new A(6); + var comparer = new Comparer(); + + var isEqual = comparer.Compare(a1, a2); + + Assert.IsTrue(isEqual); + } + + [Test] + public void ClassPropertyEquality() + { + var a1 = new A {ClassB = new B {Property1 = "Str1"}}; + var a2 = new A {ClassB = new B {Property1 = "Str1"}}; + var comparer = new Comparer(); + + var isEqual = comparer.Compare(a1, a2); + + Assert.IsTrue(isEqual); + } + + [Test] + public void ClassPropertyInequality() + { + var a1 = new A {ClassB = new B {Property1 = "Str1"}}; + var a2 = new A {ClassB = new B {Property1 = "Str2"}}; + var comparer = new Comparer(); + + var differences = comparer.CalculateDifferences(a1, a2).ToList(); + + CollectionAssert.IsNotEmpty(differences); + Assert.AreEqual("ClassB.Property1", differences.First().MemberPath); + Assert.AreEqual("Str1", differences.First().Value1); + Assert.AreEqual("Str2", differences.First().Value2); + } + + [Test] + public void ClassPropertyInequalityFirstNull() + { + var a1 = new A(); + var a2 = new A {ClassB = new B {Property1 = "Str2"}}; + var comparer = new Comparer(); + + var differences = comparer.CalculateDifferences(a1, a2).ToList(); + + CollectionAssert.IsNotEmpty(differences); + Assert.AreEqual("ClassB", differences.First().MemberPath); + Assert.AreEqual("", differences.First().Value1); + Assert.AreEqual(a2.ClassB.ToString(), differences.First().Value2); + } + + [Test] + public void ClassPropertyInequalitySecondNull() + { + var a1 = new A {ClassB = new B {Property1 = "Str2"}}; + var a2 = new A(); + var comparer = new Comparer(); + + var differences = comparer.CalculateDifferences(a1, a2).ToList(); + + CollectionAssert.IsNotEmpty(differences); + Assert.AreEqual("ClassB", differences.First().MemberPath); + Assert.AreEqual(a1.ClassB.ToString(), differences.First().Value1); + Assert.AreEqual("", differences.First().Value2); + } + + [Test] + public void NoRecursiveComparison() + { + var a1 = new A {ClassB = new B {Property1 = "Str1"}}; + var a2 = new A {ClassB = new B {Property1 = "Str2"}}; + var comparer = new Comparer(new ComparisonSettings {RecursiveComparison = false}); + + var isEqual = comparer.Compare(a1, a2); + + Assert.IsTrue(isEqual); + } + + [Test] + public void InterfacePropertyEquality() + { + var a1 = new A {IntefaceProperty = new TestInterfaceImplementation1 {Property = "Str1"}}; + var a2 = new A + { + IntefaceProperty = new TestInterfaceImplementation2 {Property = "Str1", AnotherProperty = 50} + }; + var comparer = new Comparer(); + + var isEqual = comparer.Compare(a1, a2); + + Assert.IsTrue(isEqual); + } + + [Test] + public void InterfacePropertyInequality() + { + var a1 = new A {IntefaceProperty = new TestInterfaceImplementation1 {Property = "Str1"}}; + var a2 = new A + { + IntefaceProperty = new TestInterfaceImplementation2 {Property = "Str2", AnotherProperty = 50} + }; + var comparer = new Comparer(); + + var differences = comparer.CalculateDifferences(a1, a2).ToList(); + + CollectionAssert.IsNotEmpty(differences); + Assert.AreEqual("IntefaceProperty.Property", differences.First().MemberPath); + Assert.AreEqual("Str1", differences.First().Value1); + Assert.AreEqual("Str2", differences.First().Value2); + } + + [Test] + public void StructPropertyEquality() + { + var a1 = new A {StructProperty = new TestStruct {FieldA = "FA", FieldB = "FB"}}; + var a2 = new A {StructProperty = new TestStruct {FieldA = "FA", FieldB = "FB"}}; + var comparer = new Comparer(); + + var isEqual = comparer.Compare(a1, a2); + + Assert.IsTrue(isEqual); + } + + [Test] + public void StructPropertyInequality() + { + var a1 = new A {StructProperty = new TestStruct {FieldA = "FA", FieldB = "FB"}}; + var a2 = new A {StructProperty = new TestStruct {FieldA = "FA", FieldB = "FBB"}}; + var comparer = new Comparer(); + + var differences = comparer.CalculateDifferences(a1, a2).ToList(); + + CollectionAssert.IsNotEmpty(differences); + Assert.AreEqual("StructProperty.FieldB", differences.First().MemberPath); + Assert.AreEqual("FB", differences.First().Value1); + Assert.AreEqual("FBB", differences.First().Value2); + } + + [Test] + public void EnumPropertyEquality() + { + var a1 = new A {EnumProperty = TestEnum.Value1}; + var a2 = new A {EnumProperty = TestEnum.Value1}; + var comparer = new Comparer(); + + var isEqual = comparer.Compare(a1, a2); + + Assert.IsTrue(isEqual); + } + + [Test] + public void EnumPropertyInequality() + { + var a1 = new A {EnumProperty = TestEnum.Value1}; + var a2 = new A {EnumProperty = TestEnum.Value2}; + var comparer = new Comparer(); + + var differences = comparer.CalculateDifferences(a1, a2).ToList(); + + CollectionAssert.IsNotEmpty(differences); + Assert.AreEqual("EnumProperty", differences.First().MemberPath); + Assert.AreEqual("Value1", differences.First().Value1); + Assert.AreEqual("Value2", differences.First().Value2); + } + + [Test] + public void SetDefaultComparer() + { + var a1 = new A {TestProperty1 = "ABC", Field = 5}; + var a2 = new A {TestProperty1 = "BCD", Field = 6}; + var comparer = new Comparer(); + var valueComparer = Substitute.For(); + valueComparer.Compare(Arg.Any(), Arg.Any(), Arg.Any()).Returns(true); + comparer.SetDefaultComparer(valueComparer); + + var isEqual = comparer.Compare(a1, a2); + + Assert.IsTrue(isEqual); + valueComparer.Received().Compare(Arg.Any(), Arg.Any(), Arg.Any()); + } + + [Test] + public void SetDefaultComparerNullException() + { + var comparer = new Comparer(); + + Assert.Throws(() => comparer.SetDefaultComparer(null)); + } + + [Test] + public void InheritedAndBaseClassInequality() + { + var a1 = new A {ClassB = new B {Property1 = "Str1"}}; + var a2 = new A {ClassB = new InheritedFromB {Property1 = "Str2", NewProperty = "SomeValue"}}; + var comparer = new Comparer(); + + var isEqual = comparer.Compare(a1, a2, out var differencesEnum); + var differences = differencesEnum.ToList(); + + Assert.IsFalse(isEqual); + CollectionAssert.IsNotEmpty(differences); + Assert.AreEqual(1, differences.Count); + Assert.AreEqual("ClassB.Property1", differences.First().MemberPath); + Assert.AreEqual("Str1", differences.First().Value1); + Assert.AreEqual("Str2", differences.First().Value2); + } + + [Test] + public void InheritedAndBaseClassEquality() + { + var a1 = new A {ClassB = new B {Property1 = "Str1"}}; + var a2 = new A {ClassB = new InheritedFromB {Property1 = "Str1", NewProperty = "SomeValue"}}; + var comparer = new Comparer(); + + var isEqual = comparer.Compare(a1, a2); + + Assert.IsTrue(isEqual); + } + + [TestCase(FlagsEnum.Flag1 | FlagsEnum.Flag2, FlagsEnum.Flag1 | FlagsEnum.Flag3)] + [TestCase(FlagsEnum.Flag2, FlagsEnum.Flag3)] + [TestCase(FlagsEnum.Flag1, FlagsEnum.Flag1 | FlagsEnum.Flag2)] + public void FlagsInequality(FlagsEnum flags1, FlagsEnum flags2) + { + var a1 = new A {Flags = flags1}; + var a2 = new A {Flags = flags2}; + var comparer = new Comparer(); + + var isEqual = comparer.Compare(a1, a2, out var differencesEnum); + var differences = differencesEnum.ToList(); + + Assert.IsFalse(isEqual); + CollectionAssert.IsNotEmpty(differences); + Assert.AreEqual(1, differences.Count); + Assert.AreEqual("Flags", differences.First().MemberPath); + Assert.AreEqual(flags1.ToString(), differences.First().Value1); + Assert.AreEqual(flags2.ToString(), differences.First().Value2); + } + + [TestCase(FlagsEnum.Flag1 | FlagsEnum.Flag2, FlagsEnum.Flag1 | FlagsEnum.Flag2)] + [TestCase(FlagsEnum.Flag2, FlagsEnum.Flag2)] + public void FlagsEquality(FlagsEnum flags1, FlagsEnum flags2) + { + var a1 = new A {Flags = flags1}; + var a2 = new A {Flags = flags2}; + var comparer = new Comparer(); + + var isEqual = comparer.Compare(a1, a2); + + Assert.IsTrue(isEqual); + } + + [Test] + public void TypePropertyEquality() + { + var a1 = new A {TypeProperty = typeof(string)}; + var a2 = new A {TypeProperty = typeof(string)}; + var comparer = new Comparer(); + + var isEqual = comparer.Compare(a1, a2); + + Assert.IsTrue(isEqual); + } + + [Test] + public void TypePropertyInequality() + { + var a1 = new A {TypeProperty = typeof(string)}; + var a2 = new A {TypeProperty = typeof(int)}; + var comparer = new Comparer(); + + var isEqual = comparer.Compare(a1, a2, out var differencesEnum); + var differences = differencesEnum.ToList(); + + Assert.IsFalse(isEqual); + CollectionAssert.IsNotEmpty(differences); + Assert.AreEqual(1, differences.Count); + Assert.AreEqual("TypeProperty", differences.First().MemberPath); + } + + [Test] + public void TimeSpanEquality() + { + var a1 = new TimeSpan(123456789); + var a2 = new TimeSpan(123456789); + var comparer = new Comparer(); + + var isEqual = comparer.Compare(a1, a2); + + Assert.IsTrue(isEqual); + } + + [Test] + public void TimeSpanInequality() + { + var a1 = new TimeSpan(123456789); + var a2 = new TimeSpan(123456788); + var comparer = new Comparer(); + + var isEqual = comparer.Compare(a1, a2, out var differencesEnum); + var differences = differencesEnum.ToList(); + + Assert.IsFalse(isEqual); + CollectionAssert.IsNotEmpty(differences); + Assert.AreEqual(1, differences.Count); + Assert.AreEqual(string.Empty, differences.First().MemberPath); + } + + [Test] + public void GuidEquality() + { + var a1 = new Guid("01234567890123456789012345678912"); + var a2 = new Guid("01234567890123456789012345678912"); + var comparer = new Comparer(); + + var isEqual = comparer.Compare(a1, a2); + + Assert.IsTrue(isEqual); + } + + [Test] + public void GuidInequality() + { + var a1 = new Guid("01234567890123456789012345678912"); + var a2 = new Guid("01234567890123456789012345678913"); + var comparer = new Comparer(); + + var isEqual = comparer.Compare(a1, a2, out var differencesEnum); + var differences = differencesEnum.ToList(); + + Assert.IsFalse(isEqual); + CollectionAssert.IsNotEmpty(differences); + Assert.AreEqual(1, differences.Count); + Assert.AreEqual(string.Empty, differences.First().MemberPath); + } + } +} \ No newline at end of file diff --git a/ObjectsComparer/ObjectsComparer/Comparer.cs b/ObjectsComparer/ObjectsComparer/Comparer.cs index 7b2684f..0ee3766 100644 --- a/ObjectsComparer/ObjectsComparer/Comparer.cs +++ b/ObjectsComparer/ObjectsComparer/Comparer.cs @@ -9,7 +9,7 @@ namespace ObjectsComparer /// /// Compares objects. /// - public class Comparer : AbstractComparer + public class Comparer : AbstractComparer, IContextableComparer { private static string CalculateDifferencesMethodName { @@ -27,23 +27,32 @@ public Comparer(ComparisonSettings settings = null, BaseComparer parentComparer { } - /// - /// Calculates list of differences between objects. - /// - /// Type. - /// Object 1. - /// Object 2. - /// List of differences between objects. public override IEnumerable CalculateDifferences(Type type, object obj1, object obj2) { - var objectsComparerMethod = typeof(IComparersFactory).GetTypeInfo().GetMethods().First(m => m.IsGenericMethod); - var objectsComparerGenericMethod = objectsComparerMethod.MakeGenericMethod(type); - var comparer = objectsComparerGenericMethod.Invoke(Factory, new object[] { Settings, this }); - var genericType = typeof(IComparer<>).MakeGenericType(type); - var method = genericType.GetTypeInfo().GetMethod(CalculateDifferencesMethodName, new[] { type, type }); + return CalculateDifferences(type, obj1, obj2, ComparisionContext.Undefined); + } + + public IEnumerable CalculateDifferences(Type type, object obj1, object obj2, IComparisionContext comparisionContext) + { + if (comparisionContext is null) + { + throw new ArgumentNullException(nameof(comparisionContext)); + } + + var getObjectsComparerMethod = typeof(IComparersFactory).GetTypeInfo().GetMethods().First(m => m.IsGenericMethod); + var getObjectsComparerGenericMethod = getObjectsComparerMethod.MakeGenericMethod(type); + var comparer = getObjectsComparerGenericMethod.Invoke(Factory, new object[] { Settings, this }); + + bool comparerIsContextableComparer = comparer.GetType().GetTypeInfo().GetInterfaces() + .Any(intft => intft.GetTypeInfo().IsGenericType && intft.GetGenericTypeDefinition() == typeof(IContextableComparer<>)); + + var genericType = comparerIsContextableComparer ? typeof(IContextableComparer<>).MakeGenericType(type) : typeof(IComparer<>).MakeGenericType(type); + var genericMethodParameterTypes = comparerIsContextableComparer ? new[] { type, type, typeof(ComparisionContext) } : new[] { type, type }; + var genericMethod = genericType.GetTypeInfo().GetMethod(CalculateDifferencesMethodName, genericMethodParameterTypes); + var genericMethodParameters = comparerIsContextableComparer ? new[] { obj1, obj2, comparisionContext } : new[] { obj1, obj2 }; // ReSharper disable once PossibleNullReferenceException - return (IEnumerable)method.Invoke(comparer, new[] { obj1, obj2 }); + return (IEnumerable)genericMethod.Invoke(comparer, genericMethodParameters); } } } diff --git a/ObjectsComparer/ObjectsComparer/Comparer~1.cs b/ObjectsComparer/ObjectsComparer/Comparer~1.cs index e248558..358fd78 100644 --- a/ObjectsComparer/ObjectsComparer/Comparer~1.cs +++ b/ObjectsComparer/ObjectsComparer/Comparer~1.cs @@ -10,7 +10,7 @@ namespace ObjectsComparer /// /// Compares objects of type . /// - public class Comparer : AbstractComparer + public class Comparer : AbstractComparer, IContextableComparer { private readonly List _members; private readonly List _conditionalComparers; @@ -53,7 +53,13 @@ public Comparer(ComparisonSettings settings = null, BaseComparer parentComparer /// List of differences between objects. public override IEnumerable CalculateDifferences(T obj1, T obj2) { - return CalculateDifferences(obj1, obj2, null); + return CalculateDifferences(obj1, obj2, (MemberInfo)null); + } + + public IEnumerable CalculateDifferences(T obj1, T obj2, IComparisionContext comparisionContext) + { + //throw new NotImplementedException(); + return CalculateDifferences(obj1, obj2, (MemberInfo)null); } internal IEnumerable CalculateDifferences(T obj1, T obj2, MemberInfo memberInfo) @@ -131,7 +137,7 @@ internal IEnumerable CalculateDifferences(T obj1, T obj2, MemberInfo { var objectDataComparer = Factory.GetObjectsComparer(type, Settings, this); - foreach (var failure in objectDataComparer.CalculateDifferences(type, value1, value2)) + foreach (var failure in objectDataComparer.CalculateDifferences(type, value1, value2, ComparisionContext.Create(currentMember: member))) { yield return failure.InsertPath(member.Name); } diff --git a/ObjectsComparer/ObjectsComparer/ComparisionContext.cs b/ObjectsComparer/ObjectsComparer/ComparisionContext.cs new file mode 100644 index 0000000..f74bc40 --- /dev/null +++ b/ObjectsComparer/ObjectsComparer/ComparisionContext.cs @@ -0,0 +1,35 @@ +using System; +using System.Collections.Generic; +using System.Reflection; + +namespace ObjectsComparer +{ + public sealed class ComparisionContext : IComparisionContext + { + public static readonly IComparisionContext Undefined = new ComparisionContext(); + + private ComparisionContext() + { + } + + private ComparisionContext(MemberInfo currentMember) + { + Member = currentMember ?? throw new ArgumentNullException(nameof(currentMember)); + } + + /// + /// + /// + public MemberInfo Member { get; } + + public static IComparisionContext Create(MemberInfo currentMember) + { + if (currentMember is null) + { + throw new ArgumentNullException(nameof(currentMember)); + } + + return new ComparisionContext(currentMember); + } + } +} \ No newline at end of file diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs index 11871cd..c2d8f30 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs @@ -7,7 +7,7 @@ namespace ObjectsComparer { - internal class EnumerablesComparer : AbstractComparer, IComparerWithCondition + internal class EnumerablesComparer : AbstractComparer, IComparerWithCondition, IContextableComparer { public EnumerablesComparer(ComparisonSettings settings, BaseComparer parentComparer, IComparersFactory factory) : base(settings, parentComparer, factory) @@ -15,6 +15,11 @@ public EnumerablesComparer(ComparisonSettings settings, BaseComparer parentCompa } public override IEnumerable CalculateDifferences(Type type, object obj1, object obj2) + { + return CalculateDifferences(type, obj1, obj2, ComparisionContext.Undefined); + } + + public IEnumerable CalculateDifferences(Type type, object obj1, object obj2, IComparisionContext comparisionContext) { if (!Settings.EmptyAndNullEnumerablesEqual && (obj1 == null || obj2 == null) && obj1 != obj2) @@ -46,7 +51,7 @@ public override IEnumerable CalculateDifferences(Type type, object o if (array1.Length != array2.Length) { - yield return new Difference("", array1.Length.ToString(), array2.Length.ToString(), + yield return new Difference("", array1.Length.ToString(), array2.Length.ToString(), DifferenceTypes.NumberOfElementsMismatch); yield break; } @@ -88,6 +93,8 @@ public override IEnumerable CalculateDifferences(Type type, object o } } + + public bool IsMatch(Type type, object obj1, object obj2) { return type.InheritsFrom(typeof(IEnumerable)) && !type.InheritsFrom(typeof(IEnumerable<>)); diff --git a/ObjectsComparer/ObjectsComparer/IComparableExtensions.cs b/ObjectsComparer/ObjectsComparer/IComparableExtensions.cs new file mode 100644 index 0000000..8c37666 --- /dev/null +++ b/ObjectsComparer/ObjectsComparer/IComparableExtensions.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; + +namespace ObjectsComparer +{ + public static class IComparableExtensions + { + public static IEnumerable CalculateDifferences(this IComparer comparer, Type type, object obj1, object obj2, IComparisionContext currentContext) + { + if (comparer is IContextableComparer contextableComparer) + { + return contextableComparer.CalculateDifferences(type, obj1, obj2, currentContext); + } + + return comparer.CalculateDifferences(type, obj1, obj2); + } + } + + +} \ No newline at end of file diff --git a/ObjectsComparer/ObjectsComparer/IComparisionContext.cs b/ObjectsComparer/ObjectsComparer/IComparisionContext.cs new file mode 100644 index 0000000..d93f38f --- /dev/null +++ b/ObjectsComparer/ObjectsComparer/IComparisionContext.cs @@ -0,0 +1,12 @@ +using System.Reflection; + +namespace ObjectsComparer +{ + /// + /// Represents the current context of the comparison. + /// + public interface IComparisionContext + { + MemberInfo Member { get; } + } +} \ No newline at end of file diff --git a/ObjectsComparer/ObjectsComparer/IContextableComparer.cs b/ObjectsComparer/ObjectsComparer/IContextableComparer.cs new file mode 100644 index 0000000..c6807c5 --- /dev/null +++ b/ObjectsComparer/ObjectsComparer/IContextableComparer.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; + +namespace ObjectsComparer +{ + /// + /// Comparer that accept comparison context. + /// + public interface IContextableComparer + { + IEnumerable CalculateDifferences(Type type, object obj1, object obj2, IComparisionContext comparisionContext); + } +} \ No newline at end of file diff --git a/ObjectsComparer/ObjectsComparer/IContextableComparer~1.cs b/ObjectsComparer/ObjectsComparer/IContextableComparer~1.cs new file mode 100644 index 0000000..adb87e6 --- /dev/null +++ b/ObjectsComparer/ObjectsComparer/IContextableComparer~1.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; + +namespace ObjectsComparer +{ + /// + /// Generic comparer that accept comparison context. + /// + public interface IContextableComparer + { + IEnumerable CalculateDifferences(T obj1, T obj2, IComparisionContext comparisionContext); + } +} From ff99c57c4d1ff95e74cdd7050851588d14fa42e5 Mon Sep 17 00:00:00 2001 From: nemec Date: Wed, 4 Aug 2021 23:39:26 +0200 Subject: [PATCH 003/181] Rename comparerIsContextableComparer. --- ObjectsComparer/ObjectsComparer/Comparer.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ObjectsComparer/ObjectsComparer/Comparer.cs b/ObjectsComparer/ObjectsComparer/Comparer.cs index 0ee3766..0acbf82 100644 --- a/ObjectsComparer/ObjectsComparer/Comparer.cs +++ b/ObjectsComparer/ObjectsComparer/Comparer.cs @@ -43,13 +43,13 @@ public IEnumerable CalculateDifferences(Type type, object obj1, obje var getObjectsComparerGenericMethod = getObjectsComparerMethod.MakeGenericMethod(type); var comparer = getObjectsComparerGenericMethod.Invoke(Factory, new object[] { Settings, this }); - bool comparerIsContextableComparer = comparer.GetType().GetTypeInfo().GetInterfaces() + bool comparerIsContextable = comparer.GetType().GetTypeInfo().GetInterfaces() .Any(intft => intft.GetTypeInfo().IsGenericType && intft.GetGenericTypeDefinition() == typeof(IContextableComparer<>)); - var genericType = comparerIsContextableComparer ? typeof(IContextableComparer<>).MakeGenericType(type) : typeof(IComparer<>).MakeGenericType(type); - var genericMethodParameterTypes = comparerIsContextableComparer ? new[] { type, type, typeof(ComparisionContext) } : new[] { type, type }; + var genericType = comparerIsContextable ? typeof(IContextableComparer<>).MakeGenericType(type) : typeof(IComparer<>).MakeGenericType(type); + var genericMethodParameterTypes = comparerIsContextable ? new[] { type, type, typeof(ComparisionContext) } : new[] { type, type }; var genericMethod = genericType.GetTypeInfo().GetMethod(CalculateDifferencesMethodName, genericMethodParameterTypes); - var genericMethodParameters = comparerIsContextableComparer ? new[] { obj1, obj2, comparisionContext } : new[] { obj1, obj2 }; + var genericMethodParameters = comparerIsContextable ? new[] { obj1, obj2, comparisionContext } : new[] { obj1, obj2 }; // ReSharper disable once PossibleNullReferenceException return (IEnumerable)genericMethod.Invoke(comparer, genericMethodParameters); From dfd7b18510deb93832de930b7e69609215005d86 Mon Sep 17 00:00:00 2001 From: nemec Date: Thu, 5 Aug 2021 00:32:24 +0200 Subject: [PATCH 004/181] Implement IContextableComparer into: EnumerablesComparer, EnumerablesComparer, Comparer. --- ObjectsComparer/ObjectsComparer/Comparer~1.cs | 14 ++++++++++---- .../CustomComparers/EnumerablesComparer.cs | 9 ++++++--- .../CustomComparers/EnumerablesComparer~1.cs | 14 ++++++++++++-- .../ObjectsComparer/IComparableExtensions.cs | 4 ++-- 4 files changed, 30 insertions(+), 11 deletions(-) diff --git a/ObjectsComparer/ObjectsComparer/Comparer~1.cs b/ObjectsComparer/ObjectsComparer/Comparer~1.cs index 358fd78..70a0032 100644 --- a/ObjectsComparer/ObjectsComparer/Comparer~1.cs +++ b/ObjectsComparer/ObjectsComparer/Comparer~1.cs @@ -53,16 +53,20 @@ public Comparer(ComparisonSettings settings = null, BaseComparer parentComparer /// List of differences between objects. public override IEnumerable CalculateDifferences(T obj1, T obj2) { - return CalculateDifferences(obj1, obj2, (MemberInfo)null); + return CalculateDifferences(obj1, obj2, memberInfo: null); } public IEnumerable CalculateDifferences(T obj1, T obj2, IComparisionContext comparisionContext) { - //throw new NotImplementedException(); - return CalculateDifferences(obj1, obj2, (MemberInfo)null); + return CalculateDifferences(obj1, obj2, memberInfo: null, comparisionContext); } internal IEnumerable CalculateDifferences(T obj1, T obj2, MemberInfo memberInfo) + { + return CalculateDifferences(obj1, obj2, memberInfo, ComparisionContext.Undefined); + } + + IEnumerable CalculateDifferences(T obj1, T obj2, MemberInfo memberInfo, IComparisionContext comparisionContext) { var comparer = memberInfo != null ? OverridesCollection.GetComparer(memberInfo) @@ -85,7 +89,7 @@ internal IEnumerable CalculateDifferences(T obj1, T obj2, MemberInfo var conditionalComparer = _conditionalComparers.FirstOrDefault(c => c.IsMatch(typeof(T), obj1, obj2)); if (conditionalComparer != null) { - foreach (var difference in conditionalComparer.CalculateDifferences(typeof(T), obj1, obj2)) + foreach (var difference in conditionalComparer.CalculateDifferences(typeof(T), obj1, obj2, comparisionContext)) { yield return difference; } @@ -179,5 +183,7 @@ private List GetProperties(Type type, List processedTypes) return properties; } + + } } diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs index c2d8f30..e7fc34a 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs @@ -21,13 +21,18 @@ public override IEnumerable CalculateDifferences(Type type, object o public IEnumerable CalculateDifferences(Type type, object obj1, object obj2, IComparisionContext comparisionContext) { + if (comparisionContext is null) + { + throw new ArgumentNullException(nameof(comparisionContext)); + } + if (!Settings.EmptyAndNullEnumerablesEqual && (obj1 == null || obj2 == null) && obj1 != obj2) { yield return new Difference("[]", obj1?.ToString() ?? string.Empty, obj2?.ToString() ?? string.Empty); yield break; } - + obj1 = obj1 ?? Enumerable.Empty(); obj2 = obj2 ?? Enumerable.Empty(); @@ -93,8 +98,6 @@ public IEnumerable CalculateDifferences(Type type, object obj1, obje } } - - public bool IsMatch(Type type, object obj1, object obj2) { return type.InheritsFrom(typeof(IEnumerable)) && !type.InheritsFrom(typeof(IEnumerable<>)); diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer~1.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer~1.cs index 3f32656..b85779a 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer~1.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer~1.cs @@ -6,7 +6,7 @@ namespace ObjectsComparer { - internal class EnumerablesComparer : AbstractComparer + internal class EnumerablesComparer : AbstractComparer, IContextableComparer { private readonly IComparer _comparer; @@ -18,6 +18,16 @@ public EnumerablesComparer(ComparisonSettings settings, BaseComparer parentCompa public override IEnumerable CalculateDifferences(Type type, object obj1, object obj2) { + return CalculateDifferences(type, obj1, obj2, ComparisionContext.Undefined); + } + + public IEnumerable CalculateDifferences(Type type, object obj1, object obj2, IComparisionContext comparisionContext) + { + if (comparisionContext is null) + { + throw new ArgumentNullException(nameof(comparisionContext)); + } + if (!type.InheritsFrom(typeof(IEnumerable<>))) { throw new ArgumentException("Invalid type"); @@ -49,7 +59,7 @@ public override IEnumerable CalculateDifferences(Type type, object o { if (!type.GetTypeInfo().IsArray) { - yield return new Difference("", list1.Count.ToString(), list2.Count.ToString(), + yield return new Difference("", list1.Count.ToString(), list2.Count.ToString(), DifferenceTypes.NumberOfElementsMismatch); } diff --git a/ObjectsComparer/ObjectsComparer/IComparableExtensions.cs b/ObjectsComparer/ObjectsComparer/IComparableExtensions.cs index 8c37666..35d96c9 100644 --- a/ObjectsComparer/ObjectsComparer/IComparableExtensions.cs +++ b/ObjectsComparer/ObjectsComparer/IComparableExtensions.cs @@ -5,11 +5,11 @@ namespace ObjectsComparer { public static class IComparableExtensions { - public static IEnumerable CalculateDifferences(this IComparer comparer, Type type, object obj1, object obj2, IComparisionContext currentContext) + public static IEnumerable CalculateDifferences(this IComparer comparer, Type type, object obj1, object obj2, IComparisionContext comparisionContext) { if (comparer is IContextableComparer contextableComparer) { - return contextableComparer.CalculateDifferences(type, obj1, obj2, currentContext); + return contextableComparer.CalculateDifferences(type, obj1, obj2, comparisionContext); } return comparer.CalculateDifferences(type, obj1, obj2); From 784aa9199c5c02260d69e448671c4f7b1cfac8cd Mon Sep 17 00:00:00 2001 From: "ASD\\nemec" Date: Thu, 5 Aug 2021 14:50:34 +0200 Subject: [PATCH 005/181] Edit typeof(IComparisionContext) > typeof(IComparisionContext). --- ObjectsComparer/ObjectsComparer/Comparer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ObjectsComparer/ObjectsComparer/Comparer.cs b/ObjectsComparer/ObjectsComparer/Comparer.cs index 0acbf82..57cae7f 100644 --- a/ObjectsComparer/ObjectsComparer/Comparer.cs +++ b/ObjectsComparer/ObjectsComparer/Comparer.cs @@ -47,7 +47,7 @@ public IEnumerable CalculateDifferences(Type type, object obj1, obje .Any(intft => intft.GetTypeInfo().IsGenericType && intft.GetGenericTypeDefinition() == typeof(IContextableComparer<>)); var genericType = comparerIsContextable ? typeof(IContextableComparer<>).MakeGenericType(type) : typeof(IComparer<>).MakeGenericType(type); - var genericMethodParameterTypes = comparerIsContextable ? new[] { type, type, typeof(ComparisionContext) } : new[] { type, type }; + var genericMethodParameterTypes = comparerIsContextable ? new[] { type, type, typeof(IComparisionContext) } : new[] { type, type }; var genericMethod = genericType.GetTypeInfo().GetMethod(CalculateDifferencesMethodName, genericMethodParameterTypes); var genericMethodParameters = comparerIsContextable ? new[] { obj1, obj2, comparisionContext } : new[] { obj1, obj2 }; From 7c8e84649b7d9d4f389b38151ad98b0fef97df0c Mon Sep 17 00:00:00 2001 From: "ASD\\nemec" Date: Thu, 5 Aug 2021 14:50:34 +0200 Subject: [PATCH 006/181] Build comparison context tree. Edit typeof(IComparisionContext) > typeof(IComparisionContext). Implement IContextableComparer, IContextableComparer into AbstractEnumerablesComparer, EnumerablesComparer, EnumerablesComparer, GenericEnumerablesComparer, HashSetsComparer, MultidimensionalArraysComparer. Edit typo ...comparision > ...comparison. Rename files ComparisionContext.cs > ComparisonContext.cs, IComparisionContext.cs > IComparisionContext.cs. --- .../ObjectsComparer.Tests/DaNComparerTests.cs | 130 ++++++++++++++++++ ObjectsComparer/ObjectsComparer/Comparer.cs | 12 +- ObjectsComparer/ObjectsComparer/Comparer~1.cs | 16 ++- .../ObjectsComparer/ComparisionContext.cs | 35 ----- .../ObjectsComparer/ComparisonContext.cs | 56 ++++++++ .../AbstractEnumerablesComparer.cs | 4 +- .../CustomComparers/EnumerablesComparer.cs | 10 +- .../CustomComparers/EnumerablesComparer~1.cs | 20 ++- .../GenericEnumerablesComparer.cs | 7 +- .../CustomComparers/HashSetsComparer.cs | 7 +- .../MultidimensionalArraysComparer.cs | 7 +- .../ObjectsComparer/IComparableExtensions.cs | 16 ++- .../ObjectsComparer/IComparisionContext.cs | 12 -- .../ObjectsComparer/IComparisonContext.cs | 17 +++ .../ObjectsComparer/IContextableComparer.cs | 2 +- .../ObjectsComparer/IContextableComparer~1.cs | 4 +- 16 files changed, 273 insertions(+), 82 deletions(-) delete mode 100644 ObjectsComparer/ObjectsComparer/ComparisionContext.cs create mode 100644 ObjectsComparer/ObjectsComparer/ComparisonContext.cs delete mode 100644 ObjectsComparer/ObjectsComparer/IComparisionContext.cs create mode 100644 ObjectsComparer/ObjectsComparer/IComparisonContext.cs diff --git a/ObjectsComparer/ObjectsComparer.Tests/DaNComparerTests.cs b/ObjectsComparer/ObjectsComparer.Tests/DaNComparerTests.cs index 675dcb7..357e21d 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/DaNComparerTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/DaNComparerTests.cs @@ -22,12 +22,142 @@ public class Car public string[] Items3 { get; set; } } + class Osoba + { + public int Id { get; set; } + + public string Jmeno { get; set; } + + public List TrvaleAdresy { get; set; } = new List(); + + public List PrechodneAdresy { get; set; } = new List(); + + public Osoba Pritel { get; set; } + } + + class Adresa + { + public int Id { get; set; } + + public string Ulice { get; set; } + + public List Mesta { get; set; } = new List(); + } + + class Mesto + { + public int Id { get; set; } + + public string Nazev { get; set; } + } + [TestFixture] public class DaNComparerTests { + [Test] + public void TestOsoba() + { + Tuple osoby = LoadOsoby(); + var comparer = new Comparer(); + var context = ComparisonContext.Undefined; + var diffs = comparer.CalculateDifferences(osoby.Item1, osoby.Item2, context).ToArray(); + } + + Tuple LoadOsoby() + { + var osoba1 = new Osoba + { + Id = 1, + Jmeno = "Daniel", + }; + var pritel1 = new Osoba + { + Id = -1, + Jmeno = "Pavel" + }; + + osoba1.Pritel = pritel1; + pritel1.Pritel = osoba1; + + var adresaPritele1 = new Adresa + { + Id = 11, + Ulice = "Bílá" + }; + osoba1.Pritel.TrvaleAdresy.Add(adresaPritele1); + + var adresa1 = new Adresa + { + Id = 2, + Ulice = "Májová", + }; + var adresa2 = new Adresa + { + Id = 3, + Ulice = "Bělská" + }; + var adresa3 = new Adresa + { + Id = 4, + Ulice = "Růžová" + }; + var adresaList = new List(new Adresa[] { adresa1, adresa2, adresa3 }); + osoba1.TrvaleAdresy.AddRange(adresaList); + + var osoba2 = new Osoba + { + Id = 1, + Jmeno = "Jan", + }; + + var pritel2 = new Osoba + { + Id = -2, + Jmeno = "Petr" + }; + + osoba2.Pritel = pritel2; + + var adresaPritele2 = new Adresa + { + Id = 111, + Ulice = "Černá" + }; + osoba2.Pritel.TrvaleAdresy.Add(adresaPritele2); + + var adresa4 = new Adresa + { + Id = 2, + Ulice = "Májová" + }; + var adresa5 = new Adresa + { + Id = 3, + Ulice = "Bělská" + }; + var adresa6 = new Adresa + { + Id = 4, + Ulice = "Modrá" + }; + var adresaList2 = new List(new Adresa[] { adresa4, adresa5, adresa6 }); + osoba2.TrvaleAdresy.AddRange(adresaList2); + + return new Tuple(osoba1, osoba2); + } + + public void Calc(T obj1, T obj2) + { + var x = ((object)obj1 ?? obj2).GetType(); + } + [Test] public void TestEnumerablesComparer() { + string s1 = null; + string s2 = "x"; + Calc(s2, s1); + var car1 = new Car(); //car1.Items1 = new int[] { 1, 2, 3 }; //car1.Items2 = new List { "ahoj", "nazdar", "čau" }; diff --git a/ObjectsComparer/ObjectsComparer/Comparer.cs b/ObjectsComparer/ObjectsComparer/Comparer.cs index 0acbf82..c4756d0 100644 --- a/ObjectsComparer/ObjectsComparer/Comparer.cs +++ b/ObjectsComparer/ObjectsComparer/Comparer.cs @@ -29,14 +29,14 @@ public Comparer(ComparisonSettings settings = null, BaseComparer parentComparer public override IEnumerable CalculateDifferences(Type type, object obj1, object obj2) { - return CalculateDifferences(type, obj1, obj2, ComparisionContext.Undefined); + return CalculateDifferences(type, obj1, obj2, ComparisonContext.Undefined); } - public IEnumerable CalculateDifferences(Type type, object obj1, object obj2, IComparisionContext comparisionContext) + public IEnumerable CalculateDifferences(Type type, object obj1, object obj2, IComparisonContext comparisonContext) { - if (comparisionContext is null) + if (comparisonContext is null) { - throw new ArgumentNullException(nameof(comparisionContext)); + throw new ArgumentNullException(nameof(comparisonContext)); } var getObjectsComparerMethod = typeof(IComparersFactory).GetTypeInfo().GetMethods().First(m => m.IsGenericMethod); @@ -47,9 +47,9 @@ public IEnumerable CalculateDifferences(Type type, object obj1, obje .Any(intft => intft.GetTypeInfo().IsGenericType && intft.GetGenericTypeDefinition() == typeof(IContextableComparer<>)); var genericType = comparerIsContextable ? typeof(IContextableComparer<>).MakeGenericType(type) : typeof(IComparer<>).MakeGenericType(type); - var genericMethodParameterTypes = comparerIsContextable ? new[] { type, type, typeof(ComparisionContext) } : new[] { type, type }; + var genericMethodParameterTypes = comparerIsContextable ? new[] { type, type, typeof(IComparisonContext) } : new[] { type, type }; var genericMethod = genericType.GetTypeInfo().GetMethod(CalculateDifferencesMethodName, genericMethodParameterTypes); - var genericMethodParameters = comparerIsContextable ? new[] { obj1, obj2, comparisionContext } : new[] { obj1, obj2 }; + var genericMethodParameters = comparerIsContextable ? new[] { obj1, obj2, comparisonContext } : new[] { obj1, obj2 }; // ReSharper disable once PossibleNullReferenceException return (IEnumerable)genericMethod.Invoke(comparer, genericMethodParameters); diff --git a/ObjectsComparer/ObjectsComparer/Comparer~1.cs b/ObjectsComparer/ObjectsComparer/Comparer~1.cs index 70a0032..f0bf37c 100644 --- a/ObjectsComparer/ObjectsComparer/Comparer~1.cs +++ b/ObjectsComparer/ObjectsComparer/Comparer~1.cs @@ -56,17 +56,17 @@ public override IEnumerable CalculateDifferences(T obj1, T obj2) return CalculateDifferences(obj1, obj2, memberInfo: null); } - public IEnumerable CalculateDifferences(T obj1, T obj2, IComparisionContext comparisionContext) + public IEnumerable CalculateDifferences(T obj1, T obj2, IComparisonContext comparisonContext) { - return CalculateDifferences(obj1, obj2, memberInfo: null, comparisionContext); + return CalculateDifferences(obj1, obj2, memberInfo: null, comparisonContext); } internal IEnumerable CalculateDifferences(T obj1, T obj2, MemberInfo memberInfo) { - return CalculateDifferences(obj1, obj2, memberInfo, ComparisionContext.Undefined); + return CalculateDifferences(obj1, obj2, memberInfo, ComparisonContext.Undefined); } - IEnumerable CalculateDifferences(T obj1, T obj2, MemberInfo memberInfo, IComparisionContext comparisionContext) + IEnumerable CalculateDifferences(T obj1, T obj2, MemberInfo memberInfo, IComparisonContext comparisonContext) { var comparer = memberInfo != null ? OverridesCollection.GetComparer(memberInfo) @@ -89,7 +89,7 @@ IEnumerable CalculateDifferences(T obj1, T obj2, MemberInfo memberIn var conditionalComparer = _conditionalComparers.FirstOrDefault(c => c.IsMatch(typeof(T), obj1, obj2)); if (conditionalComparer != null) { - foreach (var difference in conditionalComparer.CalculateDifferences(typeof(T), obj1, obj2, comparisionContext)) + foreach (var difference in conditionalComparer.CalculateDifferences(typeof(T), obj1, obj2, comparisonContext)) { yield return difference; } @@ -116,7 +116,7 @@ IEnumerable CalculateDifferences(T obj1, T obj2, MemberInfo memberIn } foreach (var member in _members) - { + { var value1 = member.GetMemberValue(obj1); var value2 = member.GetMemberValue(obj2); var type = member.GetMemberType(); @@ -126,6 +126,8 @@ IEnumerable CalculateDifferences(T obj1, T obj2, MemberInfo memberIn continue; } + var context = ComparisonContext.Create(currentMember: member, ancestor: comparisonContext); + var valueComparer = DefaultValueComparer; var hasCustomComparer = false; @@ -141,7 +143,7 @@ IEnumerable CalculateDifferences(T obj1, T obj2, MemberInfo memberIn { var objectDataComparer = Factory.GetObjectsComparer(type, Settings, this); - foreach (var failure in objectDataComparer.CalculateDifferences(type, value1, value2, ComparisionContext.Create(currentMember: member))) + foreach (var failure in objectDataComparer.CalculateDifferences(type, value1, value2, context)) { yield return failure.InsertPath(member.Name); } diff --git a/ObjectsComparer/ObjectsComparer/ComparisionContext.cs b/ObjectsComparer/ObjectsComparer/ComparisionContext.cs deleted file mode 100644 index d2b7cd1..0000000 --- a/ObjectsComparer/ObjectsComparer/ComparisionContext.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Reflection; - -namespace ObjectsComparer -{ - public sealed class ComparisionContext : IComparisionContext - { - public static readonly IComparisionContext Undefined = new ComparisionContext(); - - private ComparisionContext() - { - } - - private ComparisionContext(MemberInfo currentMember) - { - Member = currentMember ?? throw new ArgumentNullException(nameof(currentMember)); - } - - /// - /// - /// - public MemberInfo Member { get; } - - public static IComparisionContext Create(MemberInfo currentMember) - { - if (currentMember is null) - { - throw new ArgumentNullException(nameof(currentMember)); - } - - return new ComparisionContext(currentMember); - } - } -} \ No newline at end of file diff --git a/ObjectsComparer/ObjectsComparer/ComparisonContext.cs b/ObjectsComparer/ObjectsComparer/ComparisonContext.cs new file mode 100644 index 0000000..f0948e1 --- /dev/null +++ b/ObjectsComparer/ObjectsComparer/ComparisonContext.cs @@ -0,0 +1,56 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Reflection; + +namespace ObjectsComparer +{ + public sealed class ComparisonContext : IComparisonContext + { + public static readonly IComparisonContext Undefined = new ComparisonContext(); + + readonly List _descendants = new List(); + + private ComparisonContext() + { + } + + private ComparisonContext(MemberInfo currentMember) + { + //Member = currentMember ?? throw new ArgumentNullException(nameof(currentMember)); + Member = currentMember; + } + + /// + /// + /// + public MemberInfo Member { get; } + + public IComparisonContext Ancestor { get; set; } + + public ReadOnlyCollection Descendants => _descendants.AsReadOnly(); + + internal static IComparisonContext Create(MemberInfo currentMember = null, IComparisonContext ancestor = null) + { + //if (currentMember is null) + //{ + // throw new ArgumentNullException(nameof(currentMember)); + //} + + var context = new ComparisonContext(currentMember); + + if (ancestor != null) + { + ((ComparisonContext)ancestor).AddDescendant(context); + } + + return context; + } + + void AddDescendant(ComparisonContext descendant) + { + _descendants.Add(descendant); + descendant.Ancestor = this; + } + } +} \ No newline at end of file diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractEnumerablesComparer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractEnumerablesComparer.cs index ac54739..cf1d05d 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractEnumerablesComparer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractEnumerablesComparer.cs @@ -5,7 +5,7 @@ namespace ObjectsComparer { - internal abstract class AbstractEnumerablesComparer: AbstractComparer, IComparerWithCondition + internal abstract class AbstractEnumerablesComparer: AbstractComparer, IComparerWithCondition, IContextableComparer { protected AbstractEnumerablesComparer(ComparisonSettings settings, BaseComparer parentComparer, IComparersFactory factory) @@ -42,5 +42,7 @@ public virtual bool SkipMember(Type type, MemberInfo member) public abstract override IEnumerable CalculateDifferences(Type type, object obj1, object obj2); public abstract bool IsMatch(Type type, object obj1, object obj2); + + public abstract IEnumerable CalculateDifferences(Type type, object obj1, object obj2, IComparisonContext comparisonContext); } } \ No newline at end of file diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs index e7fc34a..df6e295 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs @@ -16,14 +16,14 @@ public EnumerablesComparer(ComparisonSettings settings, BaseComparer parentCompa public override IEnumerable CalculateDifferences(Type type, object obj1, object obj2) { - return CalculateDifferences(type, obj1, obj2, ComparisionContext.Undefined); + return CalculateDifferences(type, obj1, obj2, ComparisonContext.Undefined); } - public IEnumerable CalculateDifferences(Type type, object obj1, object obj2, IComparisionContext comparisionContext) + public IEnumerable CalculateDifferences(Type type, object obj1, object obj2, IComparisonContext comparisonContext) { - if (comparisionContext is null) + if (comparisonContext is null) { - throw new ArgumentNullException(nameof(comparisionContext)); + throw new ArgumentNullException(nameof(comparisonContext)); } if (!Settings.EmptyAndNullEnumerablesEqual && @@ -91,7 +91,7 @@ public IEnumerable CalculateDifferences(Type type, object obj1, obje } var comparer = Factory.GetObjectsComparer(array1[i].GetType(), Settings, this); - foreach (var failure in comparer.CalculateDifferences(array1[i].GetType(), array1[i], array2[i])) + foreach (var failure in comparer.CalculateDifferences(array1[i].GetType(), array1[i], array2[i], comparisonContext)) { yield return failure.InsertPath($"[{i}]"); } diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer~1.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer~1.cs index b85779a..968cf4d 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer~1.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer~1.cs @@ -6,7 +6,7 @@ namespace ObjectsComparer { - internal class EnumerablesComparer : AbstractComparer, IContextableComparer + internal class EnumerablesComparer : AbstractComparer, IContextableComparer, IContextableComparer { private readonly IComparer _comparer; @@ -18,14 +18,14 @@ public EnumerablesComparer(ComparisonSettings settings, BaseComparer parentCompa public override IEnumerable CalculateDifferences(Type type, object obj1, object obj2) { - return CalculateDifferences(type, obj1, obj2, ComparisionContext.Undefined); + return CalculateDifferences(type, obj1, obj2, ComparisonContext.Undefined); } - public IEnumerable CalculateDifferences(Type type, object obj1, object obj2, IComparisionContext comparisionContext) + public IEnumerable CalculateDifferences(Type type, object obj1, object obj2, IComparisonContext comparisonContext) { - if (comparisionContext is null) + if (comparisonContext is null) { - throw new ArgumentNullException(nameof(comparisionContext)); + throw new ArgumentNullException(nameof(comparisonContext)); } if (!type.InheritsFrom(typeof(IEnumerable<>))) @@ -68,11 +68,19 @@ public IEnumerable CalculateDifferences(Type type, object obj1, obje for (var i = 0; i < list2.Count; i++) { - foreach (var failure in _comparer.CalculateDifferences(list1[i], list2[i])) + //List item has not got its MemberInfo, but has got its ancestor - list. + var context = ComparisonContext.Create(currentMember: null, ancestor: comparisonContext); + + foreach (var failure in _comparer.CalculateDifferences(list1[i], list2[i], context)) { yield return failure.InsertPath($"[{i}]"); } } } + + public IEnumerable CalculateDifferences(T obj1, T obj2, IComparisonContext comparisonContext) + { + return CalculateDifferences(((object)obj1 ?? obj2).GetType(), obj1, obj2, comparisonContext); + } } } diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/GenericEnumerablesComparer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/GenericEnumerablesComparer.cs index 2c54bcf..4be6aa9 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/GenericEnumerablesComparer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/GenericEnumerablesComparer.cs @@ -16,6 +16,11 @@ public GenericEnumerablesComparer(ComparisonSettings settings, BaseComparer pare } public override IEnumerable CalculateDifferences(Type type, object obj1, object obj2) + { + return CalculateDifferences(type, obj1, obj2, ComparisonContext.Undefined); + } + + public override IEnumerable CalculateDifferences(Type type, object obj1, object obj2, IComparisonContext comparisonContext) { if (obj1 == null && obj2 == null) { @@ -44,7 +49,7 @@ public override IEnumerable CalculateDifferences(Type type, object o var enumerablesComparerType = typeof(EnumerablesComparer<>).MakeGenericType(elementType); var comparer = (IComparer)Activator.CreateInstance(enumerablesComparerType, Settings, this, Factory); - foreach (var difference in comparer.CalculateDifferences(type, obj1, obj2)) + foreach (var difference in comparer.CalculateDifferences(type, obj1, obj2, comparisonContext)) { yield return difference; } diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/HashSetsComparer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/HashSetsComparer.cs index 6775ab8..896be63 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/HashSetsComparer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/HashSetsComparer.cs @@ -14,6 +14,11 @@ public HashSetsComparer(ComparisonSettings settings, BaseComparer parentComparer } public override IEnumerable CalculateDifferences(Type type, object obj1, object obj2) + { + return CalculateDifferences(type, obj1, obj2, ComparisonContext.Undefined); + } + + public override IEnumerable CalculateDifferences(Type type, object obj1, object obj2, IComparisonContext comparisonContext) { if (obj1 == null && obj2 == null) { @@ -33,7 +38,7 @@ public override IEnumerable CalculateDifferences(Type type, object o var enumerablesComparerType = typeof(HashSetsComparer<>).MakeGenericType(elementType); var comparer = (IComparer)Activator.CreateInstance(enumerablesComparerType, Settings, this, Factory); - foreach (var difference in comparer.CalculateDifferences(type, obj1, obj2)) + foreach (var difference in comparer.CalculateDifferences(type, obj1, obj2, comparisonContext)) { yield return difference; } diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/MultidimensionalArraysComparer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/MultidimensionalArraysComparer.cs index d796c98..15fd3aa 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/MultidimensionalArraysComparer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/MultidimensionalArraysComparer.cs @@ -14,6 +14,11 @@ public MultidimensionalArraysComparer(ComparisonSettings settings, BaseComparer } public override IEnumerable CalculateDifferences(Type type, object obj1, object obj2) + { + return CalculateDifferences(type, obj1, obj2, ComparisonContext.Undefined); + } + + public override IEnumerable CalculateDifferences(Type type, object obj1, object obj2, IComparisonContext comparisonContext) { if (obj1 == null && obj2 == null) { @@ -24,7 +29,7 @@ public override IEnumerable CalculateDifferences(Type type, object o var enumerablesComparerType = typeof(MultidimensionalArrayComparer<>).MakeGenericType(typeInfo.GetElementType()); var comparer = (IComparer)Activator.CreateInstance(enumerablesComparerType, Settings, this, Factory); - foreach (var difference in comparer.CalculateDifferences(type, obj1, obj2)) + foreach (var difference in comparer.CalculateDifferences(type, obj1, obj2, comparisonContext)) { yield return difference; } diff --git a/ObjectsComparer/ObjectsComparer/IComparableExtensions.cs b/ObjectsComparer/ObjectsComparer/IComparableExtensions.cs index 35d96c9..519367e 100644 --- a/ObjectsComparer/ObjectsComparer/IComparableExtensions.cs +++ b/ObjectsComparer/ObjectsComparer/IComparableExtensions.cs @@ -5,16 +5,24 @@ namespace ObjectsComparer { public static class IComparableExtensions { - public static IEnumerable CalculateDifferences(this IComparer comparer, Type type, object obj1, object obj2, IComparisionContext comparisionContext) + public static IEnumerable CalculateDifferences(this IComparer comparer, Type type, object obj1, object obj2, IComparisonContext comparisonContext) { if (comparer is IContextableComparer contextableComparer) { - return contextableComparer.CalculateDifferences(type, obj1, obj2, comparisionContext); + return contextableComparer.CalculateDifferences(type, obj1, obj2, comparisonContext); } return comparer.CalculateDifferences(type, obj1, obj2); } - } - + public static IEnumerable CalculateDifferences(this IComparer comparer, T obj1, T obj2, IComparisonContext comparisonContext) + { + if (comparer is IContextableComparer contextableComparer) + { + return contextableComparer.CalculateDifferences(obj1, obj2, comparisonContext); + } + + return comparer.CalculateDifferences(obj1, obj2); + } + } } \ No newline at end of file diff --git a/ObjectsComparer/ObjectsComparer/IComparisionContext.cs b/ObjectsComparer/ObjectsComparer/IComparisionContext.cs deleted file mode 100644 index d93f38f..0000000 --- a/ObjectsComparer/ObjectsComparer/IComparisionContext.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System.Reflection; - -namespace ObjectsComparer -{ - /// - /// Represents the current context of the comparison. - /// - public interface IComparisionContext - { - MemberInfo Member { get; } - } -} \ No newline at end of file diff --git a/ObjectsComparer/ObjectsComparer/IComparisonContext.cs b/ObjectsComparer/ObjectsComparer/IComparisonContext.cs new file mode 100644 index 0000000..a5a616c --- /dev/null +++ b/ObjectsComparer/ObjectsComparer/IComparisonContext.cs @@ -0,0 +1,17 @@ +using System.Collections.ObjectModel; +using System.Reflection; + +namespace ObjectsComparer +{ + /// + /// Represents the comparison's process context. + /// + public interface IComparisonContext + { + MemberInfo Member { get; } + + IComparisonContext Ancestor { get; } + + ReadOnlyCollection Descendants { get; } + } +} \ No newline at end of file diff --git a/ObjectsComparer/ObjectsComparer/IContextableComparer.cs b/ObjectsComparer/ObjectsComparer/IContextableComparer.cs index c6807c5..76c6bc5 100644 --- a/ObjectsComparer/ObjectsComparer/IContextableComparer.cs +++ b/ObjectsComparer/ObjectsComparer/IContextableComparer.cs @@ -8,6 +8,6 @@ namespace ObjectsComparer /// public interface IContextableComparer { - IEnumerable CalculateDifferences(Type type, object obj1, object obj2, IComparisionContext comparisionContext); + IEnumerable CalculateDifferences(Type type, object obj1, object obj2, IComparisonContext comparisonContext); } } \ No newline at end of file diff --git a/ObjectsComparer/ObjectsComparer/IContextableComparer~1.cs b/ObjectsComparer/ObjectsComparer/IContextableComparer~1.cs index adb87e6..26b57bb 100644 --- a/ObjectsComparer/ObjectsComparer/IContextableComparer~1.cs +++ b/ObjectsComparer/ObjectsComparer/IContextableComparer~1.cs @@ -4,10 +4,10 @@ namespace ObjectsComparer { /// - /// Generic comparer that accept comparison context. + /// Generic comparer that accept comparison's process context, see . /// public interface IContextableComparer { - IEnumerable CalculateDifferences(T obj1, T obj2, IComparisionContext comparisionContext); + IEnumerable CalculateDifferences(T obj1, T obj2, IComparisonContext comparisonContext); } } From a427b3a2b96ee141ed74c50ccec766e825471205 Mon Sep 17 00:00:00 2001 From: Daniel Nemec Date: Sun, 8 Aug 2021 11:28:58 +0200 Subject: [PATCH 007/181] Translate POCO test helper classes and tests. --- .../ObjectsComparer.Tests/DaNComparerTests.cs | 116 +++++++----------- 1 file changed, 46 insertions(+), 70 deletions(-) diff --git a/ObjectsComparer/ObjectsComparer.Tests/DaNComparerTests.cs b/ObjectsComparer/ObjectsComparer.Tests/DaNComparerTests.cs index 5458797..c0d966a 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/DaNComparerTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/DaNComparerTests.cs @@ -10,7 +10,6 @@ namespace ObjectsComparer.Tests { public class Driver { - } public class Car @@ -22,35 +21,35 @@ public class Car public string[] Items3 { get; set; } } - class Osoba + class Person { public int Id { get; set; } - public string Jmeno { get; set; } + public string PersonName { get; set; } - public List TrvaleAdresy { get; set; } = new List(); + public List
AddressList1 { get; set; } = new List
(); - public List PrechodneAdresy { get; set; } = new List(); + public List
AddressList2 { get; set; } = new List
(); - public Osoba Pritel { get; set; } + public Person BestFriend { get; set; } public string[] ShortNames { get; set; } } - class Adresa + class Address { public int Id { get; set; } - public string Ulice { get; set; } + public string Street { get; set; } - public List Mesta { get; set; } = new List(); + public List CityList { get; set; } = new List(); } - class Mesto + class City { public int Id { get; set; } - public string Nazev { get; set; } + public string CityName { get; set; } } [TestFixture] @@ -59,95 +58,94 @@ public class DaNComparerTests [Test] public void TestOsoba() { - Tuple osoby = LoadOsoby(); - var comparer = new Comparer(); + Tuple osoby = LoadOsoby(); + var comparer = new Comparer(); var rootContext = ComparisonContext.Create(); var diffs = comparer.CalculateDifferences(osoby.Item1, osoby.Item2, rootContext).ToArray(); } - Tuple LoadOsoby() + Tuple LoadOsoby() { - var osoba1 = new Osoba + var person1 = new Person { Id = 1, - Jmeno = "Daniel", + PersonName = "Daniel", ShortNames = new string[] { "shn1", "shn2", "shn3" } }; - var pritel1 = new Osoba + var pritel1 = new Person { Id = -1, - Jmeno = "Pavel" + PersonName = "Paul" }; - osoba1.Pritel = pritel1; - pritel1.Pritel = osoba1; + person1.BestFriend = pritel1; - var adresaPritele1 = new Adresa + var friend1Address = new Address { Id = 11, - Ulice = "Bílá" + Street = "White" }; - osoba1.Pritel.TrvaleAdresy.Add(adresaPritele1); + person1.BestFriend.AddressList1.Add(friend1Address); - var adresa1 = new Adresa + var adr1 = new Address { Id = 2, - Ulice = "Májová", + Street = "Red", }; - var adresa2 = new Adresa + var adr2 = new Address { Id = 3, - Ulice = "Bělská" + Street = "Yellow" }; - var adresa3 = new Adresa + var adr3 = new Address { Id = 4, - Ulice = "Růžová" + Street = "Rose" }; - var adresaList = new List(new Adresa[] { adresa1, adresa2, adresa3 }); - osoba1.TrvaleAdresy.AddRange(adresaList); + var addressList = new List
(new Address[] { adr1, adr2, adr3 }); + person1.AddressList1.AddRange(addressList); - var osoba2 = new Osoba + var person2 = new Person { Id = 1, - Jmeno = "Jan", + PersonName = "John", ShortNames = new string[] { "shn1", "shn2", "shn3" } }; - var pritel2 = new Osoba + var pritel2 = new Person { Id = -2, - Jmeno = "Petr" + PersonName = "Peter" }; - osoba2.Pritel = pritel2; + person2.BestFriend = pritel2; - var adresaPritele2 = new Adresa + var adresaPritele2 = new Address { Id = 111, - Ulice = "Černá" + Street = "Black" }; - osoba2.Pritel.TrvaleAdresy.Add(adresaPritele2); + person2.BestFriend.AddressList1.Add(adresaPritele2); - var adresa4 = new Adresa + var adr4 = new Address { Id = 2, - Ulice = "Májová" + Street = "Red" }; - var adresa5 = new Adresa + var adr5 = new Address { Id = 3, - Ulice = "Bělská" + Street = "Yellow" }; - var adresa6 = new Adresa + var adr6 = new Address { Id = 4, - Ulice = "Modrá" + Street = "Blue" }; - var adresaList2 = new List(new Adresa[] { adresa4, adresa5, adresa6 }); - osoba2.TrvaleAdresy.AddRange(adresaList2); + var addressList2 = new List
(new Address[] { adr4, adr5, adr6 }); + person2.AddressList1.AddRange(addressList2); - return new Tuple(osoba1, osoba2); + return new Tuple(person1, person2); } public void Calc(T obj1, T obj2) @@ -155,28 +153,6 @@ public void Calc(T obj1, T obj2) var x = ((object)obj1 ?? obj2).GetType(); } - [Test] - public void TestEnumerablesComparer() - { - string s1 = null; - string s2 = "x"; - Calc(s2, s1); - - var car1 = new Car(); - //car1.Items1 = new int[] { 1, 2, 3 }; - //car1.Items2 = new List { "ahoj", "nazdar", "čau" }; - car1.Items3 = new string[] { "ahoj", "nazdar", "čau" }; - var car2 = new Car(); - //car2.Items1 = new int[] { -1, 2, 3 }; - //car2.Items2 = new List { "ahoj", "hello", "čau" }; - car2.Items3 = new string[] { "hi", "nazdar", "čau" }; - //var comparer = new Comparer(); - var comparer = new Comparer(); - //var diffs = comparer.CalculateDifferences(typeof(Car), car1, car2).ToArray(); - var diffs = comparer.CalculateDifferences(car1, car2).ToArray(); - //var member = car1.GetType().GetMember(nameof(car1.Items1)).Single(); - } - public class SubClassA { public bool BoolProperty { get; set; } From 19ac44ef492a6dfa4685686ad045f9c4dcf8c1c0 Mon Sep 17 00:00:00 2001 From: Daniel Nemec Date: Sun, 8 Aug 2021 11:56:06 +0200 Subject: [PATCH 008/181] Build comparison context tree in EnumerablesComparer. --- ObjectsComparer/ObjectsComparer.Tests/DaNComparerTests.cs | 8 ++++++-- .../CustomComparers/EnumerablesComparer.cs | 3 +++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/ObjectsComparer/ObjectsComparer.Tests/DaNComparerTests.cs b/ObjectsComparer/ObjectsComparer.Tests/DaNComparerTests.cs index c0d966a..6d62df4 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/DaNComparerTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/DaNComparerTests.cs @@ -34,6 +34,8 @@ class Person public Person BestFriend { get; set; } public string[] ShortNames { get; set; } + + public IEnumerable LongNames { get; set; } } class Address @@ -70,7 +72,8 @@ Tuple LoadOsoby() { Id = 1, PersonName = "Daniel", - ShortNames = new string[] { "shn1", "shn2", "shn3" } + ShortNames = new string[] { "shn1", "shn2", "shn3" }, + LongNames = new string[] { "ln1", "ln2", "ln3" } }; var pritel1 = new Person { @@ -109,7 +112,8 @@ Tuple LoadOsoby() { Id = 1, PersonName = "John", - ShortNames = new string[] { "shn1", "shn2", "shn3" } + ShortNames = new string[] { "shn1", "shn2", "shn3" }, + LongNames = new string[] { "ln1", "ln2", "ln3" } }; var pritel2 = new Person diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs index df6e295..ff77827 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs @@ -64,6 +64,9 @@ public IEnumerable CalculateDifferences(Type type, object obj1, obje //ToDo Extract type for (var i = 0; i < array2.Length; i++) { + //List item has not got its MemberInfo, but has got its ancestor - list. + var context = ComparisonContext.Create(currentMember: null, ancestor: comparisonContext); + if (array1[i] == null && array2[i] == null) { continue; From c29cfee3f26c365bdfa5bde94e4639d6f3db2cce Mon Sep 17 00:00:00 2001 From: "ASD\\nemec" Date: Tue, 10 Aug 2021 14:44:12 +0200 Subject: [PATCH 009/181] Edit comment. --- .../ObjectsComparer/IComparisonContext.cs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/ObjectsComparer/ObjectsComparer/IComparisonContext.cs b/ObjectsComparer/ObjectsComparer/IComparisonContext.cs index a5a616c..336eca0 100644 --- a/ObjectsComparer/ObjectsComparer/IComparisonContext.cs +++ b/ObjectsComparer/ObjectsComparer/IComparisonContext.cs @@ -8,10 +8,25 @@ namespace ObjectsComparer /// public interface IComparisonContext { + /// + /// It is always null for root context (start point of the comparison) and always null for list item. List item never has got its member. It only has got the ancestor context - list and that list has got its member. + /// MemberInfo Member { get; } + /// + /// Ancestor context. For example if current context is "Person.Name" property, ancestor is Person. + /// IComparisonContext Ancestor { get; } + /// + /// Children contexts. For example, if Person class has got properties Name and Birthday, person context has got one child context Name a and one child context Birthday. + /// ReadOnlyCollection Descendants { get; } + + //A list of differences directly related to this context. + + //Whether the object has any properties (bool recursive). + + //HasDifferences(bool recursive) } } \ No newline at end of file From a93cd9651d94c58d570c8901702d67d447a7de46 Mon Sep 17 00:00:00 2001 From: nemec Date: Wed, 11 Aug 2021 00:17:27 +0200 Subject: [PATCH 010/181] Delete IComparisonContext inetrface. Refactor ComparisonContext class. --- ObjectsComparer/ObjectsComparer/Comparer.cs | 4 +- ObjectsComparer/ObjectsComparer/Comparer~1.cs | 4 +- .../ObjectsComparer/ComparisonContext.cs | 39 ++++++++++--------- .../AbstractEnumerablesComparer.cs | 2 +- .../CustomComparers/EnumerablesComparer.cs | 2 +- .../CustomComparers/EnumerablesComparer~1.cs | 4 +- .../GenericEnumerablesComparer.cs | 2 +- .../CustomComparers/HashSetsComparer.cs | 2 +- .../MultidimensionalArraysComparer.cs | 2 +- ...leExtensions.cs => IComparerExtensions.cs} | 6 +-- .../ObjectsComparer/IComparisonContext.cs | 32 --------------- .../ObjectsComparer/IContextableComparer.cs | 2 +- .../ObjectsComparer/IContextableComparer~1.cs | 4 +- 13 files changed, 37 insertions(+), 68 deletions(-) rename ObjectsComparer/ObjectsComparer/{IComparableExtensions.cs => IComparerExtensions.cs} (83%) delete mode 100644 ObjectsComparer/ObjectsComparer/IComparisonContext.cs diff --git a/ObjectsComparer/ObjectsComparer/Comparer.cs b/ObjectsComparer/ObjectsComparer/Comparer.cs index c4756d0..95ed12f 100644 --- a/ObjectsComparer/ObjectsComparer/Comparer.cs +++ b/ObjectsComparer/ObjectsComparer/Comparer.cs @@ -32,7 +32,7 @@ public override IEnumerable CalculateDifferences(Type type, object o return CalculateDifferences(type, obj1, obj2, ComparisonContext.Undefined); } - public IEnumerable CalculateDifferences(Type type, object obj1, object obj2, IComparisonContext comparisonContext) + public IEnumerable CalculateDifferences(Type type, object obj1, object obj2, ComparisonContext comparisonContext) { if (comparisonContext is null) { @@ -47,7 +47,7 @@ public IEnumerable CalculateDifferences(Type type, object obj1, obje .Any(intft => intft.GetTypeInfo().IsGenericType && intft.GetGenericTypeDefinition() == typeof(IContextableComparer<>)); var genericType = comparerIsContextable ? typeof(IContextableComparer<>).MakeGenericType(type) : typeof(IComparer<>).MakeGenericType(type); - var genericMethodParameterTypes = comparerIsContextable ? new[] { type, type, typeof(IComparisonContext) } : new[] { type, type }; + var genericMethodParameterTypes = comparerIsContextable ? new[] { type, type, typeof(ComparisonContext) } : new[] { type, type }; var genericMethod = genericType.GetTypeInfo().GetMethod(CalculateDifferencesMethodName, genericMethodParameterTypes); var genericMethodParameters = comparerIsContextable ? new[] { obj1, obj2, comparisonContext } : new[] { obj1, obj2 }; diff --git a/ObjectsComparer/ObjectsComparer/Comparer~1.cs b/ObjectsComparer/ObjectsComparer/Comparer~1.cs index f0bf37c..26915fb 100644 --- a/ObjectsComparer/ObjectsComparer/Comparer~1.cs +++ b/ObjectsComparer/ObjectsComparer/Comparer~1.cs @@ -56,7 +56,7 @@ public override IEnumerable CalculateDifferences(T obj1, T obj2) return CalculateDifferences(obj1, obj2, memberInfo: null); } - public IEnumerable CalculateDifferences(T obj1, T obj2, IComparisonContext comparisonContext) + public IEnumerable CalculateDifferences(T obj1, T obj2, ComparisonContext comparisonContext) { return CalculateDifferences(obj1, obj2, memberInfo: null, comparisonContext); } @@ -66,7 +66,7 @@ internal IEnumerable CalculateDifferences(T obj1, T obj2, MemberInfo return CalculateDifferences(obj1, obj2, memberInfo, ComparisonContext.Undefined); } - IEnumerable CalculateDifferences(T obj1, T obj2, MemberInfo memberInfo, IComparisonContext comparisonContext) + IEnumerable CalculateDifferences(T obj1, T obj2, MemberInfo memberInfo, ComparisonContext comparisonContext) { var comparer = memberInfo != null ? OverridesCollection.GetComparer(memberInfo) diff --git a/ObjectsComparer/ObjectsComparer/ComparisonContext.cs b/ObjectsComparer/ObjectsComparer/ComparisonContext.cs index f0948e1..713936a 100644 --- a/ObjectsComparer/ObjectsComparer/ComparisonContext.cs +++ b/ObjectsComparer/ObjectsComparer/ComparisonContext.cs @@ -5,11 +5,11 @@ namespace ObjectsComparer { - public sealed class ComparisonContext : IComparisonContext + public sealed class ComparisonContext { - public static readonly IComparisonContext Undefined = new ComparisonContext(); + public static readonly ComparisonContext Undefined = new ComparisonContext(); - readonly List _descendants = new List(); + readonly List _descendants = new List(); private ComparisonContext() { @@ -17,33 +17,28 @@ private ComparisonContext() private ComparisonContext(MemberInfo currentMember) { - //Member = currentMember ?? throw new ArgumentNullException(nameof(currentMember)); Member = currentMember; } /// - /// + /// It is always null for root context (start point of the comparison) and always null for list item. List item never has got its member. It only has got the ancestor context - list and that list has got its member. /// public MemberInfo Member { get; } - public IComparisonContext Ancestor { get; set; } + /// + /// Ancestor context. For example if current context is "Person.Name" property, ancestor is Person. + /// + public ComparisonContext Ancestor { get; set; } - public ReadOnlyCollection Descendants => _descendants.AsReadOnly(); + /// + /// Children contexts. For example, if Person class has got properties Name and Birthday, person context has got one child context Name a and one child context Birthday. + /// + public ReadOnlyCollection Descendants => _descendants.AsReadOnly(); - internal static IComparisonContext Create(MemberInfo currentMember = null, IComparisonContext ancestor = null) + internal static ComparisonContext Create(MemberInfo currentMember = null, ComparisonContext ancestor = null) { - //if (currentMember is null) - //{ - // throw new ArgumentNullException(nameof(currentMember)); - //} - var context = new ComparisonContext(currentMember); - - if (ancestor != null) - { - ((ComparisonContext)ancestor).AddDescendant(context); - } - + ancestor.AddDescendant(context); return context; } @@ -52,5 +47,11 @@ void AddDescendant(ComparisonContext descendant) _descendants.Add(descendant); descendant.Ancestor = this; } + + //A list of differences directly related to this context. + + //Whether the object has any properties (bool recursive). + + //HasDifferences(bool recursive) } } \ No newline at end of file diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractEnumerablesComparer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractEnumerablesComparer.cs index 85eddc0..5d5d1d7 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractEnumerablesComparer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractEnumerablesComparer.cs @@ -58,6 +58,6 @@ public virtual bool SkipMember(Type type, MemberInfo member) public abstract bool IsMatch(Type type, object obj1, object obj2); - public abstract IEnumerable CalculateDifferences(Type type, object obj1, object obj2, IComparisonContext comparisonContext); + public abstract IEnumerable CalculateDifferences(Type type, object obj1, object obj2, ComparisonContext comparisonContext); } } \ No newline at end of file diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs index ff77827..0ca8892 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs @@ -19,7 +19,7 @@ public override IEnumerable CalculateDifferences(Type type, object o return CalculateDifferences(type, obj1, obj2, ComparisonContext.Undefined); } - public IEnumerable CalculateDifferences(Type type, object obj1, object obj2, IComparisonContext comparisonContext) + public IEnumerable CalculateDifferences(Type type, object obj1, object obj2, ComparisonContext comparisonContext) { if (comparisonContext is null) { diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer~1.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer~1.cs index 968cf4d..ab9354d 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer~1.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer~1.cs @@ -21,7 +21,7 @@ public override IEnumerable CalculateDifferences(Type type, object o return CalculateDifferences(type, obj1, obj2, ComparisonContext.Undefined); } - public IEnumerable CalculateDifferences(Type type, object obj1, object obj2, IComparisonContext comparisonContext) + public IEnumerable CalculateDifferences(Type type, object obj1, object obj2, ComparisonContext comparisonContext) { if (comparisonContext is null) { @@ -78,7 +78,7 @@ public IEnumerable CalculateDifferences(Type type, object obj1, obje } } - public IEnumerable CalculateDifferences(T obj1, T obj2, IComparisonContext comparisonContext) + public IEnumerable CalculateDifferences(T obj1, T obj2, ComparisonContext comparisonContext) { return CalculateDifferences(((object)obj1 ?? obj2).GetType(), obj1, obj2, comparisonContext); } diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/GenericEnumerablesComparer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/GenericEnumerablesComparer.cs index 4be6aa9..41c2afd 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/GenericEnumerablesComparer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/GenericEnumerablesComparer.cs @@ -20,7 +20,7 @@ public override IEnumerable CalculateDifferences(Type type, object o return CalculateDifferences(type, obj1, obj2, ComparisonContext.Undefined); } - public override IEnumerable CalculateDifferences(Type type, object obj1, object obj2, IComparisonContext comparisonContext) + public override IEnumerable CalculateDifferences(Type type, object obj1, object obj2, ComparisonContext comparisonContext) { if (obj1 == null && obj2 == null) { diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/HashSetsComparer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/HashSetsComparer.cs index 896be63..9f85033 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/HashSetsComparer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/HashSetsComparer.cs @@ -18,7 +18,7 @@ public override IEnumerable CalculateDifferences(Type type, object o return CalculateDifferences(type, obj1, obj2, ComparisonContext.Undefined); } - public override IEnumerable CalculateDifferences(Type type, object obj1, object obj2, IComparisonContext comparisonContext) + public override IEnumerable CalculateDifferences(Type type, object obj1, object obj2, ComparisonContext comparisonContext) { if (obj1 == null && obj2 == null) { diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/MultidimensionalArraysComparer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/MultidimensionalArraysComparer.cs index 15fd3aa..7a322a2 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/MultidimensionalArraysComparer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/MultidimensionalArraysComparer.cs @@ -18,7 +18,7 @@ public override IEnumerable CalculateDifferences(Type type, object o return CalculateDifferences(type, obj1, obj2, ComparisonContext.Undefined); } - public override IEnumerable CalculateDifferences(Type type, object obj1, object obj2, IComparisonContext comparisonContext) + public override IEnumerable CalculateDifferences(Type type, object obj1, object obj2, ComparisonContext comparisonContext) { if (obj1 == null && obj2 == null) { diff --git a/ObjectsComparer/ObjectsComparer/IComparableExtensions.cs b/ObjectsComparer/ObjectsComparer/IComparerExtensions.cs similarity index 83% rename from ObjectsComparer/ObjectsComparer/IComparableExtensions.cs rename to ObjectsComparer/ObjectsComparer/IComparerExtensions.cs index 519367e..1bd9218 100644 --- a/ObjectsComparer/ObjectsComparer/IComparableExtensions.cs +++ b/ObjectsComparer/ObjectsComparer/IComparerExtensions.cs @@ -3,9 +3,9 @@ namespace ObjectsComparer { - public static class IComparableExtensions + public static class IComparerExtensions { - public static IEnumerable CalculateDifferences(this IComparer comparer, Type type, object obj1, object obj2, IComparisonContext comparisonContext) + public static IEnumerable CalculateDifferences(this IComparer comparer, Type type, object obj1, object obj2, ComparisonContext comparisonContext) { if (comparer is IContextableComparer contextableComparer) { @@ -15,7 +15,7 @@ public static IEnumerable CalculateDifferences(this IComparer compar return comparer.CalculateDifferences(type, obj1, obj2); } - public static IEnumerable CalculateDifferences(this IComparer comparer, T obj1, T obj2, IComparisonContext comparisonContext) + public static IEnumerable CalculateDifferences(this IComparer comparer, T obj1, T obj2, ComparisonContext comparisonContext) { if (comparer is IContextableComparer contextableComparer) { diff --git a/ObjectsComparer/ObjectsComparer/IComparisonContext.cs b/ObjectsComparer/ObjectsComparer/IComparisonContext.cs deleted file mode 100644 index 336eca0..0000000 --- a/ObjectsComparer/ObjectsComparer/IComparisonContext.cs +++ /dev/null @@ -1,32 +0,0 @@ -using System.Collections.ObjectModel; -using System.Reflection; - -namespace ObjectsComparer -{ - /// - /// Represents the comparison's process context. - /// - public interface IComparisonContext - { - /// - /// It is always null for root context (start point of the comparison) and always null for list item. List item never has got its member. It only has got the ancestor context - list and that list has got its member. - /// - MemberInfo Member { get; } - - /// - /// Ancestor context. For example if current context is "Person.Name" property, ancestor is Person. - /// - IComparisonContext Ancestor { get; } - - /// - /// Children contexts. For example, if Person class has got properties Name and Birthday, person context has got one child context Name a and one child context Birthday. - /// - ReadOnlyCollection Descendants { get; } - - //A list of differences directly related to this context. - - //Whether the object has any properties (bool recursive). - - //HasDifferences(bool recursive) - } -} \ No newline at end of file diff --git a/ObjectsComparer/ObjectsComparer/IContextableComparer.cs b/ObjectsComparer/ObjectsComparer/IContextableComparer.cs index 76c6bc5..01e59b5 100644 --- a/ObjectsComparer/ObjectsComparer/IContextableComparer.cs +++ b/ObjectsComparer/ObjectsComparer/IContextableComparer.cs @@ -8,6 +8,6 @@ namespace ObjectsComparer /// public interface IContextableComparer { - IEnumerable CalculateDifferences(Type type, object obj1, object obj2, IComparisonContext comparisonContext); + IEnumerable CalculateDifferences(Type type, object obj1, object obj2, ComparisonContext comparisonContext); } } \ No newline at end of file diff --git a/ObjectsComparer/ObjectsComparer/IContextableComparer~1.cs b/ObjectsComparer/ObjectsComparer/IContextableComparer~1.cs index 26b57bb..1625530 100644 --- a/ObjectsComparer/ObjectsComparer/IContextableComparer~1.cs +++ b/ObjectsComparer/ObjectsComparer/IContextableComparer~1.cs @@ -4,10 +4,10 @@ namespace ObjectsComparer { /// - /// Generic comparer that accept comparison's process context, see . + /// Generic comparer that accept comparison's process context, see . /// public interface IContextableComparer { - IEnumerable CalculateDifferences(T obj1, T obj2, IComparisonContext comparisonContext); + IEnumerable CalculateDifferences(T obj1, T obj2, ComparisonContext comparisonContext); } } From 079b1a7aa3b02807a5acd7a2d58b90aa9c7af686 Mon Sep 17 00:00:00 2001 From: Daniel Nemec Date: Sat, 18 Sep 2021 20:33:41 +0200 Subject: [PATCH 011/181] Extend the ComparisonSettings class with the List property. --- .../ComparisonSettingsTests.cs | 33 ++++++ .../ObjectsComparer/ComparisonContext.cs | 6 +- .../ObjectsComparer/ComparisonSettings.cs | 5 + .../ObjectsComparer/ListComparisonSettings.cs | 21 ++++ .../ListConfigurationOptions.cs | 100 ++++++++++++++++++ 5 files changed, 164 insertions(+), 1 deletion(-) create mode 100644 ObjectsComparer/ObjectsComparer/ListComparisonSettings.cs create mode 100644 ObjectsComparer/ObjectsComparer/ListConfigurationOptions.cs diff --git a/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs b/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs index e5460d1..44e673b 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs @@ -48,5 +48,38 @@ public void WronkType() Assert.Throws(() => settings.GetCustomSetting("setting1")); } + + /// + /// Whether list comparison by key is correctly set. + /// + [Test] + public void CompareListElementsByKeyIsCorrectlySet() + { + //Client side. + var settings = new ComparisonSettings(); + settings.List.Configure((comparisonContext, configurationOptions) => + { + configurationOptions.CompareElementsByKey(); + }); + + //Component side. + var options = new ListConfigurationOptions(); + var ctx = ComparisonContext.Create(); + settings.List.ConfigureOptions(ctx, options); + + Assert.AreEqual(true, options.KeyProvider != null); + } + + /// + /// Whether backward compatibility is ensured. + /// + [Test] + public void ListComparisonConfigurationBackwardCompatibilityEnsured() + { + var options = ListConfigurationOptions.Default; + + Assert.AreEqual(false, options.CompareUnequalLists); + Assert.AreEqual(true, options.KeyProvider == null); + } } } diff --git a/ObjectsComparer/ObjectsComparer/ComparisonContext.cs b/ObjectsComparer/ObjectsComparer/ComparisonContext.cs index 713936a..4413df2 100644 --- a/ObjectsComparer/ObjectsComparer/ComparisonContext.cs +++ b/ObjectsComparer/ObjectsComparer/ComparisonContext.cs @@ -38,7 +38,11 @@ private ComparisonContext(MemberInfo currentMember) internal static ComparisonContext Create(MemberInfo currentMember = null, ComparisonContext ancestor = null) { var context = new ComparisonContext(currentMember); - ancestor.AddDescendant(context); + if (ancestor != null) + { + ancestor.AddDescendant(context); + } + return context; } diff --git a/ObjectsComparer/ObjectsComparer/ComparisonSettings.cs b/ObjectsComparer/ObjectsComparer/ComparisonSettings.cs index f8d4974..ad86244 100644 --- a/ObjectsComparer/ObjectsComparer/ComparisonSettings.cs +++ b/ObjectsComparer/ObjectsComparer/ComparisonSettings.cs @@ -27,6 +27,11 @@ public class ComparisonSettings private readonly Dictionary, object> _settings = new Dictionary, object>(); + /// + /// List comparison settings. + /// + public ListComparisonSettings List { get; } = new ListComparisonSettings(); + /// /// Initializes a new instance of the class. /// diff --git a/ObjectsComparer/ObjectsComparer/ListComparisonSettings.cs b/ObjectsComparer/ObjectsComparer/ListComparisonSettings.cs new file mode 100644 index 0000000..9aea3b0 --- /dev/null +++ b/ObjectsComparer/ObjectsComparer/ListComparisonSettings.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace ObjectsComparer +{ + public class ListComparisonSettings + { + internal Action ConfigureOptions { get; private set; } = null; + + public void Configure(Action configureOptions) + { + if (configureOptions is null) + { + throw new ArgumentNullException(nameof(configureOptions)); + } + + ConfigureOptions = configureOptions; + } + } +} diff --git a/ObjectsComparer/ObjectsComparer/ListConfigurationOptions.cs b/ObjectsComparer/ObjectsComparer/ListConfigurationOptions.cs new file mode 100644 index 0000000..ea43212 --- /dev/null +++ b/ObjectsComparer/ObjectsComparer/ListConfigurationOptions.cs @@ -0,0 +1,100 @@ +using System; +using System.Linq; +using System.Collections.Generic; +using System.Reflection; +using System.Text; + +namespace ObjectsComparer +{ + public class ListConfigurationOptions + { + /// + /// Whether to compare elements of the lists even if their number differs ( always will be logged). Default value = false. + /// + public bool CompareUnequalLists { get; set; } = false; + + /// + /// If null, the elements will be compared by their index, otherwise by key. Default value = null. + /// + internal Func KeyProvider { get; private set;} = null; + + internal static ListConfigurationOptions Default = new ListConfigurationOptions(); + + /// + /// Compares list elements by index. Default behavior. + /// + public void CompareElementsByIndex() + { + KeyProvider = null; + } + + /// + /// Compares list elements by key. It will try to find one of the public properties named "Id" or "Name", in that order. Case sensitive. + /// + public void CompareElementsByKey() + { + CompareElementsByKey(caseSensitive: true, "Id", "Name"); + } + + /// + /// Compares list elements by key. It will try to find one of the public properties specified by argument . In that order. + /// + public void CompareElementsByKey(bool caseSensitive = true, params string[] keys) + { + if (keys is null) + { + throw new ArgumentNullException(nameof(keys)); + } + + if (keys.Any() == false) + { + throw new ArgumentException("At least one key is required.", nameof(keys)); + } + + CompareElementsByKey(element => + { + return GetKeyValue(element, caseSensitive, keys); + }); + } + + /// + /// Compares list elements by key using . + /// + public void CompareElementsByKey(Func keyProvider) + { + if (keyProvider is null) + { + throw new ArgumentNullException(nameof(keyProvider)); + } + + KeyProvider = keyProvider; + } + + /// + /// It will try to find one of the public properties specified by , then it returns its value. + /// + /// Null if no property matches the specified key, or the corresponding property returns null, or is null itself. + static object GetKeyValue(object instance, bool caseSensitive, params string[] keys) + { + if (instance != null) + { + BindingFlags bindingAttr = BindingFlags.Public; + if (caseSensitive == false) + { + bindingAttr |= BindingFlags.IgnoreCase; + } + + foreach (var key in keys) + { + var property = instance.GetType().GetTypeInfo().GetProperty(key, bindingAttr); + if (property != null) + { + return property.GetValue(instance); + } + } + } + + return instance; + } + } +} From 54be4999d25477de88585841a02aaeacf0174967 Mon Sep 17 00:00:00 2001 From: Daniel Nemec Date: Sun, 19 Sep 2021 18:45:28 +0200 Subject: [PATCH 012/181] Edit CalculateDifferences operation: Add element key comparison. Ucompleted! --- .../CustomComparers/EnumerablesComparer.cs | 45 ++++++++++++++++++- .../ElementNotFoundByKeyException.cs | 11 +++++ .../ListConfigurationOptions.cs | 4 +- 3 files changed, 56 insertions(+), 4 deletions(-) create mode 100644 ObjectsComparer/ObjectsComparer/Exceptions/ElementNotFoundByKeyException.cs diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs index 0ca8892..0295e22 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using System.Reflection; +using ObjectsComparer.Exceptions; using ObjectsComparer.Utils; namespace ObjectsComparer @@ -54,19 +55,59 @@ public IEnumerable CalculateDifferences(Type type, object obj1, obje var array1 = ((IEnumerable)obj1).Cast().ToArray(); var array2 = ((IEnumerable)obj2).Cast().ToArray(); + var listConfigurationOptions = ListConfigurationOptions.Default; + Settings.List.ConfigureOptions?.Invoke(comparisonContext, listConfigurationOptions); + if (array1.Length != array2.Length) { yield return new Difference("", array1.Length.ToString(), array2.Length.ToString(), DifferenceTypes.NumberOfElementsMismatch); - yield break; + + if (listConfigurationOptions.CompareUnequalLists == false) + { + yield break; + } } + var smallerArray = array1.Length <= array2.Length ? array1 : array2; + var largerArray = smallerArray == array1 ? array2 : array1; + //ToDo Extract type - for (var i = 0; i < array2.Length; i++) + for (var i = 0; i < smallerArray.Length; i++) { //List item has not got its MemberInfo, but has got its ancestor - list. var context = ComparisonContext.Create(currentMember: null, ancestor: comparisonContext); + object element1 = smallerArray[i]; + object element2 = null; + + if (listConfigurationOptions.KeyProvider == null) + { + element2 = largerArray[i]; + } + else + { + if (element1 == null) + { + if (largerArray.Any(li => li == null)) + { + element2 = null; + } + else + { + + } + } + else + { + object element1Key = listConfigurationOptions.KeyProvider(element1); + if (element1Key == null) + { + throw new ElementNotFoundByKeyException(); + } + } + } + if (array1[i] == null && array2[i] == null) { continue; diff --git a/ObjectsComparer/ObjectsComparer/Exceptions/ElementNotFoundByKeyException.cs b/ObjectsComparer/ObjectsComparer/Exceptions/ElementNotFoundByKeyException.cs new file mode 100644 index 0000000..f6ee623 --- /dev/null +++ b/ObjectsComparer/ObjectsComparer/Exceptions/ElementNotFoundByKeyException.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace ObjectsComparer.Exceptions +{ + public class ElementNotFoundByKeyException : Exception + { + + } +} diff --git a/ObjectsComparer/ObjectsComparer/ListConfigurationOptions.cs b/ObjectsComparer/ObjectsComparer/ListConfigurationOptions.cs index ea43212..b216ff6 100644 --- a/ObjectsComparer/ObjectsComparer/ListConfigurationOptions.cs +++ b/ObjectsComparer/ObjectsComparer/ListConfigurationOptions.cs @@ -9,7 +9,7 @@ namespace ObjectsComparer public class ListConfigurationOptions { /// - /// Whether to compare elements of the lists even if their number differs ( always will be logged). Default value = false. + /// Whether to compare elements of the lists even if their number differs ( will always be logged). Default value = false. /// public bool CompareUnequalLists { get; set; } = false; @@ -37,7 +37,7 @@ public void CompareElementsByKey() } /// - /// Compares list elements by key. It will try to find one of the public properties specified by argument . In that order. + /// Compares list elements by key. It will try to find one of the public properties specified by argument , in that order. /// public void CompareElementsByKey(bool caseSensitive = true, params string[] keys) { From 89b12794339b8df870e5efc229c0a9b7394ca197 Mon Sep 17 00:00:00 2001 From: Daniel Nemec Date: Mon, 27 Sep 2021 11:05:19 +0200 Subject: [PATCH 013/181] Add CalculateDifferencesByKey, CalculateDifferencesByIndex. --- .../ComparisonSettingsTests.cs | 16 +++- .../CustomComparers/EnumerablesComparer.cs | 75 +++++++++---------- .../ListConfigurationOptions.cs | 2 +- 3 files changed, 49 insertions(+), 44 deletions(-) diff --git a/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs b/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs index 44e673b..eb48f43 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs @@ -1,4 +1,6 @@ -using System.Collections.Generic; +using System.Collections; +using System.Linq; +using System.Collections.Generic; using NUnit.Framework; namespace ObjectsComparer.Tests @@ -71,7 +73,7 @@ public void CompareListElementsByKeyIsCorrectlySet() } /// - /// Whether backward compatibility is ensured. + /// Whether backward compatibility is ensured i.e. sequential comparing of equal lists. /// [Test] public void ListComparisonConfigurationBackwardCompatibilityEnsured() @@ -81,5 +83,15 @@ public void ListComparisonConfigurationBackwardCompatibilityEnsured() Assert.AreEqual(false, options.CompareUnequalLists); Assert.AreEqual(true, options.KeyProvider == null); } + + [Test] + public void PrubeznyTest() + { + var a1 = new ArrayList() { 1, 2, 3 }; + var a2 = new ArrayList() { 1, 2, 3, 4 }; + var comparer = new Comparer(); + + var result = comparer.CalculateDifferences(a1, a2).ToArray(); + } } } diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs index 0295e22..fa640df 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs @@ -71,71 +71,64 @@ public IEnumerable CalculateDifferences(Type type, object obj1, obje var smallerArray = array1.Length <= array2.Length ? array1 : array2; var largerArray = smallerArray == array1 ? array2 : array1; + IEnumerable failrues; + if (listConfigurationOptions.KeyProvider != null) + { + failrues = CalculateDifferencesByKey(smallerArray, largerArray, comparisonContext, listConfigurationOptions); + } + else + { + failrues = CalculateDifferencesByIndex(smallerArray, largerArray, comparisonContext); + } + + foreach (var failrue in failrues) + { + yield return failrue; + } + } + + private IEnumerable CalculateDifferencesByKey(object[] smallerArray, object[] largerArray, ComparisonContext comparisonContext, ListConfigurationOptions listConfigurationOptions) + { + throw new NotImplementedException(); + } + + private IEnumerable CalculateDifferencesByIndex(object[] smallerArray, object[] largerArray, ComparisonContext comparisonContext) + { //ToDo Extract type for (var i = 0; i < smallerArray.Length; i++) { //List item has not got its MemberInfo, but has got its ancestor - list. var context = ComparisonContext.Create(currentMember: null, ancestor: comparisonContext); - object element1 = smallerArray[i]; - object element2 = null; - - if (listConfigurationOptions.KeyProvider == null) - { - element2 = largerArray[i]; - } - else - { - if (element1 == null) - { - if (largerArray.Any(li => li == null)) - { - element2 = null; - } - else - { - - } - } - else - { - object element1Key = listConfigurationOptions.KeyProvider(element1); - if (element1Key == null) - { - throw new ElementNotFoundByKeyException(); - } - } - } - - if (array1[i] == null && array2[i] == null) + if (smallerArray[i] == null && largerArray[i] == null) { continue; } - var valueComparer1 = array1[i] != null ? OverridesCollection.GetComparer(array1[i].GetType()) ?? DefaultValueComparer : DefaultValueComparer; - var valueComparer2 = array2[i] != null ? OverridesCollection.GetComparer(array2[i].GetType()) ?? DefaultValueComparer : DefaultValueComparer; + var valueComparer1 = smallerArray[i] != null ? OverridesCollection.GetComparer(smallerArray[i].GetType()) ?? DefaultValueComparer : DefaultValueComparer; + var valueComparer2 = largerArray[i] != null ? OverridesCollection.GetComparer(largerArray[i].GetType()) ?? DefaultValueComparer : DefaultValueComparer; - if (array1[i] == null) + if (smallerArray[i] == null) { - yield return new Difference($"[{i}]", string.Empty, valueComparer2.ToString(array2[i])); + yield return new Difference($"[{i}]", string.Empty, valueComparer2.ToString(largerArray[i])); continue; } - if (array2[i] == null) + if (largerArray[i] == null) { - yield return new Difference($"[{i}]", valueComparer1.ToString(array1[i]), string.Empty); + yield return new Difference($"[{i}]", valueComparer1.ToString(smallerArray[i]), string.Empty); continue; } - if (array1[i].GetType() != array2[i].GetType()) + if (smallerArray[i].GetType() != largerArray[i].GetType()) { - yield return new Difference($"[{i}]", valueComparer1.ToString(array1[i]), valueComparer2.ToString(array2[i]), DifferenceTypes.TypeMismatch); + yield return new Difference($"[{i}]", valueComparer1.ToString(smallerArray[i]), valueComparer2.ToString(largerArray[i]), DifferenceTypes.TypeMismatch); continue; } - var comparer = Factory.GetObjectsComparer(array1[i].GetType(), Settings, this); - foreach (var failure in comparer.CalculateDifferences(array1[i].GetType(), array1[i], array2[i], comparisonContext)) + var comparer = Factory.GetObjectsComparer(smallerArray[i].GetType(), Settings, this); + foreach (var failure in comparer.CalculateDifferences(smallerArray[i].GetType(), smallerArray[i], largerArray[i], comparisonContext)) { yield return failure.InsertPath($"[{i}]"); } diff --git a/ObjectsComparer/ObjectsComparer/ListConfigurationOptions.cs b/ObjectsComparer/ObjectsComparer/ListConfigurationOptions.cs index b216ff6..420d9be 100644 --- a/ObjectsComparer/ObjectsComparer/ListConfigurationOptions.cs +++ b/ObjectsComparer/ObjectsComparer/ListConfigurationOptions.cs @@ -73,7 +73,7 @@ public void CompareElementsByKey(Func keyProvider) /// /// It will try to find one of the public properties specified by , then it returns its value. /// - /// Null if no property matches the specified key, or the corresponding property returns null, or is null itself. + /// Returns the value of the property that corresponds to the specified key. If no property matches the specified key, it returns the itself. static object GetKeyValue(object instance, bool caseSensitive, params string[] keys) { if (instance != null) From 9b9d4ddd6d6900fa5f9592a24050c80b59cdf41b Mon Sep 17 00:00:00 2001 From: Daniel Nemec Date: Mon, 27 Sep 2021 20:00:09 +0200 Subject: [PATCH 014/181] Rem SkipArrayMemberNameList. --- .../AbstractEnumerablesComparer.cs | 29 ++++++++++--------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractEnumerablesComparer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractEnumerablesComparer.cs index 5d5d1d7..88a7608 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractEnumerablesComparer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractEnumerablesComparer.cs @@ -3,24 +3,25 @@ using System.Collections.Generic; using System.Reflection; using ObjectsComparer.Utils; +using System.Collections; namespace ObjectsComparer { internal abstract class AbstractEnumerablesComparer: AbstractComparer, IComparerWithCondition, IContextableComparer { - /// - /// member names that will be skipped from comaprison. - /// - static readonly string[] SkipArrayMemberNameList = new string[] - { - nameof(Array.Length), - "LongLength", - nameof(Array.Rank), - "SyncRoot", - "IsReadOnly", - "IsFixedSize", - "IsSynchronized" - }; + ///// + ///// member names that will be skipped from comaprison. + ///// + //static readonly string[] SkipArrayMemberNameList = new string[] + //{ + // nameof(Array.Length), + // "LongLength", + // nameof(Array.Rank), + // "SyncRoot", + // "IsReadOnly", + // "IsFixedSize", + // "IsSynchronized" + //}; protected AbstractEnumerablesComparer(ComparisonSettings settings, BaseComparer parentComparer, IComparersFactory factory) @@ -37,7 +38,7 @@ public virtual bool SkipMember(Type type, MemberInfo member) { if (type.InheritsFrom(typeof(Array))) { - if (SkipArrayMemberNameList.Any(skipMemberName => skipMemberName == member.Name)) + if (member.Name == "LongLength") { return true; } From 616dde0bc4e721a22233a7270abb8b224c606b7a Mon Sep 17 00:00:00 2001 From: "ASD\\nemec" Date: Thu, 30 Sep 2021 13:11:12 +0200 Subject: [PATCH 015/181] Reimplement CalculateDifferencesByIndex operation. Respect value1 and value2 positions in Difference instance. Add missed element in first/second object difference type. --- .../Comparer_NonGenericEnumerableTests.cs | 30 ++++++++++ .../CustomComparers/EnumerablesComparer.cs | 60 +++++++++++++------ 2 files changed, 72 insertions(+), 18 deletions(-) diff --git a/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs b/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs index debcb82..c060247 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs @@ -51,6 +51,36 @@ public void InequalityProperty() Assert.AreEqual("Str3", differences.First().Value2); } + [Test] + public void InequalityCountAndInequalityProperty() + { + var a1 = new A { NonGenericEnumerable = new ArrayList { new B { Property1 = "Str2" }, new B { Property1 = "Str1" } } }; + var a2 = new A { NonGenericEnumerable = new ArrayList { new B { Property1 = "Str1" } } }; + + var settings = new ComparisonSettings(); + settings.List.Configure((ctx, options) => + { + options.CompareUnequalLists = true; + }); + + var comparer = new Comparer(settings); + + var differences = comparer.CalculateDifferences(a1, a2).ToList(); + + CollectionAssert.IsNotEmpty(differences); + Assert.AreEqual("NonGenericEnumerable", differences.First().MemberPath); + Assert.AreEqual(DifferenceTypes.NumberOfElementsMismatch, differences.First().DifferenceType); + Assert.AreEqual("2", differences.First().Value1); + Assert.AreEqual("1", differences.First().Value2); + Assert.AreEqual(DifferenceTypes.ValueMismatch, differences[1].DifferenceType); + Assert.AreEqual("NonGenericEnumerable[0].Property1", differences[1].MemberPath); + Assert.AreEqual("Str2", differences[1].Value1); + Assert.AreEqual("Str1", differences[1].Value2); + Assert.AreEqual(DifferenceTypes.MissedElementInSecondObject, differences[2].DifferenceType); + Assert.AreEqual(true, differences[2].Value1 != string.Empty); + Assert.AreEqual(true, differences[2].Value2 == string.Empty); + } + [Test] public void NullElementsEquality() { diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs index fa640df..3fb2a7e 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs @@ -1,6 +1,7 @@ using System; using System.Collections; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; using System.Reflection; using ObjectsComparer.Exceptions; @@ -69,17 +70,15 @@ public IEnumerable CalculateDifferences(Type type, object obj1, obje } } - var smallerArray = array1.Length <= array2.Length ? array1 : array2; - var largerArray = smallerArray == array1 ? array2 : array1; IEnumerable failrues; if (listConfigurationOptions.KeyProvider != null) { - failrues = CalculateDifferencesByKey(smallerArray, largerArray, comparisonContext, listConfigurationOptions); + failrues = CalculateDifferencesByKey(array1, array2, comparisonContext, listConfigurationOptions); } else { - failrues = CalculateDifferencesByIndex(smallerArray, largerArray, comparisonContext); + failrues = CalculateDifferencesByIndex(array1, array2, comparisonContext); } foreach (var failrue in failrues) @@ -88,51 +87,76 @@ public IEnumerable CalculateDifferences(Type type, object obj1, obje } } - private IEnumerable CalculateDifferencesByKey(object[] smallerArray, object[] largerArray, ComparisonContext comparisonContext, ListConfigurationOptions listConfigurationOptions) + private IEnumerable CalculateDifferencesByKey(object[] array1, object[] array2, ComparisonContext comparisonContext, ListConfigurationOptions listConfigurationOptions) { + Debug.WriteLine(nameof(CalculateDifferencesByKey)); throw new NotImplementedException(); } - private IEnumerable CalculateDifferencesByIndex(object[] smallerArray, object[] largerArray, ComparisonContext comparisonContext) + private IEnumerable CalculateDifferencesByIndex(object[] array1, object[] array2, ComparisonContext comparisonContext) { + Debug.WriteLine(nameof(CalculateDifferencesByIndex)); + + int array1Count = array1.Count(); + int array2Count = array2.Count(); + int smallerCount = array1Count <= array2Count ? array1Count : array2Count; + //ToDo Extract type - for (var i = 0; i < smallerArray.Length; i++) + for (var i = 0; i < smallerCount; i++) { //List item has not got its MemberInfo, but has got its ancestor - list. var context = ComparisonContext.Create(currentMember: null, ancestor: comparisonContext); - if (smallerArray[i] == null && largerArray[i] == null) + if (array1[i] == null && array2[i] == null) { continue; } - var valueComparer1 = smallerArray[i] != null ? OverridesCollection.GetComparer(smallerArray[i].GetType()) ?? DefaultValueComparer : DefaultValueComparer; - var valueComparer2 = largerArray[i] != null ? OverridesCollection.GetComparer(largerArray[i].GetType()) ?? DefaultValueComparer : DefaultValueComparer; + var valueComparer1 = array1[i] != null ? OverridesCollection.GetComparer(array1[i].GetType()) ?? DefaultValueComparer : DefaultValueComparer; + var valueComparer2 = array2[i] != null ? OverridesCollection.GetComparer(array2[i].GetType()) ?? DefaultValueComparer : DefaultValueComparer; - if (smallerArray[i] == null) + if (array1[i] == null) { - yield return new Difference($"[{i}]", string.Empty, valueComparer2.ToString(largerArray[i])); + yield return new Difference($"[{i}]", string.Empty, valueComparer2.ToString(array2[i])); continue; } - if (largerArray[i] == null) + if (array2[i] == null) { - yield return new Difference($"[{i}]", valueComparer1.ToString(smallerArray[i]), string.Empty); + yield return new Difference($"[{i}]", valueComparer1.ToString(array1[i]), string.Empty); continue; } - if (smallerArray[i].GetType() != largerArray[i].GetType()) + if (array1[i].GetType() != array2[i].GetType()) { - yield return new Difference($"[{i}]", valueComparer1.ToString(smallerArray[i]), valueComparer2.ToString(largerArray[i]), DifferenceTypes.TypeMismatch); + yield return new Difference($"[{i}]", valueComparer1.ToString(array1[i]), valueComparer2.ToString(array2[i]), DifferenceTypes.TypeMismatch); continue; } - var comparer = Factory.GetObjectsComparer(smallerArray[i].GetType(), Settings, this); - foreach (var failure in comparer.CalculateDifferences(smallerArray[i].GetType(), smallerArray[i], largerArray[i], comparisonContext)) + var comparer = Factory.GetObjectsComparer(array1[i].GetType(), Settings, this); + + foreach (var failure in comparer.CalculateDifferences(array1[i].GetType(), array1[i], array2[i], comparisonContext)) { yield return failure.InsertPath($"[{i}]"); } } + + //Add a difference for each element that is in array1 and not in array2, or vice versa. The positions of value1 and value2 are respected in Difference instance. + if (array1Count != array2Count) + { + var largerArray = array1Count > array2Count ? array1 : array2; + + for (int i = smallerCount; i < largerArray.Length; i++) + { + var valueComparer = largerArray[i] != null ? OverridesCollection.GetComparer(largerArray[i].GetType()) ?? DefaultValueComparer : DefaultValueComparer; + + yield return new Difference( + memberPath: $"[{i}]", + value1: array1Count > array2Count ? valueComparer.ToString(largerArray[i]) : string.Empty, + value2: array2Count > array1Count ? valueComparer.ToString(largerArray[i]) : string.Empty, + differenceType: array1Count > array2Count ? DifferenceTypes.MissedElementInSecondObject : DifferenceTypes.MissedElementInFirstObject); + } + } } public bool IsMatch(Type type, object obj1, object obj2) From 558a9fc359efb53c31bc848b9209a6cd9dd892a9 Mon Sep 17 00:00:00 2001 From: "ASD\\nemec" Date: Mon, 4 Oct 2021 16:01:49 +0200 Subject: [PATCH 016/181] Edit typo: comparisonContext >context. Edit test method InequalityCountAndInequalityProperty. --- .../Comparer_NonGenericEnumerableTests.cs | 26 +++++++++++++++---- .../CustomComparers/EnumerablesComparer.cs | 4 +-- 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs b/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs index c060247..37608e3 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs @@ -54,23 +54,39 @@ public void InequalityProperty() [Test] public void InequalityCountAndInequalityProperty() { - var a1 = new A { NonGenericEnumerable = new ArrayList { new B { Property1 = "Str2" }, new B { Property1 = "Str1" } } }; - var a2 = new A { NonGenericEnumerable = new ArrayList { new B { Property1 = "Str1" } } }; + var a1 = new A + { + NonGenericEnumerable = new ArrayList + { + new B { Property1 = "Str2" }, + new B { Property1 = "Str1" } , + null + } + }; + + var a2 = new A + { + NonGenericEnumerable = new ArrayList + { + new B { Property1 = "Str1" } + } + }; var settings = new ComparisonSettings(); + settings.List.Configure((ctx, options) => { options.CompareUnequalLists = true; }); var comparer = new Comparer(settings); - - var differences = comparer.CalculateDifferences(a1, a2).ToList(); + var rootCtx = ComparisonContext.Create(); + var differences = comparer.CalculateDifferences(a1, a2, rootCtx).ToList(); CollectionAssert.IsNotEmpty(differences); Assert.AreEqual("NonGenericEnumerable", differences.First().MemberPath); Assert.AreEqual(DifferenceTypes.NumberOfElementsMismatch, differences.First().DifferenceType); - Assert.AreEqual("2", differences.First().Value1); + Assert.AreEqual("3", differences.First().Value1); Assert.AreEqual("1", differences.First().Value2); Assert.AreEqual(DifferenceTypes.ValueMismatch, differences[1].DifferenceType); Assert.AreEqual("NonGenericEnumerable[0].Property1", differences[1].MemberPath); diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs index 3fb2a7e..d3b6c77 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs @@ -135,13 +135,13 @@ private IEnumerable CalculateDifferencesByIndex(object[] array1, obj var comparer = Factory.GetObjectsComparer(array1[i].GetType(), Settings, this); - foreach (var failure in comparer.CalculateDifferences(array1[i].GetType(), array1[i], array2[i], comparisonContext)) + foreach (var failure in comparer.CalculateDifferences(array1[i].GetType(), array1[i], array2[i], context)) { yield return failure.InsertPath($"[{i}]"); } } - //Add a difference for each element that is in array1 and not in array2, or vice versa. The positions of value1 and value2 are respected in Difference instance. + //Add a missed element difference for each element that is in array1 and not in array2, or vice versa. The positions of value1 and value2 are respected in Difference instance. if (array1Count != array2Count) { var largerArray = array1Count > array2Count ? array1 : array2; From afa9d0123392660bb450752fd91a8c6c7059cb1f Mon Sep 17 00:00:00 2001 From: "ASD\\nemec" Date: Wed, 6 Oct 2021 14:58:45 +0200 Subject: [PATCH 017/181] Edit CalculateDifferencesByIndex, CalculateDifferencesByKey. --- .../CustomComparers/EnumerablesComparer.cs | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs index d3b6c77..c500991 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs @@ -87,13 +87,14 @@ public IEnumerable CalculateDifferences(Type type, object obj1, obje } } - private IEnumerable CalculateDifferencesByKey(object[] array1, object[] array2, ComparisonContext comparisonContext, ListConfigurationOptions listConfigurationOptions) + private IEnumerable CalculateDifferencesByKey(object[] array1, object[] array2, ComparisonContext listComparisonContext, ListConfigurationOptions listConfigurationOptions) { Debug.WriteLine(nameof(CalculateDifferencesByKey)); - throw new NotImplementedException(); + + return null; } - private IEnumerable CalculateDifferencesByIndex(object[] array1, object[] array2, ComparisonContext comparisonContext) + private IEnumerable CalculateDifferencesByIndex(object[] array1, object[] array2, ComparisonContext listComparisonContext) { Debug.WriteLine(nameof(CalculateDifferencesByIndex)); @@ -104,8 +105,8 @@ private IEnumerable CalculateDifferencesByIndex(object[] array1, obj //ToDo Extract type for (var i = 0; i < smallerCount; i++) { - //List item has not got its MemberInfo, but has got its ancestor - list. - var context = ComparisonContext.Create(currentMember: null, ancestor: comparisonContext); + //Context representing the element has no MemberInfo. Its ancestor is the context representing the list. + var elementComparisonContext = ComparisonContext.Create(currentMember: null, ancestor: listComparisonContext); if (array1[i] == null && array2[i] == null) { @@ -135,13 +136,13 @@ private IEnumerable CalculateDifferencesByIndex(object[] array1, obj var comparer = Factory.GetObjectsComparer(array1[i].GetType(), Settings, this); - foreach (var failure in comparer.CalculateDifferences(array1[i].GetType(), array1[i], array2[i], context)) + foreach (var failure in comparer.CalculateDifferences(array1[i].GetType(), array1[i], array2[i], elementComparisonContext)) { yield return failure.InsertPath($"[{i}]"); } } - //Add a missed element difference for each element that is in array1 and not in array2, or vice versa. The positions of value1 and value2 are respected in Difference instance. + //Add a "missed element" difference for each element that is in array1 and is not in array2, or vice versa. The positions of value1 and value2 are respected in Difference instance. if (array1Count != array2Count) { var largerArray = array1Count > array2Count ? array1 : array2; From 7c3d88c1119f20e5931b76dfb6e095ed621e41b3 Mon Sep 17 00:00:00 2001 From: Daniel Nemec Date: Sat, 9 Oct 2021 22:14:53 +0200 Subject: [PATCH 018/181] Add CompareElementsByKeyOptions. Tighten access to resources. --- .../ComparisonSettingsTests.cs | 28 +++-- .../CompareElementsByKeyOptions.cs | 107 ++++++++++++++++++ .../ObjectsComparer/ComparisonContext.cs | 1 + .../CustomComparers/EnumerablesComparer.cs | 8 +- .../ObjectsComparer/ListComparisonSettings.cs | 11 +- .../ListConfigurationOptions.cs | 79 +++---------- .../ListElementComparisonMode.cs | 8 ++ 7 files changed, 164 insertions(+), 78 deletions(-) create mode 100644 ObjectsComparer/ObjectsComparer/CompareElementsByKeyOptions.cs create mode 100644 ObjectsComparer/ObjectsComparer/ListElementComparisonMode.cs diff --git a/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs b/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs index eb48f43..37953f3 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs @@ -1,4 +1,5 @@ -using System.Collections; +using System; +using System.Collections; using System.Linq; using System.Collections.Generic; using NUnit.Framework; @@ -59,17 +60,28 @@ public void CompareListElementsByKeyIsCorrectlySet() { //Client side. var settings = new ComparisonSettings(); - settings.List.Configure((comparisonContext, configurationOptions) => + + settings.List.Configure((comparisonContext, listOptions) => { - configurationOptions.CompareElementsByKey(); + listOptions.CompareUnequalLists = true; + + listOptions.CompareElementsByKey(keyOptions => + { + keyOptions.UseKey("Key"); + keyOptions.ThrowKeyNotFound = false; + }); }); //Component side. - var options = new ListConfigurationOptions(); + var listConfigurationOptions = ListConfigurationOptions.Default(); var ctx = ComparisonContext.Create(); - settings.List.ConfigureOptions(ctx, options); + settings.List.ConfigureOptionsAction(ctx, listConfigurationOptions); + var compareElementsByKeyOptions = CompareElementsByKeyOptions.Default(); + listConfigurationOptions.KeyOptionsAction(compareElementsByKeyOptions); - Assert.AreEqual(true, options.KeyProvider != null); + Assert.AreEqual(true, listConfigurationOptions.CompareUnequalLists); + Assert.AreEqual(true, listConfigurationOptions.ComparisonMode == ListElementComparisonMode.Key); + Assert.AreEqual(true, compareElementsByKeyOptions.ThrowKeyNotFound); } /// @@ -78,10 +90,10 @@ public void CompareListElementsByKeyIsCorrectlySet() [Test] public void ListComparisonConfigurationBackwardCompatibilityEnsured() { - var options = ListConfigurationOptions.Default; + var options = ListConfigurationOptions.Default(); Assert.AreEqual(false, options.CompareUnequalLists); - Assert.AreEqual(true, options.KeyProvider == null); + Assert.AreEqual(true, options.ComparisonMode == ListElementComparisonMode.Index); } [Test] diff --git a/ObjectsComparer/ObjectsComparer/CompareElementsByKeyOptions.cs b/ObjectsComparer/ObjectsComparer/CompareElementsByKeyOptions.cs new file mode 100644 index 0000000..50de053 --- /dev/null +++ b/ObjectsComparer/ObjectsComparer/CompareElementsByKeyOptions.cs @@ -0,0 +1,107 @@ +using System; +using System.Linq; +using System.Reflection; + +namespace ObjectsComparer +{ + public class CompareElementsByKeyOptions + { + CompareElementsByKeyOptions() + { + Initialize(); + } + + internal static CompareElementsByKeyOptions Default() => new CompareElementsByKeyOptions(); + + public bool ThrowKeyNotFound { get; set; } = true; + + /// + /// If null, the elements will be compared by their index, otherwise by key. Default value = null. + /// + internal Func KeyProvider { get; private set; } = null; + + void Initialize() + { + UseKey(new string[] { "Id", "Name" }, caseSensitive: false); + } + + /// + /// Compares list elements by key. It will try to find a property specified by argument . + /// + public void UseKey(string key, bool caseSensitive = false) + { + if (string.IsNullOrWhiteSpace(key)) + { + throw new ArgumentException($"'{nameof(key)}' cannot be null or whitespace.", nameof(key)); + } + + UseKey(new string[] { key }, caseSensitive); + } + + /// + /// Compares list elements by key. It will try to find one of the public properties specified by argument , in that order. + /// + public void UseKey(string[] keys, bool caseSensitive = true) + { + if (keys is null) + { + throw new ArgumentNullException(nameof(keys)); + } + + if (keys.Any() == false) + { + throw new ArgumentException("At least one key is required.", nameof(keys)); + } + + if (keys.Any(key => string.IsNullOrWhiteSpace(key))) + { + throw new ArgumentException($"'{nameof(keys)}' cannot contain null or whitespace.", nameof(keys)); + } + + UseKey(element => + { + return GetKeyValue(element, caseSensitive, keys); + }); + } + + /// + /// Compares list elements by key using . + /// + public void UseKey(Func keyProvider) + { + if (keyProvider is null) + { + throw new ArgumentNullException(nameof(keyProvider)); + } + + KeyProvider = keyProvider; + } + + /// + /// It will try to find one of the public properties specified by , then it returns its value. + /// + /// Returns the value of the property that corresponds to the specified key. If no property matches the specified key, it returns the itself. + static object GetKeyValue(object instance, bool caseSensitive, params string[] keys) + { + if (instance != null) + { + BindingFlags bindingAttr = BindingFlags.Public; + if (caseSensitive == false) + { + bindingAttr |= BindingFlags.IgnoreCase; + } + + foreach (var key in keys) + { + var property = instance.GetType().GetTypeInfo().GetProperty(key, bindingAttr); + if (property != null) + { + return property.GetValue(instance); + } + } + } + + return instance; + } + } +} diff --git a/ObjectsComparer/ObjectsComparer/ComparisonContext.cs b/ObjectsComparer/ObjectsComparer/ComparisonContext.cs index 4413df2..47d2912 100644 --- a/ObjectsComparer/ObjectsComparer/ComparisonContext.cs +++ b/ObjectsComparer/ObjectsComparer/ComparisonContext.cs @@ -38,6 +38,7 @@ private ComparisonContext(MemberInfo currentMember) internal static ComparisonContext Create(MemberInfo currentMember = null, ComparisonContext ancestor = null) { var context = new ComparisonContext(currentMember); + if (ancestor != null) { ancestor.AddDescendant(context); diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs index c500991..623e0b9 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs @@ -56,8 +56,8 @@ public IEnumerable CalculateDifferences(Type type, object obj1, obje var array1 = ((IEnumerable)obj1).Cast().ToArray(); var array2 = ((IEnumerable)obj2).Cast().ToArray(); - var listConfigurationOptions = ListConfigurationOptions.Default; - Settings.List.ConfigureOptions?.Invoke(comparisonContext, listConfigurationOptions); + var listConfigurationOptions = ListConfigurationOptions.Default(); + Settings.List.ConfigureOptionsAction?.Invoke(comparisonContext, listConfigurationOptions); if (array1.Length != array2.Length) { @@ -72,7 +72,7 @@ public IEnumerable CalculateDifferences(Type type, object obj1, obje IEnumerable failrues; - if (listConfigurationOptions.KeyProvider != null) + if (listConfigurationOptions.ComparisonMode == ListElementComparisonMode.Key) { failrues = CalculateDifferencesByKey(array1, array2, comparisonContext, listConfigurationOptions); } @@ -89,6 +89,8 @@ public IEnumerable CalculateDifferences(Type type, object obj1, obje private IEnumerable CalculateDifferencesByKey(object[] array1, object[] array2, ComparisonContext listComparisonContext, ListConfigurationOptions listConfigurationOptions) { + var keyOptions = CompareElementsByKeyOptions.Default(); + listConfigurationOptions.KeyOptionsAction?.Invoke(keyOptions); Debug.WriteLine(nameof(CalculateDifferencesByKey)); return null; diff --git a/ObjectsComparer/ObjectsComparer/ListComparisonSettings.cs b/ObjectsComparer/ObjectsComparer/ListComparisonSettings.cs index 9aea3b0..148d922 100644 --- a/ObjectsComparer/ObjectsComparer/ListComparisonSettings.cs +++ b/ObjectsComparer/ObjectsComparer/ListComparisonSettings.cs @@ -4,10 +4,17 @@ namespace ObjectsComparer { + /// + /// List comparison settings. + /// public class ListComparisonSettings { - internal Action ConfigureOptions { get; private set; } = null; + internal Action ConfigureOptionsAction { get; private set; } = null; + /// + /// + /// + /// public void Configure(Action configureOptions) { if (configureOptions is null) @@ -15,7 +22,7 @@ public void Configure(Action config throw new ArgumentNullException(nameof(configureOptions)); } - ConfigureOptions = configureOptions; + ConfigureOptionsAction = configureOptions; } } } diff --git a/ObjectsComparer/ObjectsComparer/ListConfigurationOptions.cs b/ObjectsComparer/ObjectsComparer/ListConfigurationOptions.cs index 420d9be..96d66be 100644 --- a/ObjectsComparer/ObjectsComparer/ListConfigurationOptions.cs +++ b/ObjectsComparer/ObjectsComparer/ListConfigurationOptions.cs @@ -8,93 +8,42 @@ namespace ObjectsComparer { public class ListConfigurationOptions { + ListConfigurationOptions() + { + } + /// /// Whether to compare elements of the lists even if their number differs ( will always be logged). Default value = false. /// public bool CompareUnequalLists { get; set; } = false; - /// - /// If null, the elements will be compared by their index, otherwise by key. Default value = null. - /// - internal Func KeyProvider { get; private set;} = null; - - internal static ListConfigurationOptions Default = new ListConfigurationOptions(); + internal static ListConfigurationOptions Default() => new ListConfigurationOptions(); /// /// Compares list elements by index. Default behavior. /// public void CompareElementsByIndex() { - KeyProvider = null; + KeyOptionsAction = null; } - /// - /// Compares list elements by key. It will try to find one of the public properties named "Id" or "Name", in that order. Case sensitive. - /// + internal Action KeyOptionsAction { get; private set; } + public void CompareElementsByKey() { - CompareElementsByKey(caseSensitive: true, "Id", "Name"); + CompareElementsByKey(options => { }); } - /// - /// Compares list elements by key. It will try to find one of the public properties specified by argument , in that order. - /// - public void CompareElementsByKey(bool caseSensitive = true, params string[] keys) + public void CompareElementsByKey(Action keyOptions) { - if (keys is null) - { - throw new ArgumentNullException(nameof(keys)); - } - - if (keys.Any() == false) + if (keyOptions is null) { - throw new ArgumentException("At least one key is required.", nameof(keys)); + throw new ArgumentNullException(nameof(keyOptions)); } - CompareElementsByKey(element => - { - return GetKeyValue(element, caseSensitive, keys); - }); + KeyOptionsAction = keyOptions; } - /// - /// Compares list elements by key using . - /// - public void CompareElementsByKey(Func keyProvider) - { - if (keyProvider is null) - { - throw new ArgumentNullException(nameof(keyProvider)); - } - - KeyProvider = keyProvider; - } - - /// - /// It will try to find one of the public properties specified by , then it returns its value. - /// - /// Returns the value of the property that corresponds to the specified key. If no property matches the specified key, it returns the itself. - static object GetKeyValue(object instance, bool caseSensitive, params string[] keys) - { - if (instance != null) - { - BindingFlags bindingAttr = BindingFlags.Public; - if (caseSensitive == false) - { - bindingAttr |= BindingFlags.IgnoreCase; - } - - foreach (var key in keys) - { - var property = instance.GetType().GetTypeInfo().GetProperty(key, bindingAttr); - if (property != null) - { - return property.GetValue(instance); - } - } - } - - return instance; - } + internal ListElementComparisonMode ComparisonMode => KeyOptionsAction == null ? ListElementComparisonMode.Index : ListElementComparisonMode.Key; } } diff --git a/ObjectsComparer/ObjectsComparer/ListElementComparisonMode.cs b/ObjectsComparer/ObjectsComparer/ListElementComparisonMode.cs new file mode 100644 index 0000000..65355a0 --- /dev/null +++ b/ObjectsComparer/ObjectsComparer/ListElementComparisonMode.cs @@ -0,0 +1,8 @@ +namespace ObjectsComparer +{ + internal enum ListElementComparisonMode + { + Index, + Key + } +} From 88284a991b904cb7663658aff361ecd8b19ff6e9 Mon Sep 17 00:00:00 2001 From: Daniel Nemec Date: Sun, 10 Oct 2021 18:27:48 +0200 Subject: [PATCH 019/181] Replace ComparisonContext.Undefined > CreateRoot. --- ObjectsComparer/ObjectsComparer/Comparer.cs | 2 +- ObjectsComparer/ObjectsComparer/Comparer~1.cs | 2 +- .../ObjectsComparer/ComparisonContext.cs | 17 +++++++++++++---- .../CustomComparers/EnumerablesComparer.cs | 4 ++-- .../CustomComparers/EnumerablesComparer~1.cs | 2 +- .../GenericEnumerablesComparer.cs | 2 +- .../CustomComparers/HashSetsComparer.cs | 2 +- .../MultidimensionalArraysComparer.cs | 2 +- .../ObjectsComparer/IContextableComparer.cs | 2 +- 9 files changed, 22 insertions(+), 13 deletions(-) diff --git a/ObjectsComparer/ObjectsComparer/Comparer.cs b/ObjectsComparer/ObjectsComparer/Comparer.cs index 95ed12f..335d26b 100644 --- a/ObjectsComparer/ObjectsComparer/Comparer.cs +++ b/ObjectsComparer/ObjectsComparer/Comparer.cs @@ -29,7 +29,7 @@ public Comparer(ComparisonSettings settings = null, BaseComparer parentComparer public override IEnumerable CalculateDifferences(Type type, object obj1, object obj2) { - return CalculateDifferences(type, obj1, obj2, ComparisonContext.Undefined); + return CalculateDifferences(type, obj1, obj2, ComparisonContext.CreateRoot()); } public IEnumerable CalculateDifferences(Type type, object obj1, object obj2, ComparisonContext comparisonContext) diff --git a/ObjectsComparer/ObjectsComparer/Comparer~1.cs b/ObjectsComparer/ObjectsComparer/Comparer~1.cs index 26915fb..752fa37 100644 --- a/ObjectsComparer/ObjectsComparer/Comparer~1.cs +++ b/ObjectsComparer/ObjectsComparer/Comparer~1.cs @@ -63,7 +63,7 @@ public IEnumerable CalculateDifferences(T obj1, T obj2, ComparisonCo internal IEnumerable CalculateDifferences(T obj1, T obj2, MemberInfo memberInfo) { - return CalculateDifferences(obj1, obj2, memberInfo, ComparisonContext.Undefined); + return CalculateDifferences(obj1, obj2, memberInfo, ComparisonContext.CreateRoot()); } IEnumerable CalculateDifferences(T obj1, T obj2, MemberInfo memberInfo, ComparisonContext comparisonContext) diff --git a/ObjectsComparer/ObjectsComparer/ComparisonContext.cs b/ObjectsComparer/ObjectsComparer/ComparisonContext.cs index 47d2912..fa25993 100644 --- a/ObjectsComparer/ObjectsComparer/ComparisonContext.cs +++ b/ObjectsComparer/ObjectsComparer/ComparisonContext.cs @@ -5,9 +5,17 @@ namespace ObjectsComparer { + /// + /// Information about the , which is typically a property or field, in comparison process. It has its ancestor and descendant contexts in the same way as its member has its ancestor and descendant members in an object graph. It contains all possible member differences. + /// It is possible to traverse entire compared object graph and see differences at particular members. + /// public sealed class ComparisonContext { - public static readonly ComparisonContext Undefined = new ComparisonContext(); + /// + /// Creates comparison context root. + /// + /// + public static ComparisonContext CreateRoot() => new ComparisonContext(); readonly List _descendants = new List(); @@ -21,17 +29,18 @@ private ComparisonContext(MemberInfo currentMember) } /// - /// It is always null for root context (start point of the comparison) and always null for list item. List item never has got its member. It only has got the ancestor context - list and that list has got its member. + /// Typically a property or field in comparison process. + /// It is always null for the root context (the starting point of the comparison) and always null for the list element. A list element never has a member, but it has an ancestor context which is the list and that list has its member. /// public MemberInfo Member { get; } /// - /// Ancestor context. For example if current context is "Person.Name" property, ancestor is Person. + /// Ancestor context. /// public ComparisonContext Ancestor { get; set; } /// - /// Children contexts. For example, if Person class has got properties Name and Birthday, person context has got one child context Name a and one child context Birthday. + /// Children contexts. /// public ReadOnlyCollection Descendants => _descendants.AsReadOnly(); diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs index 623e0b9..0bef48c 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs @@ -18,7 +18,7 @@ public EnumerablesComparer(ComparisonSettings settings, BaseComparer parentCompa public override IEnumerable CalculateDifferences(Type type, object obj1, object obj2) { - return CalculateDifferences(type, obj1, obj2, ComparisonContext.Undefined); + return CalculateDifferences(type, obj1, obj2, ComparisonContext.CreateRoot()); } public IEnumerable CalculateDifferences(Type type, object obj1, object obj2, ComparisonContext comparisonContext) @@ -107,7 +107,7 @@ private IEnumerable CalculateDifferencesByIndex(object[] array1, obj //ToDo Extract type for (var i = 0; i < smallerCount; i++) { - //Context representing the element has no MemberInfo. Its ancestor is the context representing the list. + //Context representing the element has no member. Its ancestor is the context representing the list. var elementComparisonContext = ComparisonContext.Create(currentMember: null, ancestor: listComparisonContext); if (array1[i] == null && array2[i] == null) diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer~1.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer~1.cs index ab9354d..c0ecb49 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer~1.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer~1.cs @@ -18,7 +18,7 @@ public EnumerablesComparer(ComparisonSettings settings, BaseComparer parentCompa public override IEnumerable CalculateDifferences(Type type, object obj1, object obj2) { - return CalculateDifferences(type, obj1, obj2, ComparisonContext.Undefined); + return CalculateDifferences(type, obj1, obj2, ComparisonContext.CreateRoot()); } public IEnumerable CalculateDifferences(Type type, object obj1, object obj2, ComparisonContext comparisonContext) diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/GenericEnumerablesComparer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/GenericEnumerablesComparer.cs index 41c2afd..ac995fa 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/GenericEnumerablesComparer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/GenericEnumerablesComparer.cs @@ -17,7 +17,7 @@ public GenericEnumerablesComparer(ComparisonSettings settings, BaseComparer pare public override IEnumerable CalculateDifferences(Type type, object obj1, object obj2) { - return CalculateDifferences(type, obj1, obj2, ComparisonContext.Undefined); + return CalculateDifferences(type, obj1, obj2, ComparisonContext.CreateRoot()); } public override IEnumerable CalculateDifferences(Type type, object obj1, object obj2, ComparisonContext comparisonContext) diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/HashSetsComparer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/HashSetsComparer.cs index 9f85033..eb3597c 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/HashSetsComparer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/HashSetsComparer.cs @@ -15,7 +15,7 @@ public HashSetsComparer(ComparisonSettings settings, BaseComparer parentComparer public override IEnumerable CalculateDifferences(Type type, object obj1, object obj2) { - return CalculateDifferences(type, obj1, obj2, ComparisonContext.Undefined); + return CalculateDifferences(type, obj1, obj2, ComparisonContext.CreateRoot()); } public override IEnumerable CalculateDifferences(Type type, object obj1, object obj2, ComparisonContext comparisonContext) diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/MultidimensionalArraysComparer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/MultidimensionalArraysComparer.cs index 7a322a2..64426e5 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/MultidimensionalArraysComparer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/MultidimensionalArraysComparer.cs @@ -15,7 +15,7 @@ public MultidimensionalArraysComparer(ComparisonSettings settings, BaseComparer public override IEnumerable CalculateDifferences(Type type, object obj1, object obj2) { - return CalculateDifferences(type, obj1, obj2, ComparisonContext.Undefined); + return CalculateDifferences(type, obj1, obj2, ComparisonContext.CreateRoot()); } public override IEnumerable CalculateDifferences(Type type, object obj1, object obj2, ComparisonContext comparisonContext) diff --git a/ObjectsComparer/ObjectsComparer/IContextableComparer.cs b/ObjectsComparer/ObjectsComparer/IContextableComparer.cs index 01e59b5..2d0c4ba 100644 --- a/ObjectsComparer/ObjectsComparer/IContextableComparer.cs +++ b/ObjectsComparer/ObjectsComparer/IContextableComparer.cs @@ -4,7 +4,7 @@ namespace ObjectsComparer { /// - /// Comparer that accept comparison context. + /// Comparer accepting . /// public interface IContextableComparer { From 48b41652c867d22a78d9ab9172e66b6cf780eee6 Mon Sep 17 00:00:00 2001 From: "ASD\\nemec" Date: Mon, 11 Oct 2021 14:30:51 +0200 Subject: [PATCH 020/181] Edit CalculateDifferencesByKey. --- .../CompareElementsByKeyOptions.cs | 3 ++ .../CustomComparers/EnumerablesComparer.cs | 34 +++++++++++++++++-- 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/ObjectsComparer/ObjectsComparer/CompareElementsByKeyOptions.cs b/ObjectsComparer/ObjectsComparer/CompareElementsByKeyOptions.cs index 50de053..adde806 100644 --- a/ObjectsComparer/ObjectsComparer/CompareElementsByKeyOptions.cs +++ b/ObjectsComparer/ObjectsComparer/CompareElementsByKeyOptions.cs @@ -13,6 +13,9 @@ public class CompareElementsByKeyOptions internal static CompareElementsByKeyOptions Default() => new CompareElementsByKeyOptions(); + /// + /// If value = false and element key will not be found, entire element will excluded from comparison. If value = true and element key will not be found, an exception of type will be raised. + /// public bool ThrowKeyNotFound { get; set; } = true; /// diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs index 0bef48c..f9de3ad 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs @@ -76,10 +76,14 @@ public IEnumerable CalculateDifferences(Type type, object obj1, obje { failrues = CalculateDifferencesByKey(array1, array2, comparisonContext, listConfigurationOptions); } - else + else if (listConfigurationOptions.ComparisonMode == ListElementComparisonMode.Index) { failrues = CalculateDifferencesByIndex(array1, array2, comparisonContext); } + else + { + throw new NotImplementedException($"ListElementComparisonMode is not implemented {listConfigurationOptions.ComparisonMode}."); + } foreach (var failrue in failrues) { @@ -91,9 +95,33 @@ private IEnumerable CalculateDifferencesByKey(object[] array1, objec { var keyOptions = CompareElementsByKeyOptions.Default(); listConfigurationOptions.KeyOptionsAction?.Invoke(keyOptions); - Debug.WriteLine(nameof(CalculateDifferencesByKey)); - return null; + foreach (var element1 in array1) + { + if (element1 == null) + { + if (array2.Any(elm2 => elm2 == null)) + { + continue; + } + + yield return new Difference("[Key = NULL]", string.Empty, string.Empty, DifferenceTypes.MissedElementInSecondObject); + continue; + } + + var element1Key = keyOptions.KeyProvider(element1); + + if (element1Key == null) + { + if (keyOptions.ThrowKeyNotFound) + { + throw new ElementNotFoundByKeyException(); + } + continue; + } + } + + Debug.WriteLine(nameof(CalculateDifferencesByKey)); } private IEnumerable CalculateDifferencesByIndex(object[] array1, object[] array2, ComparisonContext listComparisonContext) From df3e3db502bca25e03a7aacb7b2406535ec09b6b Mon Sep 17 00:00:00 2001 From: "ASD\\nemec" Date: Tue, 12 Oct 2021 14:20:25 +0200 Subject: [PATCH 021/181] Edit EnumerablesComparer.CalculateDifferencesByKey. --- .../Comparer_NonGenericEnumerableTests.cs | 53 +- .../ObjectsComparer.Tests/DaNComparerTests.cs | 637 ------------------ .../CompareElementsByKeyOptions.cs | 6 +- ObjectsComparer/ObjectsComparer/Comparer~1.cs | 2 +- .../ObjectsComparer/ComparisonContext.cs | 10 +- .../CustomComparers/EnumerablesComparer.cs | 62 +- .../CustomComparers/EnumerablesComparer~1.cs | 2 +- .../Exceptions/ElementKeyNotFoundException.cs | 29 + .../ElementNotFoundByKeyException.cs | 11 - .../ListConfigurationOptions.cs | 2 +- 10 files changed, 152 insertions(+), 662 deletions(-) delete mode 100644 ObjectsComparer/ObjectsComparer.Tests/DaNComparerTests.cs create mode 100644 ObjectsComparer/ObjectsComparer/Exceptions/ElementKeyNotFoundException.cs delete mode 100644 ObjectsComparer/ObjectsComparer/Exceptions/ElementNotFoundByKeyException.cs diff --git a/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs b/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs index 37608e3..58514b9 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs @@ -52,7 +52,58 @@ public void InequalityProperty() } [Test] - public void InequalityCountAndInequalityProperty() + public void InequalityCount_InequalityProperty_CompareByKey() + { + var a1 = new A + { + NonGenericEnumerable = new ArrayList + { + new B { Property1 = "Str2" }, + new B { Property1 = "Str1" } , + null + } + }; + + var a2 = new A + { + NonGenericEnumerable = new ArrayList + { + new B { Property1 = "Str1" } + } + }; + + var settings = new ComparisonSettings(); + + settings.List.Configure((ctx, options) => + { + options.CompareUnequalLists = true; + + options.CompareElementsByKey(keyOptions => + { + keyOptions.UseKey(nameof(B.Property1)); + }); + }); + + var comparer = new Comparer(settings); + var rootCtx = ComparisonContext.Create(); + var differences = comparer.CalculateDifferences(a1, a2, rootCtx).ToList(); + + CollectionAssert.IsNotEmpty(differences); + Assert.AreEqual("NonGenericEnumerable", differences.First().MemberPath); + Assert.AreEqual(DifferenceTypes.NumberOfElementsMismatch, differences.First().DifferenceType); + Assert.AreEqual("3", differences.First().Value1); + Assert.AreEqual("1", differences.First().Value2); + Assert.AreEqual(DifferenceTypes.ValueMismatch, differences[1].DifferenceType); + Assert.AreEqual("NonGenericEnumerable[0].Property1", differences[1].MemberPath); + Assert.AreEqual("Str2", differences[1].Value1); + Assert.AreEqual("Str1", differences[1].Value2); + Assert.AreEqual(DifferenceTypes.MissedElementInSecondObject, differences[2].DifferenceType); + Assert.AreEqual(true, differences[2].Value1 != string.Empty); + Assert.AreEqual(true, differences[2].Value2 == string.Empty); + } + + [Test] + public void InequalityCount_InequalityProperty_CompareByIndex() { var a1 = new A { diff --git a/ObjectsComparer/ObjectsComparer.Tests/DaNComparerTests.cs b/ObjectsComparer/ObjectsComparer.Tests/DaNComparerTests.cs deleted file mode 100644 index 6d62df4..0000000 --- a/ObjectsComparer/ObjectsComparer.Tests/DaNComparerTests.cs +++ /dev/null @@ -1,637 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Linq; -using NSubstitute; -using NUnit.Framework; -using ObjectsComparer.Tests.TestClasses; - -namespace ObjectsComparer.Tests -{ - public class Driver - { - } - - public class Car - { - //public IEnumerable Items1 { get; set; } - - //public IEnumerable Items2 { get; set; } - - public string[] Items3 { get; set; } - } - - class Person - { - public int Id { get; set; } - - public string PersonName { get; set; } - - public List
AddressList1 { get; set; } = new List
(); - - public List
AddressList2 { get; set; } = new List
(); - - public Person BestFriend { get; set; } - - public string[] ShortNames { get; set; } - - public IEnumerable LongNames { get; set; } - } - - class Address - { - public int Id { get; set; } - - public string Street { get; set; } - - public List CityList { get; set; } = new List(); - } - - class City - { - public int Id { get; set; } - - public string CityName { get; set; } - } - - [TestFixture] - public class DaNComparerTests - { - [Test] - public void TestOsoba() - { - Tuple osoby = LoadOsoby(); - var comparer = new Comparer(); - var rootContext = ComparisonContext.Create(); - var diffs = comparer.CalculateDifferences(osoby.Item1, osoby.Item2, rootContext).ToArray(); - } - - Tuple LoadOsoby() - { - var person1 = new Person - { - Id = 1, - PersonName = "Daniel", - ShortNames = new string[] { "shn1", "shn2", "shn3" }, - LongNames = new string[] { "ln1", "ln2", "ln3" } - }; - var pritel1 = new Person - { - Id = -1, - PersonName = "Paul" - }; - - person1.BestFriend = pritel1; - - var friend1Address = new Address - { - Id = 11, - Street = "White" - }; - person1.BestFriend.AddressList1.Add(friend1Address); - - var adr1 = new Address - { - Id = 2, - Street = "Red", - }; - var adr2 = new Address - { - Id = 3, - Street = "Yellow" - }; - var adr3 = new Address - { - Id = 4, - Street = "Rose" - }; - var addressList = new List
(new Address[] { adr1, adr2, adr3 }); - person1.AddressList1.AddRange(addressList); - - var person2 = new Person - { - Id = 1, - PersonName = "John", - ShortNames = new string[] { "shn1", "shn2", "shn3" }, - LongNames = new string[] { "ln1", "ln2", "ln3" } - }; - - var pritel2 = new Person - { - Id = -2, - PersonName = "Peter" - }; - - person2.BestFriend = pritel2; - - var adresaPritele2 = new Address - { - Id = 111, - Street = "Black" - }; - person2.BestFriend.AddressList1.Add(adresaPritele2); - - var adr4 = new Address - { - Id = 2, - Street = "Red" - }; - var adr5 = new Address - { - Id = 3, - Street = "Yellow" - }; - var adr6 = new Address - { - Id = 4, - Street = "Blue" - }; - var addressList2 = new List
(new Address[] { adr4, adr5, adr6 }); - person2.AddressList1.AddRange(addressList2); - - return new Tuple(person1, person2); - } - - public void Calc(T obj1, T obj2) - { - var x = ((object)obj1 ?? obj2).GetType(); - } - - public class SubClassA - { - public bool BoolProperty { get; set; } - } - - [Test] - public void TestBug() - { - var comparer = new Comparer(); - } - - [Test] - public void PropertyEquality() - { - var a1 = new A {IntProperty = 10, DateTimeProperty = new DateTime(2017, 1, 1), Property3 = 5}; - var a2 = new A {IntProperty = 10, DateTimeProperty = new DateTime(2017, 1, 1), Property3 = 8}; - var comparer = new Comparer(); - - var isEqual = comparer.Compare(a1, a2); - - Assert.IsTrue(isEqual); - } - - [Test] - public void PropertyInequality() - { - var date1 = new DateTime(2017, 1, 1); - var date2 = new DateTime(2017, 1, 2); - var a1 = new A {IntProperty = 10, DateTimeProperty = date1}; - var a2 = new A {IntProperty = 8, DateTimeProperty = date2}; - var comparer = new Comparer(); - - var differences = comparer.CalculateDifferences(a1, a2).ToList(); - - CollectionAssert.IsNotEmpty(differences); - Assert.AreEqual("IntProperty", differences[0].MemberPath); - Assert.AreEqual("10", differences[0].Value1); - Assert.AreEqual("8", differences[0].Value2); - Assert.AreEqual("DateTimeProperty", differences[1].MemberPath); - // ReSharper disable once SpecifyACultureInStringConversionExplicitly - Assert.AreEqual(date1.ToString(), differences[1].Value1); - // ReSharper disable once SpecifyACultureInStringConversionExplicitly - Assert.AreEqual(date2.ToString(), differences[1].Value2); - } - - [Test] - public void ReadOnlyPropertyEquality() - { - var a1 = new A(1.99); - var a2 = new A(1.99); - var comparer = new Comparer(); - - var isEqual = comparer.Compare(a1, a2); - - Assert.IsTrue(isEqual); - } - - [Test] - public void ReadOnlyPropertyInequality() - { - var a1 = new A(1.99); - var a2 = new A(0.89); - var comparer = new Comparer(); - - var differences = comparer.CalculateDifferences(a1, a2).ToList(); - - CollectionAssert.IsNotEmpty(differences); - Assert.AreEqual("ReadOnlyProperty", differences.First().MemberPath); - Assert.AreEqual("1.99", differences.First().Value1); - Assert.AreEqual("0.89", differences.First().Value2); - } - - [Test] - public void ProtectedProperty() - { - var a1 = new A(true); - var a2 = new A(false); - var comparer = new Comparer(); - - var isEqual = comparer.Compare(a1, a2); - - Assert.IsTrue(isEqual); - } - - [Test] - public void FieldEquality() - { - var a1 = new A {Field = 9}; - var a2 = new A {Field = 9}; - var comparer = new Comparer(); - - var isEqual = comparer.Compare(a1, a2); - - Assert.IsTrue(isEqual); - } - - [Test] - public void FieldInequality() - { - var a1 = new A {Field = 10}; - var a2 = new A {Field = 8}; - var comparer = new Comparer(); - - var differences = comparer.CalculateDifferences(a1, a2).ToList(); - - CollectionAssert.IsNotEmpty(differences); - Assert.AreEqual("Field", differences.First().MemberPath); - Assert.AreEqual("10", differences.First().Value1); - Assert.AreEqual("8", differences.First().Value2); - } - - [Test] - public void ReadOnlyFieldEquality() - { - var a1 = new A("Str1"); - var a2 = new A("Str1"); - var comparer = new Comparer(); - - var isEqual = comparer.Compare(a1, a2); - - Assert.IsTrue(isEqual); - } - - [Test] - public void ReadOnlyFieldInequality() - { - var a1 = new A("Str1"); - var a2 = new A("Str2"); - var comparer = new Comparer(); - - var differences = comparer.CalculateDifferences(a1, a2).ToList(); - - CollectionAssert.IsNotEmpty(differences); - Assert.AreEqual("ReadOnlyField", differences.First().MemberPath); - Assert.AreEqual("Str1", differences.First().Value1); - Assert.AreEqual("Str2", differences.First().Value2); - } - - [Test] - public void ProtectedField() - { - var a1 = new A(5); - var a2 = new A(6); - var comparer = new Comparer(); - - var isEqual = comparer.Compare(a1, a2); - - Assert.IsTrue(isEqual); - } - - [Test] - public void ClassPropertyEquality() - { - var a1 = new A {ClassB = new B {Property1 = "Str1"}}; - var a2 = new A {ClassB = new B {Property1 = "Str1"}}; - var comparer = new Comparer(); - - var isEqual = comparer.Compare(a1, a2); - - Assert.IsTrue(isEqual); - } - - [Test] - public void ClassPropertyInequality() - { - var a1 = new A {ClassB = new B {Property1 = "Str1"}}; - var a2 = new A {ClassB = new B {Property1 = "Str2"}}; - var comparer = new Comparer(); - - var differences = comparer.CalculateDifferences(a1, a2).ToList(); - - CollectionAssert.IsNotEmpty(differences); - Assert.AreEqual("ClassB.Property1", differences.First().MemberPath); - Assert.AreEqual("Str1", differences.First().Value1); - Assert.AreEqual("Str2", differences.First().Value2); - } - - [Test] - public void ClassPropertyInequalityFirstNull() - { - var a1 = new A(); - var a2 = new A {ClassB = new B {Property1 = "Str2"}}; - var comparer = new Comparer(); - - var differences = comparer.CalculateDifferences(a1, a2).ToList(); - - CollectionAssert.IsNotEmpty(differences); - Assert.AreEqual("ClassB", differences.First().MemberPath); - Assert.AreEqual("", differences.First().Value1); - Assert.AreEqual(a2.ClassB.ToString(), differences.First().Value2); - } - - [Test] - public void ClassPropertyInequalitySecondNull() - { - var a1 = new A {ClassB = new B {Property1 = "Str2"}}; - var a2 = new A(); - var comparer = new Comparer(); - - var differences = comparer.CalculateDifferences(a1, a2).ToList(); - - CollectionAssert.IsNotEmpty(differences); - Assert.AreEqual("ClassB", differences.First().MemberPath); - Assert.AreEqual(a1.ClassB.ToString(), differences.First().Value1); - Assert.AreEqual("", differences.First().Value2); - } - - [Test] - public void NoRecursiveComparison() - { - var a1 = new A {ClassB = new B {Property1 = "Str1"}}; - var a2 = new A {ClassB = new B {Property1 = "Str2"}}; - var comparer = new Comparer(new ComparisonSettings {RecursiveComparison = false}); - - var isEqual = comparer.Compare(a1, a2); - - Assert.IsTrue(isEqual); - } - - [Test] - public void InterfacePropertyEquality() - { - var a1 = new A {IntefaceProperty = new TestInterfaceImplementation1 {Property = "Str1"}}; - var a2 = new A - { - IntefaceProperty = new TestInterfaceImplementation2 {Property = "Str1", AnotherProperty = 50} - }; - var comparer = new Comparer(); - - var isEqual = comparer.Compare(a1, a2); - - Assert.IsTrue(isEqual); - } - - [Test] - public void InterfacePropertyInequality() - { - var a1 = new A {IntefaceProperty = new TestInterfaceImplementation1 {Property = "Str1"}}; - var a2 = new A - { - IntefaceProperty = new TestInterfaceImplementation2 {Property = "Str2", AnotherProperty = 50} - }; - var comparer = new Comparer(); - - var differences = comparer.CalculateDifferences(a1, a2).ToList(); - - CollectionAssert.IsNotEmpty(differences); - Assert.AreEqual("IntefaceProperty.Property", differences.First().MemberPath); - Assert.AreEqual("Str1", differences.First().Value1); - Assert.AreEqual("Str2", differences.First().Value2); - } - - [Test] - public void StructPropertyEquality() - { - var a1 = new A {StructProperty = new TestStruct {FieldA = "FA", FieldB = "FB"}}; - var a2 = new A {StructProperty = new TestStruct {FieldA = "FA", FieldB = "FB"}}; - var comparer = new Comparer(); - - var isEqual = comparer.Compare(a1, a2); - - Assert.IsTrue(isEqual); - } - - [Test] - public void StructPropertyInequality() - { - var a1 = new A {StructProperty = new TestStruct {FieldA = "FA", FieldB = "FB"}}; - var a2 = new A {StructProperty = new TestStruct {FieldA = "FA", FieldB = "FBB"}}; - var comparer = new Comparer(); - - var differences = comparer.CalculateDifferences(a1, a2).ToList(); - - CollectionAssert.IsNotEmpty(differences); - Assert.AreEqual("StructProperty.FieldB", differences.First().MemberPath); - Assert.AreEqual("FB", differences.First().Value1); - Assert.AreEqual("FBB", differences.First().Value2); - } - - [Test] - public void EnumPropertyEquality() - { - var a1 = new A {EnumProperty = TestEnum.Value1}; - var a2 = new A {EnumProperty = TestEnum.Value1}; - var comparer = new Comparer(); - - var isEqual = comparer.Compare(a1, a2); - - Assert.IsTrue(isEqual); - } - - [Test] - public void EnumPropertyInequality() - { - var a1 = new A {EnumProperty = TestEnum.Value1}; - var a2 = new A {EnumProperty = TestEnum.Value2}; - var comparer = new Comparer(); - - var differences = comparer.CalculateDifferences(a1, a2).ToList(); - - CollectionAssert.IsNotEmpty(differences); - Assert.AreEqual("EnumProperty", differences.First().MemberPath); - Assert.AreEqual("Value1", differences.First().Value1); - Assert.AreEqual("Value2", differences.First().Value2); - } - - [Test] - public void SetDefaultComparer() - { - var a1 = new A {TestProperty1 = "ABC", Field = 5}; - var a2 = new A {TestProperty1 = "BCD", Field = 6}; - var comparer = new Comparer(); - var valueComparer = Substitute.For(); - valueComparer.Compare(Arg.Any(), Arg.Any(), Arg.Any()).Returns(true); - comparer.SetDefaultComparer(valueComparer); - - var isEqual = comparer.Compare(a1, a2); - - Assert.IsTrue(isEqual); - valueComparer.Received().Compare(Arg.Any(), Arg.Any(), Arg.Any()); - } - - [Test] - public void SetDefaultComparerNullException() - { - var comparer = new Comparer(); - - Assert.Throws(() => comparer.SetDefaultComparer(null)); - } - - [Test] - public void InheritedAndBaseClassInequality() - { - var a1 = new A {ClassB = new B {Property1 = "Str1"}}; - var a2 = new A {ClassB = new InheritedFromB {Property1 = "Str2", NewProperty = "SomeValue"}}; - var comparer = new Comparer(); - - var isEqual = comparer.Compare(a1, a2, out var differencesEnum); - var differences = differencesEnum.ToList(); - - Assert.IsFalse(isEqual); - CollectionAssert.IsNotEmpty(differences); - Assert.AreEqual(1, differences.Count); - Assert.AreEqual("ClassB.Property1", differences.First().MemberPath); - Assert.AreEqual("Str1", differences.First().Value1); - Assert.AreEqual("Str2", differences.First().Value2); - } - - [Test] - public void InheritedAndBaseClassEquality() - { - var a1 = new A {ClassB = new B {Property1 = "Str1"}}; - var a2 = new A {ClassB = new InheritedFromB {Property1 = "Str1", NewProperty = "SomeValue"}}; - var comparer = new Comparer(); - - var isEqual = comparer.Compare(a1, a2); - - Assert.IsTrue(isEqual); - } - - [TestCase(FlagsEnum.Flag1 | FlagsEnum.Flag2, FlagsEnum.Flag1 | FlagsEnum.Flag3)] - [TestCase(FlagsEnum.Flag2, FlagsEnum.Flag3)] - [TestCase(FlagsEnum.Flag1, FlagsEnum.Flag1 | FlagsEnum.Flag2)] - public void FlagsInequality(FlagsEnum flags1, FlagsEnum flags2) - { - var a1 = new A {Flags = flags1}; - var a2 = new A {Flags = flags2}; - var comparer = new Comparer(); - - var isEqual = comparer.Compare(a1, a2, out var differencesEnum); - var differences = differencesEnum.ToList(); - - Assert.IsFalse(isEqual); - CollectionAssert.IsNotEmpty(differences); - Assert.AreEqual(1, differences.Count); - Assert.AreEqual("Flags", differences.First().MemberPath); - Assert.AreEqual(flags1.ToString(), differences.First().Value1); - Assert.AreEqual(flags2.ToString(), differences.First().Value2); - } - - [TestCase(FlagsEnum.Flag1 | FlagsEnum.Flag2, FlagsEnum.Flag1 | FlagsEnum.Flag2)] - [TestCase(FlagsEnum.Flag2, FlagsEnum.Flag2)] - public void FlagsEquality(FlagsEnum flags1, FlagsEnum flags2) - { - var a1 = new A {Flags = flags1}; - var a2 = new A {Flags = flags2}; - var comparer = new Comparer(); - - var isEqual = comparer.Compare(a1, a2); - - Assert.IsTrue(isEqual); - } - - [Test] - public void TypePropertyEquality() - { - var a1 = new A {TypeProperty = typeof(string)}; - var a2 = new A {TypeProperty = typeof(string)}; - var comparer = new Comparer(); - - var isEqual = comparer.Compare(a1, a2); - - Assert.IsTrue(isEqual); - } - - [Test] - public void TypePropertyInequality() - { - var a1 = new A {TypeProperty = typeof(string)}; - var a2 = new A {TypeProperty = typeof(int)}; - var comparer = new Comparer(); - - var isEqual = comparer.Compare(a1, a2, out var differencesEnum); - var differences = differencesEnum.ToList(); - - Assert.IsFalse(isEqual); - CollectionAssert.IsNotEmpty(differences); - Assert.AreEqual(1, differences.Count); - Assert.AreEqual("TypeProperty", differences.First().MemberPath); - } - - [Test] - public void TimeSpanEquality() - { - var a1 = new TimeSpan(123456789); - var a2 = new TimeSpan(123456789); - var comparer = new Comparer(); - - var isEqual = comparer.Compare(a1, a2); - - Assert.IsTrue(isEqual); - } - - [Test] - public void TimeSpanInequality() - { - var a1 = new TimeSpan(123456789); - var a2 = new TimeSpan(123456788); - var comparer = new Comparer(); - - var isEqual = comparer.Compare(a1, a2, out var differencesEnum); - var differences = differencesEnum.ToList(); - - Assert.IsFalse(isEqual); - CollectionAssert.IsNotEmpty(differences); - Assert.AreEqual(1, differences.Count); - Assert.AreEqual(string.Empty, differences.First().MemberPath); - } - - [Test] - public void GuidEquality() - { - var a1 = new Guid("01234567890123456789012345678912"); - var a2 = new Guid("01234567890123456789012345678912"); - var comparer = new Comparer(); - - var isEqual = comparer.Compare(a1, a2); - - Assert.IsTrue(isEqual); - } - - [Test] - public void GuidInequality() - { - var a1 = new Guid("01234567890123456789012345678912"); - var a2 = new Guid("01234567890123456789012345678913"); - var comparer = new Comparer(); - - var isEqual = comparer.Compare(a1, a2, out var differencesEnum); - var differences = differencesEnum.ToList(); - - Assert.IsFalse(isEqual); - CollectionAssert.IsNotEmpty(differences); - Assert.AreEqual(1, differences.Count); - Assert.AreEqual(string.Empty, differences.First().MemberPath); - } - } -} \ No newline at end of file diff --git a/ObjectsComparer/ObjectsComparer/CompareElementsByKeyOptions.cs b/ObjectsComparer/ObjectsComparer/CompareElementsByKeyOptions.cs index adde806..e58df28 100644 --- a/ObjectsComparer/ObjectsComparer/CompareElementsByKeyOptions.cs +++ b/ObjectsComparer/ObjectsComparer/CompareElementsByKeyOptions.cs @@ -19,7 +19,7 @@ public class CompareElementsByKeyOptions public bool ThrowKeyNotFound { get; set; } = true; /// - /// If null, the elements will be compared by their index, otherwise by key. Default value = null. + /// If null, the elements should be compared by their index, otherwise by key. Default value = null. /// internal Func KeyProvider { get; private set; } = null; @@ -44,7 +44,7 @@ public void UseKey(string key, bool caseSensitive = false) /// /// Compares list elements by key. It will try to find one of the public properties specified by argument , in that order. /// - public void UseKey(string[] keys, bool caseSensitive = true) + public void UseKey(string[] keys, bool caseSensitive = false) { if (keys is null) { @@ -88,7 +88,7 @@ static object GetKeyValue(object instance, bool caseSensitive, params string[] k { if (instance != null) { - BindingFlags bindingAttr = BindingFlags.Public; + BindingFlags bindingAttr = BindingFlags.Public | BindingFlags.Instance; if (caseSensitive == false) { bindingAttr |= BindingFlags.IgnoreCase; diff --git a/ObjectsComparer/ObjectsComparer/Comparer~1.cs b/ObjectsComparer/ObjectsComparer/Comparer~1.cs index 752fa37..8bc6cb2 100644 --- a/ObjectsComparer/ObjectsComparer/Comparer~1.cs +++ b/ObjectsComparer/ObjectsComparer/Comparer~1.cs @@ -126,7 +126,7 @@ IEnumerable CalculateDifferences(T obj1, T obj2, MemberInfo memberIn continue; } - var context = ComparisonContext.Create(currentMember: member, ancestor: comparisonContext); + var context = ComparisonContext.Create(member: member, ancestor: comparisonContext); var valueComparer = DefaultValueComparer; var hasCustomComparer = false; diff --git a/ObjectsComparer/ObjectsComparer/ComparisonContext.cs b/ObjectsComparer/ObjectsComparer/ComparisonContext.cs index fa25993..a6cf5b7 100644 --- a/ObjectsComparer/ObjectsComparer/ComparisonContext.cs +++ b/ObjectsComparer/ObjectsComparer/ComparisonContext.cs @@ -44,9 +44,15 @@ private ComparisonContext(MemberInfo currentMember) /// public ReadOnlyCollection Descendants => _descendants.AsReadOnly(); - internal static ComparisonContext Create(MemberInfo currentMember = null, ComparisonContext ancestor = null) + /// + /// + /// + /// See . + /// See . + /// + internal static ComparisonContext Create(MemberInfo member = null, ComparisonContext ancestor = null) { - var context = new ComparisonContext(currentMember); + var context = new ComparisonContext(member); if (ancestor != null) { diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs index f9de3ad..62061f6 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs @@ -98,6 +98,9 @@ private IEnumerable CalculateDifferencesByKey(object[] array1, objec foreach (var element1 in array1) { + //Comparison context representing the list element never has a Member. Its ancestor is the context representing the list. + var elementComparisonContext = ComparisonContext.Create(member: null, ancestor: listComparisonContext); + if (element1 == null) { if (array2.Any(elm2 => elm2 == null)) @@ -105,7 +108,7 @@ private IEnumerable CalculateDifferencesByKey(object[] array1, objec continue; } - yield return new Difference("[Key = NULL]", string.Empty, string.Empty, DifferenceTypes.MissedElementInSecondObject); + yield return new Difference("[NULL]", string.Empty, string.Empty, DifferenceTypes.MissedElementInSecondObject); continue; } @@ -115,10 +118,59 @@ private IEnumerable CalculateDifferencesByKey(object[] array1, objec { if (keyOptions.ThrowKeyNotFound) { - throw new ElementNotFoundByKeyException(); + throw new ElementKeyNotFoundException(element1); + } + + continue; + } + + if (array2.Any(elm2 => object.Equals(element1Key, keyOptions.KeyProvider(elm2)))) + { + var element2 = array2.First(elm2 => object.Equals(element1Key, keyOptions.KeyProvider(elm2))); + var comparer = Factory.GetObjectsComparer(element1.GetType(), Settings, this); + + foreach (var failure in comparer.CalculateDifferences(element1.GetType(), element1, element2, elementComparisonContext)) + { + yield return failure.InsertPath($"[{element1Key}]"); + } + } + else + { + var valueComparer1 = OverridesCollection.GetComparer(element1.GetType()) ?? DefaultValueComparer; + yield return new Difference($"[{element1Key}]", valueComparer1.ToString(element1), string.Empty, DifferenceTypes.MissedElementInSecondObject); + } + } + + foreach (var element2 in array2) + { + if (element2 == null) + { + if (array1.Any(elm1 => elm1 == null)) + { + continue; + } + + yield return new Difference("[NULL]", string.Empty, string.Empty, DifferenceTypes.MissedElementInFirstObject); + continue; + } + + var element2Key = keyOptions.KeyProvider(element2); + + if (element2Key == null) + { + if (keyOptions.ThrowKeyNotFound) + { + throw new ElementKeyNotFoundException(element2); } + continue; } + + if (array1.Any(elm1 => object.Equals(element2Key, keyOptions.KeyProvider(elm1))) == false) + { + var valueComparer2 = OverridesCollection.GetComparer(element2.GetType()) ?? DefaultValueComparer; + yield return new Difference($"[{element2Key}]", valueComparer2.ToString(element2), string.Empty, DifferenceTypes.MissedElementInFirstObject); + } } Debug.WriteLine(nameof(CalculateDifferencesByKey)); @@ -135,8 +187,8 @@ private IEnumerable CalculateDifferencesByIndex(object[] array1, obj //ToDo Extract type for (var i = 0; i < smallerCount; i++) { - //Context representing the element has no member. Its ancestor is the context representing the list. - var elementComparisonContext = ComparisonContext.Create(currentMember: null, ancestor: listComparisonContext); + //Context representing the list element never has a Member. Its ancestor is the context representing the list. + var elementComparisonContext = ComparisonContext.Create(member: null, ancestor: listComparisonContext); if (array1[i] == null && array2[i] == null) { @@ -172,7 +224,7 @@ private IEnumerable CalculateDifferencesByIndex(object[] array1, obj } } - //Add a "missed element" difference for each element that is in array1 and is not in array2, or vice versa. The positions of value1 and value2 are respected in Difference instance. + //Add a "missed element" difference for each element that is in array1 and is not in array2 or vice versa. The positions of value1 and value2 are preserved in the Difference instance. if (array1Count != array2Count) { var largerArray = array1Count > array2Count ? array1 : array2; diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer~1.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer~1.cs index c0ecb49..3271f07 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer~1.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer~1.cs @@ -69,7 +69,7 @@ public IEnumerable CalculateDifferences(Type type, object obj1, obje for (var i = 0; i < list2.Count; i++) { //List item has not got its MemberInfo, but has got its ancestor - list. - var context = ComparisonContext.Create(currentMember: null, ancestor: comparisonContext); + var context = ComparisonContext.Create(member: null, ancestor: comparisonContext); foreach (var failure in _comparer.CalculateDifferences(list1[i], list2[i], context)) { diff --git a/ObjectsComparer/ObjectsComparer/Exceptions/ElementKeyNotFoundException.cs b/ObjectsComparer/ObjectsComparer/Exceptions/ElementKeyNotFoundException.cs new file mode 100644 index 0000000..5ddb00e --- /dev/null +++ b/ObjectsComparer/ObjectsComparer/Exceptions/ElementKeyNotFoundException.cs @@ -0,0 +1,29 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace ObjectsComparer.Exceptions +{ + /// + /// Depending on the configuration, the exception is thrown if the key provider does not supply the key for list element . For more information see and . + /// + public class ElementKeyNotFoundException : Exception + { + const string ElementKeyNotFoundExceptionMsg = "Element key not found."; + + /// + /// See . + /// + /// An element that is missing a key. + /// + internal ElementKeyNotFoundException(object keylessElement, string message = ElementKeyNotFoundExceptionMsg) : base(message) + { + KeylessElement = keylessElement ?? throw new ArgumentNullException(nameof(keylessElement)); + } + + /// + /// An element that is missing a key. + /// + public object KeylessElement { get; } + } +} diff --git a/ObjectsComparer/ObjectsComparer/Exceptions/ElementNotFoundByKeyException.cs b/ObjectsComparer/ObjectsComparer/Exceptions/ElementNotFoundByKeyException.cs deleted file mode 100644 index f6ee623..0000000 --- a/ObjectsComparer/ObjectsComparer/Exceptions/ElementNotFoundByKeyException.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace ObjectsComparer.Exceptions -{ - public class ElementNotFoundByKeyException : Exception - { - - } -} diff --git a/ObjectsComparer/ObjectsComparer/ListConfigurationOptions.cs b/ObjectsComparer/ObjectsComparer/ListConfigurationOptions.cs index 96d66be..d100446 100644 --- a/ObjectsComparer/ObjectsComparer/ListConfigurationOptions.cs +++ b/ObjectsComparer/ObjectsComparer/ListConfigurationOptions.cs @@ -13,7 +13,7 @@ public class ListConfigurationOptions } /// - /// Whether to compare elements of the lists even if their number differs ( will always be logged). Default value = false. + /// Whether to compare elements of the lists even if their number differs. Regardless of the value, respective difference of type will always be logged. Default value = false. /// public bool CompareUnequalLists { get; set; } = false; From 39bbc99139cf312192d390192121a8f90e5dcfd4 Mon Sep 17 00:00:00 2001 From: "ASD\\nemec" Date: Wed, 13 Oct 2021 14:44:01 +0200 Subject: [PATCH 022/181] Edit InequalityCount_InequalityProperty_CompareByKey. --- .../Comparer_NonGenericEnumerableTests.cs | 22 ++++++++++--------- .../CompareElementsByKeyOptions.cs | 4 +++- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs b/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs index 58514b9..5092a44 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs @@ -2,6 +2,7 @@ using System.Linq; using NUnit.Framework; using ObjectsComparer.Tests.TestClasses; +using ObjectsComparer.Utils; namespace ObjectsComparer.Tests { @@ -51,6 +52,8 @@ public void InequalityProperty() Assert.AreEqual("Str3", differences.First().Value2); } + static string GetMyString() => "xxx"; + [Test] public void InequalityCount_InequalityProperty_CompareByKey() { @@ -72,16 +75,15 @@ public void InequalityCount_InequalityProperty_CompareByKey() } }; + //ComparisonContext.BelongsTo(): Returns true if current context's Member belongs to the member or if it is the member itself. + var r = PropertyHelper.GetMemberInfo(() => new B().Property1); + var settings = new ComparisonSettings(); settings.List.Configure((ctx, options) => { options.CompareUnequalLists = true; - - options.CompareElementsByKey(keyOptions => - { - keyOptions.UseKey(nameof(B.Property1)); - }); + options.CompareElementsByKey(keyOptions => keyOptions.UseKey(nameof(B.Property1))); }); var comparer = new Comparer(settings); @@ -93,12 +95,12 @@ public void InequalityCount_InequalityProperty_CompareByKey() Assert.AreEqual(DifferenceTypes.NumberOfElementsMismatch, differences.First().DifferenceType); Assert.AreEqual("3", differences.First().Value1); Assert.AreEqual("1", differences.First().Value2); - Assert.AreEqual(DifferenceTypes.ValueMismatch, differences[1].DifferenceType); - Assert.AreEqual("NonGenericEnumerable[0].Property1", differences[1].MemberPath); - Assert.AreEqual("Str2", differences[1].Value1); - Assert.AreEqual("Str1", differences[1].Value2); + Assert.AreEqual(DifferenceTypes.MissedElementInSecondObject, differences[1].DifferenceType); + Assert.AreEqual("NonGenericEnumerable[Str2]", differences[1].MemberPath); + Assert.AreEqual(false, string.IsNullOrWhiteSpace(differences[1].Value1)); + Assert.AreEqual(true, string.IsNullOrWhiteSpace(differences[1].Value2)); Assert.AreEqual(DifferenceTypes.MissedElementInSecondObject, differences[2].DifferenceType); - Assert.AreEqual(true, differences[2].Value1 != string.Empty); + Assert.AreEqual("NonGenericEnumerable[NULL]", differences[2].MemberPath); Assert.AreEqual(true, differences[2].Value2 == string.Empty); } diff --git a/ObjectsComparer/ObjectsComparer/CompareElementsByKeyOptions.cs b/ObjectsComparer/ObjectsComparer/CompareElementsByKeyOptions.cs index e58df28..00608db 100644 --- a/ObjectsComparer/ObjectsComparer/CompareElementsByKeyOptions.cs +++ b/ObjectsComparer/ObjectsComparer/CompareElementsByKeyOptions.cs @@ -1,6 +1,7 @@ using System; using System.Linq; using System.Reflection; +using ObjectsComparer.Exceptions; namespace ObjectsComparer { @@ -14,7 +15,8 @@ public class CompareElementsByKeyOptions internal static CompareElementsByKeyOptions Default() => new CompareElementsByKeyOptions(); /// - /// If value = false and element key will not be found, entire element will excluded from comparison. If value = true and element key will not be found, an exception of type will be raised. + /// If value = false and element key will not be found, the element will be excluded from comparison and no difference will be logged. If value = true and element key will not be found, an exception of type will be thrown. + /// Default value = true. /// public bool ThrowKeyNotFound { get; set; } = true; From 2f800cd8032b14278ac049a0f9f3f7846973718d Mon Sep 17 00:00:00 2001 From: "ASD\\nemec" Date: Thu, 14 Oct 2021 14:37:16 +0200 Subject: [PATCH 023/181] Add operation InequalityCount_InequalityProperty_CompareByKey2_Reverse_Order. Corrent string.empty at value1. --- .../Comparer_NonGenericEnumerableTests.cs | 53 ++++++++++++++++++- .../CustomComparers/EnumerablesComparer.cs | 2 +- 2 files changed, 53 insertions(+), 2 deletions(-) diff --git a/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs b/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs index 5092a44..cc496b6 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs @@ -76,7 +76,7 @@ public void InequalityCount_InequalityProperty_CompareByKey() }; //ComparisonContext.BelongsTo(): Returns true if current context's Member belongs to the member or if it is the member itself. - var r = PropertyHelper.GetMemberInfo(() => new B().Property1); + //var r = PropertyHelper.GetMemberInfo(() => new B().Property1); var settings = new ComparisonSettings(); @@ -104,6 +104,57 @@ public void InequalityCount_InequalityProperty_CompareByKey() Assert.AreEqual(true, differences[2].Value2 == string.Empty); } + [Test] + public void InequalityCount_InequalityProperty_CompareByKey2_Reverse_Order() + { + var a1 = new A + { + NonGenericEnumerable = new ArrayList + { + new B { Property1 = "Str2" }, + new B { Property1 = "Str1" } , + null + } + }; + + var a2 = new A + { + NonGenericEnumerable = new ArrayList + { + new B { Property1 = "Str1" } + } + }; + + //ComparisonContext.BelongsTo(): Returns true if current context's Member belongs to the member or if it is the member itself. + //var r = PropertyHelper.GetMemberInfo(() => new B().Property1); + + var settings = new ComparisonSettings(); + + settings.List.Configure((ctx, options) => + { + options.CompareUnequalLists = true; + options.CompareElementsByKey(keyOptions => keyOptions.UseKey(nameof(B.Property1))); + }); + + var comparer = new Comparer(settings); + var rootCtx = ComparisonContext.Create(); + var differences = comparer.CalculateDifferences(a2, a1, rootCtx).ToList(); + + CollectionAssert.IsNotEmpty(differences); + Assert.AreEqual("NonGenericEnumerable", differences.First().MemberPath); + Assert.AreEqual(DifferenceTypes.NumberOfElementsMismatch, differences.First().DifferenceType); + Assert.AreEqual("3", differences.First().Value1); + Assert.AreEqual("1", differences.First().Value2); + Assert.AreEqual(DifferenceTypes.MissedElementInSecondObject, differences[1].DifferenceType); + Assert.AreEqual("NonGenericEnumerable[Str2]", differences[1].MemberPath); + Assert.AreEqual(false, string.IsNullOrWhiteSpace(differences[1].Value1)); + Assert.AreEqual(true, string.IsNullOrWhiteSpace(differences[1].Value2)); + Assert.AreEqual(DifferenceTypes.MissedElementInSecondObject, differences[2].DifferenceType); + Assert.AreEqual("NonGenericEnumerable[NULL]", differences[2].MemberPath); + Assert.AreEqual(true, differences[2].Value2 == string.Empty); + } + + [Test] public void InequalityCount_InequalityProperty_CompareByIndex() { diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs index 62061f6..8af92df 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs @@ -169,7 +169,7 @@ private IEnumerable CalculateDifferencesByKey(object[] array1, objec if (array1.Any(elm1 => object.Equals(element2Key, keyOptions.KeyProvider(elm1))) == false) { var valueComparer2 = OverridesCollection.GetComparer(element2.GetType()) ?? DefaultValueComparer; - yield return new Difference($"[{element2Key}]", valueComparer2.ToString(element2), string.Empty, DifferenceTypes.MissedElementInFirstObject); + yield return new Difference($"[{element2Key}]", string.Empty, valueComparer2.ToString(element2), DifferenceTypes.MissedElementInFirstObject); } } From 5c0004584544f8c1960b2280b6bbd791eb31d243 Mon Sep 17 00:00:00 2001 From: Daniel Nemec Date: Sat, 16 Oct 2021 23:04:54 +0200 Subject: [PATCH 024/181] Ensure element context for each unique element occcurence. --- .../Comparer_NonGenericEnumerableTests.cs | 37 ++++++++++--------- .../CustomComparers/EnumerablesComparer.cs | 18 +++++---- 2 files changed, 30 insertions(+), 25 deletions(-) diff --git a/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs b/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs index cc496b6..544ace7 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs @@ -87,8 +87,8 @@ public void InequalityCount_InequalityProperty_CompareByKey() }); var comparer = new Comparer(settings); - var rootCtx = ComparisonContext.Create(); - var differences = comparer.CalculateDifferences(a1, a2, rootCtx).ToList(); + var rootContext = ComparisonContext.Create(); + var differences = comparer.CalculateDifferences(a1, a2, rootContext).ToList(); CollectionAssert.IsNotEmpty(differences); Assert.AreEqual("NonGenericEnumerable", differences.First().MemberPath); @@ -105,15 +105,13 @@ public void InequalityCount_InequalityProperty_CompareByKey() } [Test] - public void InequalityCount_InequalityProperty_CompareByKey2_Reverse_Order() + public void InequalityCount_InequalityProperty_CompareByKey2() { var a1 = new A { NonGenericEnumerable = new ArrayList { - new B { Property1 = "Str2" }, - new B { Property1 = "Str1" } , - null + new B { Property1 = "Str1" } } }; @@ -121,10 +119,12 @@ public void InequalityCount_InequalityProperty_CompareByKey2_Reverse_Order() { NonGenericEnumerable = new ArrayList { - new B { Property1 = "Str1" } + new B { Property1 = "Str2" }, + new B { Property1 = "Str1" } , + null } }; - + //ComparisonContext.BelongsTo(): Returns true if current context's Member belongs to the member or if it is the member itself. //var r = PropertyHelper.GetMemberInfo(() => new B().Property1); @@ -137,21 +137,22 @@ public void InequalityCount_InequalityProperty_CompareByKey2_Reverse_Order() }); var comparer = new Comparer(settings); - var rootCtx = ComparisonContext.Create(); - var differences = comparer.CalculateDifferences(a2, a1, rootCtx).ToList(); + var rootContext = ComparisonContext.Create(); + var differences = comparer.CalculateDifferences(a1, a2, rootContext).ToList(); CollectionAssert.IsNotEmpty(differences); Assert.AreEqual("NonGenericEnumerable", differences.First().MemberPath); Assert.AreEqual(DifferenceTypes.NumberOfElementsMismatch, differences.First().DifferenceType); - Assert.AreEqual("3", differences.First().Value1); - Assert.AreEqual("1", differences.First().Value2); - Assert.AreEqual(DifferenceTypes.MissedElementInSecondObject, differences[1].DifferenceType); + Assert.AreEqual("1", differences.First().Value1); + Assert.AreEqual("3", differences.First().Value2); + Assert.AreEqual(DifferenceTypes.MissedElementInFirstObject, differences[1].DifferenceType); Assert.AreEqual("NonGenericEnumerable[Str2]", differences[1].MemberPath); - Assert.AreEqual(false, string.IsNullOrWhiteSpace(differences[1].Value1)); - Assert.AreEqual(true, string.IsNullOrWhiteSpace(differences[1].Value2)); - Assert.AreEqual(DifferenceTypes.MissedElementInSecondObject, differences[2].DifferenceType); + Assert.AreEqual(true, string.IsNullOrWhiteSpace(differences[1].Value1)); + Assert.AreEqual(false, string.IsNullOrWhiteSpace(differences[1].Value2)); + Assert.AreEqual(DifferenceTypes.MissedElementInFirstObject, differences[2].DifferenceType); Assert.AreEqual("NonGenericEnumerable[NULL]", differences[2].MemberPath); Assert.AreEqual(true, differences[2].Value2 == string.Empty); + Assert.AreEqual(true, differences[2].Value2 == string.Empty); } @@ -184,8 +185,8 @@ public void InequalityCount_InequalityProperty_CompareByIndex() }); var comparer = new Comparer(settings); - var rootCtx = ComparisonContext.Create(); - var differences = comparer.CalculateDifferences(a1, a2, rootCtx).ToList(); + var rootContext = ComparisonContext.Create(); + var differences = comparer.CalculateDifferences(a1, a2, rootContext).ToList(); CollectionAssert.IsNotEmpty(differences); Assert.AreEqual("NonGenericEnumerable", differences.First().MemberPath); diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs index 8af92df..fbb2e90 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs @@ -98,8 +98,7 @@ private IEnumerable CalculateDifferencesByKey(object[] array1, objec foreach (var element1 in array1) { - //Comparison context representing the list element never has a Member. Its ancestor is the context representing the list. - var elementComparisonContext = ComparisonContext.Create(member: null, ancestor: listComparisonContext); + var elementContext = ComparisonContext.Create(member: null, ancestor: listComparisonContext); if (element1 == null) { @@ -129,7 +128,7 @@ private IEnumerable CalculateDifferencesByKey(object[] array1, objec var element2 = array2.First(elm2 => object.Equals(element1Key, keyOptions.KeyProvider(elm2))); var comparer = Factory.GetObjectsComparer(element1.GetType(), Settings, this); - foreach (var failure in comparer.CalculateDifferences(element1.GetType(), element1, element2, elementComparisonContext)) + foreach (var failure in comparer.CalculateDifferences(element1.GetType(), element1, element2, elementContext)) { yield return failure.InsertPath($"[{element1Key}]"); } @@ -150,6 +149,8 @@ private IEnumerable CalculateDifferencesByKey(object[] array1, objec continue; } + var elementContext = ComparisonContext.Create(member: null, ancestor: listComparisonContext); + yield return new Difference("[NULL]", string.Empty, string.Empty, DifferenceTypes.MissedElementInFirstObject); continue; } @@ -168,6 +169,8 @@ private IEnumerable CalculateDifferencesByKey(object[] array1, objec if (array1.Any(elm1 => object.Equals(element2Key, keyOptions.KeyProvider(elm1))) == false) { + var elementContext = ComparisonContext.Create(member: null, ancestor: listComparisonContext); + var valueComparer2 = OverridesCollection.GetComparer(element2.GetType()) ?? DefaultValueComparer; yield return new Difference($"[{element2Key}]", string.Empty, valueComparer2.ToString(element2), DifferenceTypes.MissedElementInFirstObject); } @@ -187,8 +190,7 @@ private IEnumerable CalculateDifferencesByIndex(object[] array1, obj //ToDo Extract type for (var i = 0; i < smallerCount; i++) { - //Context representing the list element never has a Member. Its ancestor is the context representing the list. - var elementComparisonContext = ComparisonContext.Create(member: null, ancestor: listComparisonContext); + var elementContext = ComparisonContext.Create(member: null, ancestor: listComparisonContext); if (array1[i] == null && array2[i] == null) { @@ -218,19 +220,21 @@ private IEnumerable CalculateDifferencesByIndex(object[] array1, obj var comparer = Factory.GetObjectsComparer(array1[i].GetType(), Settings, this); - foreach (var failure in comparer.CalculateDifferences(array1[i].GetType(), array1[i], array2[i], elementComparisonContext)) + foreach (var failure in comparer.CalculateDifferences(array1[i].GetType(), array1[i], array2[i], elementContext)) { yield return failure.InsertPath($"[{i}]"); } } - //Add a "missed element" difference for each element that is in array1 and is not in array2 or vice versa. The positions of value1 and value2 are preserved in the Difference instance. + //Add a "missed element" difference for each element that is in array1 that and is not in array2 or vice versa. The positions of value1 and value2 are preserved in the Difference instance. if (array1Count != array2Count) { var largerArray = array1Count > array2Count ? array1 : array2; for (int i = smallerCount; i < largerArray.Length; i++) { + var elementContext = ComparisonContext.Create(member: null, ancestor: listComparisonContext); + var valueComparer = largerArray[i] != null ? OverridesCollection.GetComparer(largerArray[i].GetType()) ?? DefaultValueComparer : DefaultValueComparer; yield return new Difference( From e104c620c2885bd6427553b1881d44701c67563c Mon Sep 17 00:00:00 2001 From: Daniel Nemec Date: Sat, 16 Oct 2021 23:23:16 +0200 Subject: [PATCH 025/181] Add Differences property to ComparisonContext. --- .../ObjectsComparer/ComparisonContext.cs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/ObjectsComparer/ObjectsComparer/ComparisonContext.cs b/ObjectsComparer/ObjectsComparer/ComparisonContext.cs index a6cf5b7..d3223b8 100644 --- a/ObjectsComparer/ObjectsComparer/ComparisonContext.cs +++ b/ObjectsComparer/ObjectsComparer/ComparisonContext.cs @@ -19,6 +19,8 @@ public sealed class ComparisonContext readonly List _descendants = new List(); + readonly List _differences = new List(); + private ComparisonContext() { } @@ -44,6 +46,8 @@ private ComparisonContext(MemberInfo currentMember) /// public ReadOnlyCollection Descendants => _descendants.AsReadOnly(); + public ReadOnlyCollection Differences => _differences.AsReadOnly(); + /// /// /// @@ -68,6 +72,16 @@ void AddDescendant(ComparisonContext descendant) descendant.Ancestor = this; } + internal void AddDifference(Difference difference) + { + if (difference is null) + { + throw new ArgumentNullException(nameof(difference)); + } + + _differences.Add(difference); + } + //A list of differences directly related to this context. //Whether the object has any properties (bool recursive). From 0f5583820681d8b7f0003bdc5164c892179c5a45 Mon Sep 17 00:00:00 2001 From: Daniel Nemec Date: Sun, 17 Oct 2021 00:41:59 +0200 Subject: [PATCH 026/181] Add AddDifferenceToComparisonContext operation. --- .../CustomComparers/EnumerablesComparer.cs | 27 ++++++++++++++----- 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs index fbb2e90..580a7fc 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs @@ -61,8 +61,7 @@ public IEnumerable CalculateDifferences(Type type, object obj1, obje if (array1.Length != array2.Length) { - yield return new Difference("", array1.Length.ToString(), array2.Length.ToString(), - DifferenceTypes.NumberOfElementsMismatch); + yield return AddDifferenceToComparisonContext(new Difference("", array1.Length.ToString(), array2.Length.ToString(), DifferenceTypes.NumberOfElementsMismatch), comparisonContext); if (listConfigurationOptions.CompareUnequalLists == false) { @@ -91,6 +90,22 @@ public IEnumerable CalculateDifferences(Type type, object obj1, obje } } + Difference AddDifferenceToComparisonContext(Difference difference, ComparisonContext comparisonContext) + { + if (difference is null) + { + throw new ArgumentNullException(nameof(difference)); + } + + if (comparisonContext is null) + { + throw new ArgumentNullException(nameof(comparisonContext)); + } + + comparisonContext.AddDifference(difference); + return difference; + } + private IEnumerable CalculateDifferencesByKey(object[] array1, object[] array2, ComparisonContext listComparisonContext, ListConfigurationOptions listConfigurationOptions) { var keyOptions = CompareElementsByKeyOptions.Default(); @@ -107,7 +122,7 @@ private IEnumerable CalculateDifferencesByKey(object[] array1, objec continue; } - yield return new Difference("[NULL]", string.Empty, string.Empty, DifferenceTypes.MissedElementInSecondObject); + yield return AddDifferenceToComparisonContext(new Difference("[NULL]", string.Empty, string.Empty, DifferenceTypes.MissedElementInSecondObject), elementContext); continue; } @@ -136,7 +151,7 @@ private IEnumerable CalculateDifferencesByKey(object[] array1, objec else { var valueComparer1 = OverridesCollection.GetComparer(element1.GetType()) ?? DefaultValueComparer; - yield return new Difference($"[{element1Key}]", valueComparer1.ToString(element1), string.Empty, DifferenceTypes.MissedElementInSecondObject); + yield return AddDifferenceToComparisonContext(new Difference($"[{element1Key}]", valueComparer1.ToString(element1), string.Empty, DifferenceTypes.MissedElementInSecondObject), elementContext); } } @@ -151,7 +166,7 @@ private IEnumerable CalculateDifferencesByKey(object[] array1, objec var elementContext = ComparisonContext.Create(member: null, ancestor: listComparisonContext); - yield return new Difference("[NULL]", string.Empty, string.Empty, DifferenceTypes.MissedElementInFirstObject); + yield return AddDifferenceToComparisonContext(new Difference("[NULL]", string.Empty, string.Empty, DifferenceTypes.MissedElementInFirstObject), elementContext); continue; } @@ -172,7 +187,7 @@ private IEnumerable CalculateDifferencesByKey(object[] array1, objec var elementContext = ComparisonContext.Create(member: null, ancestor: listComparisonContext); var valueComparer2 = OverridesCollection.GetComparer(element2.GetType()) ?? DefaultValueComparer; - yield return new Difference($"[{element2Key}]", string.Empty, valueComparer2.ToString(element2), DifferenceTypes.MissedElementInFirstObject); + yield return AddDifferenceToComparisonContext(new Difference($"[{element2Key}]", string.Empty, valueComparer2.ToString(element2), DifferenceTypes.MissedElementInFirstObject), elementContext); } } From 013e20a364f64d5a87833caf7627fdfd2a15ae61 Mon Sep 17 00:00:00 2001 From: Daniel Nemec Date: Sun, 17 Oct 2021 18:20:44 +0200 Subject: [PATCH 027/181] Add operation AddDifferenceToComparisonContext. Edit Difference.InsertPath: Return this instead of a new instance. Add test classes Person, Address. --- .../Comparer_NonGenericEnumerableTests.cs | 19 ++++++++++++ .../TestClasses/Address.cs | 15 ++++++++++ .../TestClasses/Person.cs | 17 +++++++++++ .../ObjectsComparer/BaseComparer.cs | 22 +++++++++++++- ObjectsComparer/ObjectsComparer/Comparer~1.cs | 16 +++++----- .../CustomComparers/EnumerablesComparer.cs | 30 +++++-------------- ObjectsComparer/ObjectsComparer/Difference.cs | 16 ++++++---- 7 files changed, 96 insertions(+), 39 deletions(-) create mode 100644 ObjectsComparer/ObjectsComparer.Tests/TestClasses/Address.cs create mode 100644 ObjectsComparer/ObjectsComparer.Tests/TestClasses/Person.cs diff --git a/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs b/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs index 544ace7..757da71 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs @@ -155,6 +155,25 @@ public void InequalityCount_InequalityProperty_CompareByKey2() Assert.AreEqual(true, differences[2].Value2 == string.Empty); } + [Test] + public void RighComparisonContextGraph() + { + var p1 = new Person + { + FirstName = "F1", + LastName = "L1" + }; + var p2 = new Person + { + FirstName = "F2", + LastName = "L2" + }; + + var settings = new ComparisonSettings(); + var comparer = new Comparer(settings); + var rootContext = ComparisonContext.Create(); + var differences = comparer.CalculateDifferences(p1, p2, rootContext).ToList(); + } [Test] public void InequalityCount_InequalityProperty_CompareByIndex() diff --git a/ObjectsComparer/ObjectsComparer.Tests/TestClasses/Address.cs b/ObjectsComparer/ObjectsComparer.Tests/TestClasses/Address.cs new file mode 100644 index 0000000..05b9858 --- /dev/null +++ b/ObjectsComparer/ObjectsComparer.Tests/TestClasses/Address.cs @@ -0,0 +1,15 @@ +namespace ObjectsComparer.Tests.TestClasses +{ + public class Address + { + public string City { get; set; } + + public string Country { get; set; } + + public string State { get; set; } + + public string PostalCode { get; set; } + + public string Street { get; set; } + } +} diff --git a/ObjectsComparer/ObjectsComparer.Tests/TestClasses/Person.cs b/ObjectsComparer/ObjectsComparer.Tests/TestClasses/Person.cs new file mode 100644 index 0000000..111f979 --- /dev/null +++ b/ObjectsComparer/ObjectsComparer.Tests/TestClasses/Person.cs @@ -0,0 +1,17 @@ +using System.Collections; + +namespace ObjectsComparer.Tests.TestClasses +{ + public class Person + { + public string FirstName { get; set; } + + public string LastName { get; set; } + + public System.DateTime? Birthdate { get; set; } + + public string PhoneNumber { get; set; } + + public IEnumerable NonGenericAddresses { get; set; } + } +} diff --git a/ObjectsComparer/ObjectsComparer/BaseComparer.cs b/ObjectsComparer/ObjectsComparer/BaseComparer.cs index 0366f09..0d220d5 100644 --- a/ObjectsComparer/ObjectsComparer/BaseComparer.cs +++ b/ObjectsComparer/ObjectsComparer/BaseComparer.cs @@ -139,9 +139,9 @@ public void AddComparerOverride(string memberName, IValueComparer valueComparer, /// /// Sets . + public void SetDefaultComparer(IValueComparer valueComparer) /// /// Value Comparer. - public void SetDefaultComparer(IValueComparer valueComparer) { DefaultValueComparer = valueComparer ?? throw new ArgumentNullException(nameof(valueComparer)); } @@ -183,5 +183,25 @@ public void IgnoreMember(Func filter) { OverridesCollection.AddComparer(DoNotCompareValueComparer.Instance, filter); } + + /// + /// Adds an to the end of the 's . + /// + /// The argument. + protected virtual Difference AddDifferenceToComparisonContext(Difference difference, ComparisonContext comparisonContext) + { + if (difference is null) + { + throw new ArgumentNullException(nameof(difference)); + } + + if (comparisonContext is null) + { + throw new ArgumentNullException(nameof(comparisonContext)); + } + + comparisonContext.AddDifference(difference); + return difference; + } } } \ No newline at end of file diff --git a/ObjectsComparer/ObjectsComparer/Comparer~1.cs b/ObjectsComparer/ObjectsComparer/Comparer~1.cs index 8bc6cb2..650a68e 100644 --- a/ObjectsComparer/ObjectsComparer/Comparer~1.cs +++ b/ObjectsComparer/ObjectsComparer/Comparer~1.cs @@ -78,9 +78,7 @@ IEnumerable CalculateDifferences(T obj1, T obj2, MemberInfo memberIn comparer = comparer ?? DefaultValueComparer; if (!comparer.Compare(obj1, obj2, Settings)) { - yield return - new Difference(string.Empty, comparer.ToString(obj1), - comparer.ToString(obj2)); + yield return AddDifferenceToComparisonContext(new Difference(string.Empty, comparer.ToString(obj1), comparer.ToString(obj2)), comparisonContext); } yield break; @@ -91,7 +89,7 @@ IEnumerable CalculateDifferences(T obj1, T obj2, MemberInfo memberIn { foreach (var difference in conditionalComparer.CalculateDifferences(typeof(T), obj1, obj2, comparisonContext)) { - yield return difference; + yield return AddDifferenceToComparisonContext(difference, comparisonContext); } if (conditionalComparer.IsStopComparison(typeof(T), obj1, obj2)) @@ -104,7 +102,7 @@ IEnumerable CalculateDifferences(T obj1, T obj2, MemberInfo memberIn { if (!DefaultValueComparer.Compare(obj1, obj2, Settings)) { - yield return new Difference(string.Empty, DefaultValueComparer.ToString(obj1), DefaultValueComparer.ToString(obj2)); + yield return AddDifferenceToComparisonContext(new Difference(string.Empty, DefaultValueComparer.ToString(obj1), DefaultValueComparer.ToString(obj2)), comparisonContext); } yield break; @@ -126,7 +124,7 @@ IEnumerable CalculateDifferences(T obj1, T obj2, MemberInfo memberIn continue; } - var context = ComparisonContext.Create(member: member, ancestor: comparisonContext); + var memberContext = ComparisonContext.Create(member: member, ancestor: comparisonContext); var valueComparer = DefaultValueComparer; var hasCustomComparer = false; @@ -143,9 +141,9 @@ IEnumerable CalculateDifferences(T obj1, T obj2, MemberInfo memberIn { var objectDataComparer = Factory.GetObjectsComparer(type, Settings, this); - foreach (var failure in objectDataComparer.CalculateDifferences(type, value1, value2, context)) + foreach (var failure in objectDataComparer.CalculateDifferences(type, value1, value2, memberContext)) { - yield return failure.InsertPath(member.Name); + yield return AddDifferenceToComparisonContext(failure.InsertPath(member.Name), memberContext); } continue; @@ -153,7 +151,7 @@ IEnumerable CalculateDifferences(T obj1, T obj2, MemberInfo memberIn if (!valueComparer.Compare(value1, value2, Settings)) { - yield return new Difference(member.Name, valueComparer.ToString(value1), valueComparer.ToString(value2)); + yield return AddDifferenceToComparisonContext(new Difference(member.Name, valueComparer.ToString(value1), valueComparer.ToString(value2)), memberContext); } } } diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs index 580a7fc..d144f91 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs @@ -90,22 +90,6 @@ public IEnumerable CalculateDifferences(Type type, object obj1, obje } } - Difference AddDifferenceToComparisonContext(Difference difference, ComparisonContext comparisonContext) - { - if (difference is null) - { - throw new ArgumentNullException(nameof(difference)); - } - - if (comparisonContext is null) - { - throw new ArgumentNullException(nameof(comparisonContext)); - } - - comparisonContext.AddDifference(difference); - return difference; - } - private IEnumerable CalculateDifferencesByKey(object[] array1, object[] array2, ComparisonContext listComparisonContext, ListConfigurationOptions listConfigurationOptions) { var keyOptions = CompareElementsByKeyOptions.Default(); @@ -217,19 +201,19 @@ private IEnumerable CalculateDifferencesByIndex(object[] array1, obj if (array1[i] == null) { - yield return new Difference($"[{i}]", string.Empty, valueComparer2.ToString(array2[i])); + yield return AddDifferenceToComparisonContext(new Difference($"[{i}]", string.Empty, valueComparer2.ToString(array2[i])), elementContext); continue; } if (array2[i] == null) { - yield return new Difference($"[{i}]", valueComparer1.ToString(array1[i]), string.Empty); + yield return AddDifferenceToComparisonContext(new Difference($"[{i}]", valueComparer1.ToString(array1[i]), string.Empty), elementContext); continue; } if (array1[i].GetType() != array2[i].GetType()) { - yield return new Difference($"[{i}]", valueComparer1.ToString(array1[i]), valueComparer2.ToString(array2[i]), DifferenceTypes.TypeMismatch); + yield return AddDifferenceToComparisonContext(new Difference($"[{i}]", valueComparer1.ToString(array1[i]), valueComparer2.ToString(array2[i]), DifferenceTypes.TypeMismatch), elementContext); continue; } @@ -241,22 +225,22 @@ private IEnumerable CalculateDifferencesByIndex(object[] array1, obj } } - //Add a "missed element" difference for each element that is in array1 that and is not in array2 or vice versa. The positions of value1 and value2 are preserved in the Difference instance. + //Add a "missed element" difference for each element that is in array1 and that is not in array2 or vice versa. if (array1Count != array2Count) { var largerArray = array1Count > array2Count ? array1 : array2; for (int i = smallerCount; i < largerArray.Length; i++) { - var elementContext = ComparisonContext.Create(member: null, ancestor: listComparisonContext); - var valueComparer = largerArray[i] != null ? OverridesCollection.GetComparer(largerArray[i].GetType()) ?? DefaultValueComparer : DefaultValueComparer; - yield return new Difference( + var difference = new Difference( memberPath: $"[{i}]", value1: array1Count > array2Count ? valueComparer.ToString(largerArray[i]) : string.Empty, value2: array2Count > array1Count ? valueComparer.ToString(largerArray[i]) : string.Empty, differenceType: array1Count > array2Count ? DifferenceTypes.MissedElementInSecondObject : DifferenceTypes.MissedElementInFirstObject); + + yield return AddDifferenceToComparisonContext(difference, ComparisonContext.Create(member: null, ancestor: listComparisonContext)); } } } diff --git a/ObjectsComparer/ObjectsComparer/Difference.cs b/ObjectsComparer/ObjectsComparer/Difference.cs index 1341f0c..c84f911 100644 --- a/ObjectsComparer/ObjectsComparer/Difference.cs +++ b/ObjectsComparer/ObjectsComparer/Difference.cs @@ -8,7 +8,7 @@ public class Difference /// /// Path to the member. /// - public string MemberPath { get; } + public string MemberPath { get; private set; } /// /// Value in the first object, converted to string. @@ -52,11 +52,15 @@ public Difference InsertPath(string path) ? path + MemberPath : path + "." + MemberPath; - return new Difference( - newPath, - Value1, - Value2, - DifferenceType); + //return new Difference( + // newPath, + // Value1, + // Value2, + // DifferenceType); + + MemberPath = newPath; + + return this; } /// Returns a string that represents the current object. From f78f4fa73b1e45c2bd22c49e5b44ab596dd62194 Mon Sep 17 00:00:00 2001 From: "ASD\\nemec" Date: Tue, 19 Oct 2021 12:29:33 +0200 Subject: [PATCH 028/181] EnumerablesComparer.CalculateDifferences: Add AddDifferenceToComparisonContext. --- .../Comparer_NonGenericEnumerableTests.cs | 20 ++++++++++++++++--- ObjectsComparer/ObjectsComparer/Comparer~1.cs | 4 ++-- .../CustomComparers/EnumerablesComparer.cs | 2 +- 3 files changed, 20 insertions(+), 6 deletions(-) diff --git a/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs b/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs index 757da71..5e7ba22 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs @@ -156,17 +156,31 @@ public void InequalityCount_InequalityProperty_CompareByKey2() } [Test] - public void RighComparisonContextGraph() + public void RightComparisonContextGraph() { var p1 = new Person { FirstName = "F1", - LastName = "L1" + LastName = "L1", + NonGenericAddresses = new ArrayList() + { + new Address + { + City = "City1" + } + } }; var p2 = new Person { FirstName = "F2", - LastName = "L2" + LastName = "L2", + NonGenericAddresses = new ArrayList() + { + new Address + { + City = "City2" + } + } }; var settings = new ComparisonSettings(); diff --git a/ObjectsComparer/ObjectsComparer/Comparer~1.cs b/ObjectsComparer/ObjectsComparer/Comparer~1.cs index 650a68e..df842c9 100644 --- a/ObjectsComparer/ObjectsComparer/Comparer~1.cs +++ b/ObjectsComparer/ObjectsComparer/Comparer~1.cs @@ -89,7 +89,7 @@ IEnumerable CalculateDifferences(T obj1, T obj2, MemberInfo memberIn { foreach (var difference in conditionalComparer.CalculateDifferences(typeof(T), obj1, obj2, comparisonContext)) { - yield return AddDifferenceToComparisonContext(difference, comparisonContext); + yield return difference; } if (conditionalComparer.IsStopComparison(typeof(T), obj1, obj2)) @@ -143,7 +143,7 @@ IEnumerable CalculateDifferences(T obj1, T obj2, MemberInfo memberIn foreach (var failure in objectDataComparer.CalculateDifferences(type, value1, value2, memberContext)) { - yield return AddDifferenceToComparisonContext(failure.InsertPath(member.Name), memberContext); + yield return failure.InsertPath(member.Name); } continue; diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs index d144f91..b94caf5 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs @@ -31,7 +31,7 @@ public IEnumerable CalculateDifferences(Type type, object obj1, obje if (!Settings.EmptyAndNullEnumerablesEqual && (obj1 == null || obj2 == null) && obj1 != obj2) { - yield return new Difference("[]", obj1?.ToString() ?? string.Empty, obj2?.ToString() ?? string.Empty); + yield return AddDifferenceToComparisonContext(new Difference("[]", obj1?.ToString() ?? string.Empty, obj2?.ToString() ?? string.Empty), comparisonContext); yield break; } From c8691cdaccd34c13ef9ca447ae001e6657c0a1dc Mon Sep 17 00:00:00 2001 From: "ASD\\nemec" Date: Wed, 20 Oct 2021 12:24:51 +0200 Subject: [PATCH 029/181] Edit RightComparisonContextGraph() test method. --- .../Comparer_NonGenericEnumerableTests.cs | 23 +++++++++++++------ .../TestClasses/Address.cs | 2 ++ .../ObjectsComparer/ComparisonContext.cs | 6 ++--- .../CustomComparers/EnumerablesComparer.cs | 22 ++++++++++-------- .../ObjectsComparer/IContextableComparer~1.cs | 2 +- .../ObjectsComparer/ListComparisonSettings.cs | 2 +- .../ListConfigurationOptions.cs | 3 +++ 7 files changed, 39 insertions(+), 21 deletions(-) diff --git a/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs b/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs index 5e7ba22..bdffd4c 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs @@ -52,8 +52,6 @@ public void InequalityProperty() Assert.AreEqual("Str3", differences.First().Value2); } - static string GetMyString() => "xxx"; - [Test] public void InequalityCount_InequalityProperty_CompareByKey() { @@ -160,30 +158,41 @@ public void RightComparisonContextGraph() { var p1 = new Person { - FirstName = "F1", - LastName = "L1", + FirstName = "FirstName1", + LastName = "LastName1", NonGenericAddresses = new ArrayList() { new Address { + Id = 1, City = "City1" - } + }, + + new Address{} } }; var p2 = new Person { - FirstName = "F2", - LastName = "L2", + FirstName = "FirstName2", + LastName = "LastName2", NonGenericAddresses = new ArrayList() { + null, + new Address { + Id = 1, City = "City2" } } }; var settings = new ComparisonSettings(); + settings.List.Configure((_, options) => + { + options.CompareUnequalLists = true; + //options.CompareElementsByKey(); + }); var comparer = new Comparer(settings); var rootContext = ComparisonContext.Create(); var differences = comparer.CalculateDifferences(p1, p2, rootContext).ToList(); diff --git a/ObjectsComparer/ObjectsComparer.Tests/TestClasses/Address.cs b/ObjectsComparer/ObjectsComparer.Tests/TestClasses/Address.cs index 05b9858..fc77cb9 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/TestClasses/Address.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/TestClasses/Address.cs @@ -2,6 +2,8 @@ { public class Address { + public int Id { get; set; } + public string City { get; set; } public string Country { get; set; } diff --git a/ObjectsComparer/ObjectsComparer/ComparisonContext.cs b/ObjectsComparer/ObjectsComparer/ComparisonContext.cs index d3223b8..de7c34a 100644 --- a/ObjectsComparer/ObjectsComparer/ComparisonContext.cs +++ b/ObjectsComparer/ObjectsComparer/ComparisonContext.cs @@ -6,8 +6,8 @@ namespace ObjectsComparer { /// - /// Information about the , which is typically a property or field, in comparison process. It has its ancestor and descendant contexts in the same way as its member has its ancestor and descendant members in an object graph. It contains all possible member differences. - /// It is possible to traverse entire compared object graph and see differences at particular members. + /// Information about the , which is typically a property or field, in comparison process. It has its ancestor and descendant objects in the same way as its has its ancestor and descendant members in an object graph. contains all possible member differences. + /// Once the comparison is completed, it is possible to traverse the object graph and see differences at particular members. /// public sealed class ComparisonContext { @@ -39,7 +39,7 @@ private ComparisonContext(MemberInfo currentMember) /// /// Ancestor context. /// - public ComparisonContext Ancestor { get; set; } + public ComparisonContext Ancestor { get; private set; } /// /// Children contexts. diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs index b94caf5..47d5302 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs @@ -81,7 +81,7 @@ public IEnumerable CalculateDifferences(Type type, object obj1, obje } else { - throw new NotImplementedException($"ListElementComparisonMode is not implemented {listConfigurationOptions.ComparisonMode}."); + throw new NotImplementedException($"{listConfigurationOptions.ComparisonMode} is not implemented yet."); } foreach (var failrue in failrues) @@ -92,9 +92,15 @@ public IEnumerable CalculateDifferences(Type type, object obj1, obje private IEnumerable CalculateDifferencesByKey(object[] array1, object[] array2, ComparisonContext listComparisonContext, ListConfigurationOptions listConfigurationOptions) { + Debug.WriteLine(nameof(CalculateDifferencesByKey)); + var keyOptions = CompareElementsByKeyOptions.Default(); listConfigurationOptions.KeyOptionsAction?.Invoke(keyOptions); + //TODO: keyPrefix from configuration. + var keyPrefix = "KEY="; + var nullElementPrefix = "NULLREF"; + foreach (var element1 in array1) { var elementContext = ComparisonContext.Create(member: null, ancestor: listComparisonContext); @@ -106,7 +112,7 @@ private IEnumerable CalculateDifferencesByKey(object[] array1, objec continue; } - yield return AddDifferenceToComparisonContext(new Difference("[NULL]", string.Empty, string.Empty, DifferenceTypes.MissedElementInSecondObject), elementContext); + yield return AddDifferenceToComparisonContext(new Difference($"[{nullElementPrefix}]", string.Empty, string.Empty, DifferenceTypes.MissedElementInSecondObject), elementContext); continue; } @@ -129,13 +135,13 @@ private IEnumerable CalculateDifferencesByKey(object[] array1, objec foreach (var failure in comparer.CalculateDifferences(element1.GetType(), element1, element2, elementContext)) { - yield return failure.InsertPath($"[{element1Key}]"); + yield return failure.InsertPath($"[{keyPrefix}{element1Key}]"); } } else { - var valueComparer1 = OverridesCollection.GetComparer(element1.GetType()) ?? DefaultValueComparer; - yield return AddDifferenceToComparisonContext(new Difference($"[{element1Key}]", valueComparer1.ToString(element1), string.Empty, DifferenceTypes.MissedElementInSecondObject), elementContext); + var valueComparer1 = OverridesCollection.GetComparer(element1.GetType()) ?? DefaultValueComparer; + yield return AddDifferenceToComparisonContext(new Difference($"[{keyPrefix}{element1Key}]", valueComparer1.ToString(element1), string.Empty, DifferenceTypes.MissedElementInSecondObject), elementContext); } } @@ -150,7 +156,7 @@ private IEnumerable CalculateDifferencesByKey(object[] array1, objec var elementContext = ComparisonContext.Create(member: null, ancestor: listComparisonContext); - yield return AddDifferenceToComparisonContext(new Difference("[NULL]", string.Empty, string.Empty, DifferenceTypes.MissedElementInFirstObject), elementContext); + yield return AddDifferenceToComparisonContext(new Difference($"[{nullElementPrefix}]", string.Empty, string.Empty, DifferenceTypes.MissedElementInFirstObject), elementContext); continue; } @@ -171,11 +177,9 @@ private IEnumerable CalculateDifferencesByKey(object[] array1, objec var elementContext = ComparisonContext.Create(member: null, ancestor: listComparisonContext); var valueComparer2 = OverridesCollection.GetComparer(element2.GetType()) ?? DefaultValueComparer; - yield return AddDifferenceToComparisonContext(new Difference($"[{element2Key}]", string.Empty, valueComparer2.ToString(element2), DifferenceTypes.MissedElementInFirstObject), elementContext); + yield return AddDifferenceToComparisonContext(new Difference($"[{keyPrefix}{element2Key}]", string.Empty, valueComparer2.ToString(element2), DifferenceTypes.MissedElementInFirstObject), elementContext); } } - - Debug.WriteLine(nameof(CalculateDifferencesByKey)); } private IEnumerable CalculateDifferencesByIndex(object[] array1, object[] array2, ComparisonContext listComparisonContext) diff --git a/ObjectsComparer/ObjectsComparer/IContextableComparer~1.cs b/ObjectsComparer/ObjectsComparer/IContextableComparer~1.cs index 1625530..cdbc6d0 100644 --- a/ObjectsComparer/ObjectsComparer/IContextableComparer~1.cs +++ b/ObjectsComparer/ObjectsComparer/IContextableComparer~1.cs @@ -4,7 +4,7 @@ namespace ObjectsComparer { /// - /// Generic comparer that accept comparison's process context, see . + /// Comparer accepting . /// public interface IContextableComparer { diff --git a/ObjectsComparer/ObjectsComparer/ListComparisonSettings.cs b/ObjectsComparer/ObjectsComparer/ListComparisonSettings.cs index 148d922..03603fc 100644 --- a/ObjectsComparer/ObjectsComparer/ListComparisonSettings.cs +++ b/ObjectsComparer/ObjectsComparer/ListComparisonSettings.cs @@ -12,7 +12,7 @@ public class ListComparisonSettings internal Action ConfigureOptionsAction { get; private set; } = null; /// - /// + /// Configures list comparison behavior. /// /// public void Configure(Action configureOptions) diff --git a/ObjectsComparer/ObjectsComparer/ListConfigurationOptions.cs b/ObjectsComparer/ObjectsComparer/ListConfigurationOptions.cs index d100446..efefd07 100644 --- a/ObjectsComparer/ObjectsComparer/ListConfigurationOptions.cs +++ b/ObjectsComparer/ObjectsComparer/ListConfigurationOptions.cs @@ -6,6 +6,9 @@ namespace ObjectsComparer { + /// + /// Configures list comparison behavior. + /// public class ListConfigurationOptions { ListConfigurationOptions() From 253e8c86785a534796430a11486a138c85df6961 Mon Sep 17 00:00:00 2001 From: "ASD\\nemec" Date: Wed, 20 Oct 2021 13:33:07 +0200 Subject: [PATCH 030/181] Add IntKeyPrefix, KeyProvider behavior. --- .../Comparer_NonGenericEnumerableTests.cs | 5 +++- .../CompareElementsByKeyOptions.cs | 23 +++++++++++++++++++ .../CustomComparers/EnumerablesComparer.cs | 2 +- 3 files changed, 28 insertions(+), 2 deletions(-) diff --git a/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs b/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs index bdffd4c..8451d50 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs @@ -191,7 +191,10 @@ public void RightComparisonContextGraph() settings.List.Configure((_, options) => { options.CompareUnequalLists = true; - //options.CompareElementsByKey(); + options.CompareElementsByKey(keyOptions=> + { + keyOptions.IntKeyPrefix + }); }); var comparer = new Comparer(settings); var rootContext = ComparisonContext.Create(); diff --git a/ObjectsComparer/ObjectsComparer/CompareElementsByKeyOptions.cs b/ObjectsComparer/ObjectsComparer/CompareElementsByKeyOptions.cs index 00608db..f1462c0 100644 --- a/ObjectsComparer/ObjectsComparer/CompareElementsByKeyOptions.cs +++ b/ObjectsComparer/ObjectsComparer/CompareElementsByKeyOptions.cs @@ -2,11 +2,26 @@ using System.Linq; using System.Reflection; using ObjectsComparer.Exceptions; +using ObjectsComparer; namespace ObjectsComparer { + /// + /// Configures list element behavior for comparison by key. + /// public class CompareElementsByKeyOptions { + /// + /// Default key prefix for integer key. It will be used for formating property, for example "Addresses[KEY=123]". + /// + /// Addresses + public const string DefaultIntKeyPrefix = "KEY="; + + /// + /// + /// + public const string DefaultNullElementSymbol = "NULLREF"; + CompareElementsByKeyOptions() { Initialize(); @@ -25,6 +40,14 @@ public class CompareElementsByKeyOptions /// internal Func KeyProvider { get; private set; } = null; + /// + /// Key prefix for integer key. It will be used as part of property, for example "Addresses[KEY=123]". Default value = . + /// If you do not want the integer key to be prefixed, set this value to null. + /// + public string IntKeyPrefix { get; set; } = null; + + public string NullElementSymbol { get; set; } = DefaultNullElementSymbol; + void Initialize() { UseKey(new string[] { "Id", "Name" }, caseSensitive: false); diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs index 47d5302..f3d826a 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs @@ -192,7 +192,7 @@ private IEnumerable CalculateDifferencesByIndex(object[] array1, obj //ToDo Extract type for (var i = 0; i < smallerCount; i++) - { + { var elementContext = ComparisonContext.Create(member: null, ancestor: listComparisonContext); if (array1[i] == null && array2[i] == null) From bdc585a57d67d1eaeb069cb8ea0a3cdcb1918cee Mon Sep 17 00:00:00 2001 From: "ASD\\nemec" Date: Thu, 21 Oct 2021 13:29:28 +0200 Subject: [PATCH 031/181] Add CompareElementsByKeyOptions's KeyPrefix, NullElementIdentifier properties. Do othe stuff. --- .../Comparer_NonGenericEnumerableTests.cs | 11 ++- .../ComparisonSettingsTests.cs | 4 +- .../CompareElementsByKeyOptions.cs | 70 ++++++++++++++++--- .../CustomComparers/EnumerablesComparer.cs | 19 +++-- .../ListConfigurationOptions.cs | 5 +- .../ListElementComparisonMode.cs | 8 --- .../ListElementSearchingMode.cs | 18 +++++ .../ObjectsComparer/Utils/StringExtensions.cs | 25 +++++++ 8 files changed, 128 insertions(+), 32 deletions(-) delete mode 100644 ObjectsComparer/ObjectsComparer/ListElementComparisonMode.cs create mode 100644 ObjectsComparer/ObjectsComparer/ListElementSearchingMode.cs create mode 100644 ObjectsComparer/ObjectsComparer/Utils/StringExtensions.cs diff --git a/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs b/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs index 8451d50..2495006 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs @@ -183,19 +183,24 @@ public void RightComparisonContextGraph() { Id = 1, City = "City2" - } + }, + + null } }; var settings = new ComparisonSettings(); + settings.List.Configure((_, options) => { options.CompareUnequalLists = true; - options.CompareElementsByKey(keyOptions=> + options.CompareElementsByKey(keyOptions => { - keyOptions.IntKeyPrefix + keyOptions.KeyPrefix = "Key: "; + keyOptions.NullElementIdentifier = "Null-ref"; }); }); + var comparer = new Comparer(settings); var rootContext = ComparisonContext.Create(); var differences = comparer.CalculateDifferences(p1, p2, rootContext).ToList(); diff --git a/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs b/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs index 37953f3..d5ecc0e 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs @@ -80,7 +80,7 @@ public void CompareListElementsByKeyIsCorrectlySet() listConfigurationOptions.KeyOptionsAction(compareElementsByKeyOptions); Assert.AreEqual(true, listConfigurationOptions.CompareUnequalLists); - Assert.AreEqual(true, listConfigurationOptions.ComparisonMode == ListElementComparisonMode.Key); + Assert.AreEqual(true, listConfigurationOptions.ElementSearchMode == ListElementSearchMode.Key); Assert.AreEqual(true, compareElementsByKeyOptions.ThrowKeyNotFound); } @@ -93,7 +93,7 @@ public void ListComparisonConfigurationBackwardCompatibilityEnsured() var options = ListConfigurationOptions.Default(); Assert.AreEqual(false, options.CompareUnequalLists); - Assert.AreEqual(true, options.ComparisonMode == ListElementComparisonMode.Index); + Assert.AreEqual(true, options.ElementSearchMode == ListElementSearchMode.Index); } [Test] diff --git a/ObjectsComparer/ObjectsComparer/CompareElementsByKeyOptions.cs b/ObjectsComparer/ObjectsComparer/CompareElementsByKeyOptions.cs index f1462c0..52ea446 100644 --- a/ObjectsComparer/ObjectsComparer/CompareElementsByKeyOptions.cs +++ b/ObjectsComparer/ObjectsComparer/CompareElementsByKeyOptions.cs @@ -3,24 +3,27 @@ using System.Reflection; using ObjectsComparer.Exceptions; using ObjectsComparer; +using ObjectsComparer.Utils; namespace ObjectsComparer { /// - /// Configures list element behavior for comparison by key. + /// Configures list element behavior if mode is used. /// public class CompareElementsByKeyOptions { /// - /// Default key prefix for integer key. It will be used for formating property, for example "Addresses[KEY=123]". + /// Default key prefix for an integer key. It will be used for formatting property, for example: "Addresses[KEY=123]". + /// See for more info. /// /// Addresses public const string DefaultIntKeyPrefix = "KEY="; /// - /// + /// Default element identifier for element that refers to null. It will be used for formatting property, for example: "Addresses[NULLREF]". + /// See for more info. /// - public const string DefaultNullElementSymbol = "NULLREF"; + public const string DefaultNullElementIdentifier = "NULLREF"; CompareElementsByKeyOptions() { @@ -41,12 +44,17 @@ public class CompareElementsByKeyOptions internal Func KeyProvider { get; private set; } = null; /// - /// Key prefix for integer key. It will be used as part of property, for example "Addresses[KEY=123]". Default value = . - /// If you do not want the integer key to be prefixed, set this value to null. + /// To avoid confusion with the index, an optional key element prefix can be used. If value = null, which is the default value, will be used for integer key type and no prefix will be used for other types. + /// If you don't want to use prefix at all, set this property to . /// - public string IntKeyPrefix { get; set; } = null; + public string KeyPrefix { get; set; } = null; - public string NullElementSymbol { get; set; } = DefaultNullElementSymbol; + /// + /// If the list element refers to a null value, this symbol will eventually be used as list element identifier in the property. + /// Default value = . + /// If you don't want to use it at all, set this property to . + /// + public string NullElementIdentifier { get; set; } = DefaultNullElementIdentifier; void Initialize() { @@ -131,5 +139,51 @@ static object GetKeyValue(object instance, bool caseSensitive, params string[] k return instance; } + + /// + /// See . + /// + internal static string ResolveKeyPrefix(object elementKey, CompareElementsByKeyOptions options) + { + if (elementKey is null) + { + throw new ArgumentNullException(nameof(elementKey)); + } + + if (options is null) + { + throw new ArgumentNullException(nameof(options)); + } + + if (options.KeyPrefix == string.Empty) + { + return string.Empty; + } + + if (options.KeyPrefix == null) + { + if (elementKey is byte || elementKey is short || elementKey is int || elementKey is long) + { + return DefaultIntKeyPrefix; + } + } + + return options.KeyPrefix.Left(10); + } + + internal static string ResolveNullElementIdentifier(CompareElementsByKeyOptions options) + { + if (options is null) + { + throw new ArgumentNullException(nameof(options)); + } + + if (options.NullElementIdentifier == null) + { + return string.Empty; + } + + return options.NullElementIdentifier.Left(10); + } } } diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs index f3d826a..72b3cdf 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs @@ -71,17 +71,17 @@ public IEnumerable CalculateDifferences(Type type, object obj1, obje IEnumerable failrues; - if (listConfigurationOptions.ComparisonMode == ListElementComparisonMode.Key) + if (listConfigurationOptions.ElementSearchMode == ListElementSearchMode.Key) { failrues = CalculateDifferencesByKey(array1, array2, comparisonContext, listConfigurationOptions); } - else if (listConfigurationOptions.ComparisonMode == ListElementComparisonMode.Index) + else if (listConfigurationOptions.ElementSearchMode == ListElementSearchMode.Index) { failrues = CalculateDifferencesByIndex(array1, array2, comparisonContext); } else { - throw new NotImplementedException($"{listConfigurationOptions.ComparisonMode} is not implemented yet."); + throw new NotImplementedException($"{listConfigurationOptions.ElementSearchMode} implemented yet."); } foreach (var failrue in failrues) @@ -96,10 +96,7 @@ private IEnumerable CalculateDifferencesByKey(object[] array1, objec var keyOptions = CompareElementsByKeyOptions.Default(); listConfigurationOptions.KeyOptionsAction?.Invoke(keyOptions); - - //TODO: keyPrefix from configuration. - var keyPrefix = "KEY="; - var nullElementPrefix = "NULLREF"; + var nullElementIdentifier = CompareElementsByKeyOptions.ResolveNullElementIdentifier(keyOptions); foreach (var element1 in array1) { @@ -112,7 +109,7 @@ private IEnumerable CalculateDifferencesByKey(object[] array1, objec continue; } - yield return AddDifferenceToComparisonContext(new Difference($"[{nullElementPrefix}]", string.Empty, string.Empty, DifferenceTypes.MissedElementInSecondObject), elementContext); + yield return AddDifferenceToComparisonContext(new Difference($"[{nullElementIdentifier}]", string.Empty, string.Empty, DifferenceTypes.MissedElementInSecondObject), elementContext); continue; } @@ -128,6 +125,8 @@ private IEnumerable CalculateDifferencesByKey(object[] array1, objec continue; } + var keyPrefix = CompareElementsByKeyOptions.ResolveKeyPrefix(element1Key, keyOptions); + if (array2.Any(elm2 => object.Equals(element1Key, keyOptions.KeyProvider(elm2)))) { var element2 = array2.First(elm2 => object.Equals(element1Key, keyOptions.KeyProvider(elm2))); @@ -156,7 +155,7 @@ private IEnumerable CalculateDifferencesByKey(object[] array1, objec var elementContext = ComparisonContext.Create(member: null, ancestor: listComparisonContext); - yield return AddDifferenceToComparisonContext(new Difference($"[{nullElementPrefix}]", string.Empty, string.Empty, DifferenceTypes.MissedElementInFirstObject), elementContext); + yield return AddDifferenceToComparisonContext(new Difference($"[{nullElementIdentifier}]", string.Empty, string.Empty, DifferenceTypes.MissedElementInFirstObject), elementContext); continue; } @@ -175,7 +174,7 @@ private IEnumerable CalculateDifferencesByKey(object[] array1, objec if (array1.Any(elm1 => object.Equals(element2Key, keyOptions.KeyProvider(elm1))) == false) { var elementContext = ComparisonContext.Create(member: null, ancestor: listComparisonContext); - + var keyPrefix = CompareElementsByKeyOptions.ResolveKeyPrefix(element2Key, keyOptions); var valueComparer2 = OverridesCollection.GetComparer(element2.GetType()) ?? DefaultValueComparer; yield return AddDifferenceToComparisonContext(new Difference($"[{keyPrefix}{element2Key}]", string.Empty, valueComparer2.ToString(element2), DifferenceTypes.MissedElementInFirstObject), elementContext); } diff --git a/ObjectsComparer/ObjectsComparer/ListConfigurationOptions.cs b/ObjectsComparer/ObjectsComparer/ListConfigurationOptions.cs index efefd07..b49b3e0 100644 --- a/ObjectsComparer/ObjectsComparer/ListConfigurationOptions.cs +++ b/ObjectsComparer/ObjectsComparer/ListConfigurationOptions.cs @@ -47,6 +47,9 @@ public void CompareElementsByKey(Action keyOptions) KeyOptionsAction = keyOptions; } - internal ListElementComparisonMode ComparisonMode => KeyOptionsAction == null ? ListElementComparisonMode.Index : ListElementComparisonMode.Key; + /// + /// See . + /// + internal ListElementSearchMode ElementSearchMode => KeyOptionsAction == null ? ListElementSearchMode.Index : ListElementSearchMode.Key; } } diff --git a/ObjectsComparer/ObjectsComparer/ListElementComparisonMode.cs b/ObjectsComparer/ObjectsComparer/ListElementComparisonMode.cs deleted file mode 100644 index 65355a0..0000000 --- a/ObjectsComparer/ObjectsComparer/ListElementComparisonMode.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace ObjectsComparer -{ - internal enum ListElementComparisonMode - { - Index, - Key - } -} diff --git a/ObjectsComparer/ObjectsComparer/ListElementSearchingMode.cs b/ObjectsComparer/ObjectsComparer/ListElementSearchingMode.cs new file mode 100644 index 0000000..f01f1c0 --- /dev/null +++ b/ObjectsComparer/ObjectsComparer/ListElementSearchingMode.cs @@ -0,0 +1,18 @@ +namespace ObjectsComparer +{ + /// + /// List element searching mode. + /// + internal enum ListElementSearchMode + { + /// + /// The elements will be searched according to their index. + /// + Index, + + /// + /// The elements will be searched according to their key. + /// + Key + } +} diff --git a/ObjectsComparer/ObjectsComparer/Utils/StringExtensions.cs b/ObjectsComparer/ObjectsComparer/Utils/StringExtensions.cs new file mode 100644 index 0000000..9f61cba --- /dev/null +++ b/ObjectsComparer/ObjectsComparer/Utils/StringExtensions.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace ObjectsComparer.Utils +{ + internal static class StringExtensions + { + /// + /// Returns the left part of with the of characters. + /// + /// + /// + /// + public static string Left(this string value, int length) + { + if (value is null) + { + throw new ArgumentNullException(nameof(value)); + } + + return value.Substring(0, value.Length > length ? length : value.Length); + } + } +} From eebe7170fdcbe563c1c3338bf2a2d591adfe69b5 Mon Sep 17 00:00:00 2001 From: "ASD\\nemec" Date: Fri, 22 Oct 2021 08:34:41 +0200 Subject: [PATCH 032/181] Edit RightComparisonContextGraph. Edit comments. --- .../Comparer_NonGenericEnumerableTests.cs | 13 +++++++++++-- .../ObjectsComparer.Tests/TestClasses/Person.cs | 4 +++- .../ObjectsComparer/CompareElementsByKeyOptions.cs | 2 +- .../ObjectsComparer/ListConfigurationOptions.cs | 6 ++++++ .../ObjectsComparer/ListElementSearchingMode.cs | 2 +- 5 files changed, 22 insertions(+), 5 deletions(-) diff --git a/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs b/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs index 2495006..fe32616 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs @@ -160,7 +160,7 @@ public void RightComparisonContextGraph() { FirstName = "FirstName1", LastName = "LastName1", - NonGenericAddresses = new ArrayList() + NonGenericLiveAddresses = new ArrayList { new Address { @@ -169,13 +169,22 @@ public void RightComparisonContextGraph() }, new Address{} + }, + NonGenericStayAddresses = new ArrayList + { + new Address + { + Id = 2, + City = "City3" + }, } }; + var p2 = new Person { FirstName = "FirstName2", LastName = "LastName2", - NonGenericAddresses = new ArrayList() + NonGenericLiveAddresses = new ArrayList { null, diff --git a/ObjectsComparer/ObjectsComparer.Tests/TestClasses/Person.cs b/ObjectsComparer/ObjectsComparer.Tests/TestClasses/Person.cs index 111f979..d4c3489 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/TestClasses/Person.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/TestClasses/Person.cs @@ -12,6 +12,8 @@ public class Person public string PhoneNumber { get; set; } - public IEnumerable NonGenericAddresses { get; set; } + public IEnumerable NonGenericLiveAddresses { get; set; } + + public IEnumerable NonGenericStayAddresses { get; set; } } } diff --git a/ObjectsComparer/ObjectsComparer/CompareElementsByKeyOptions.cs b/ObjectsComparer/ObjectsComparer/CompareElementsByKeyOptions.cs index 52ea446..49ca65a 100644 --- a/ObjectsComparer/ObjectsComparer/CompareElementsByKeyOptions.cs +++ b/ObjectsComparer/ObjectsComparer/CompareElementsByKeyOptions.cs @@ -8,7 +8,7 @@ namespace ObjectsComparer { /// - /// Configures list element behavior if mode is used. + /// Configures the behavior of list elements if elements are to be compared by key. /// public class CompareElementsByKeyOptions { diff --git a/ObjectsComparer/ObjectsComparer/ListConfigurationOptions.cs b/ObjectsComparer/ObjectsComparer/ListConfigurationOptions.cs index b49b3e0..d224e89 100644 --- a/ObjectsComparer/ObjectsComparer/ListConfigurationOptions.cs +++ b/ObjectsComparer/ObjectsComparer/ListConfigurationOptions.cs @@ -32,11 +32,17 @@ public void CompareElementsByIndex() internal Action KeyOptionsAction { get; private set; } + /// + /// Compares list elements by key. + /// public void CompareElementsByKey() { CompareElementsByKey(options => { }); } + /// + /// Compares list elements by key. + /// public void CompareElementsByKey(Action keyOptions) { if (keyOptions is null) diff --git a/ObjectsComparer/ObjectsComparer/ListElementSearchingMode.cs b/ObjectsComparer/ObjectsComparer/ListElementSearchingMode.cs index f01f1c0..a39e0b2 100644 --- a/ObjectsComparer/ObjectsComparer/ListElementSearchingMode.cs +++ b/ObjectsComparer/ObjectsComparer/ListElementSearchingMode.cs @@ -1,7 +1,7 @@ namespace ObjectsComparer { /// - /// List element searching mode. + /// List element search mode. /// internal enum ListElementSearchMode { From a49b693e012b75463db7aa6ec440772281986a4b Mon Sep 17 00:00:00 2001 From: "ASD\\nemec" Date: Fri, 22 Oct 2021 13:29:08 +0200 Subject: [PATCH 033/181] ComparisonContext: Add Shrink, HasDifferences operations. --- .../Comparer_NonGenericEnumerableTests.cs | 83 ++++++++++++++++++- .../ObjectsComparer/ComparisonContext.cs | 53 +++++++++++- 2 files changed, 132 insertions(+), 4 deletions(-) diff --git a/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs b/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs index fe32616..261da2e 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs @@ -1,5 +1,10 @@ -using System.Collections; +using System; +using System.Collections; using System.Linq; +using System.Reflection; +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; +using Newtonsoft.Json.Serialization; using NUnit.Framework; using ObjectsComparer.Tests.TestClasses; using ObjectsComparer.Utils; @@ -213,6 +218,22 @@ public void RightComparisonContextGraph() var comparer = new Comparer(settings); var rootContext = ComparisonContext.Create(); var differences = comparer.CalculateDifferences(p1, p2, rootContext).ToList(); + var hasDiffs = rootContext.HasDifferences(false); + var scontextBeforeShrink = SerializeComparisonContext(rootContext); + rootContext.Shrink(); + var scontextAfterShrink = SerializeComparisonContext(rootContext); + } + + string SerializeComparisonContext(ComparisonContext context) + { + var settings = new JsonSerializerSettings() + { + ContractResolver = ShouldSerializeContractResolver.Instance, + ReferenceLoopHandling = ReferenceLoopHandling.Ignore, + }; + settings.Converters.Add(new StringEnumConverter { CamelCaseText = true }); + + return JsonConvert.SerializeObject(context, Formatting.None, settings); } [Test] @@ -360,4 +381,64 @@ public void NullAndEmptyEquality() Assert.IsTrue(isEqual); } } + + class ShouldSerializeContractResolver : DefaultContractResolver + { + /* + * https://stackoverflow.com/questions/46977905/overriding-a-property-value-in-custom-json-net-contract-resolver + * https://dotnetfiddle.net/PAZULK + * https://stackoverflow.com/questions/2441290/javascriptserializer-json-serialization-of-enum-as-string + * + */ + public static readonly ShouldSerializeContractResolver Instance = new ShouldSerializeContractResolver(); + + protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization) + { + JsonProperty property = base.CreateProperty(member, memberSerialization); + + if (property.DeclaringType == typeof(ComparisonContext) && property.PropertyName == nameof(ComparisonContext.Member)) + { + property.ShouldSerialize = + instance => + { + //ComparisonContext ctx = (ComparisonContext)instance; + return false; + }; + } + + //if (property.DeclaringType == typeof(Difference) && property.PropertyName == nameof(Difference.DifferenceType)) + //{ + // property.ValueProvider = new ValueProvider(differenceObj => + // { + // var difference = (Difference)differenceObj; + // return difference.DifferenceType.ToString(); + // }); + //} + + return property; + } + } + + class ValueProvider : IValueProvider + { + readonly Func _getValueProviderImpl; + + public ValueProvider(Func valueProviderImpl) + { + _getValueProviderImpl = valueProviderImpl; + } + + + //Ser + public object GetValue(object target) + { + return _getValueProviderImpl(target); + } + + //Deser + public void SetValue(object target, object value) + { + throw new NotImplementedException(); + } + } } diff --git a/ObjectsComparer/ObjectsComparer/ComparisonContext.cs b/ObjectsComparer/ObjectsComparer/ComparisonContext.cs index de7c34a..6c064af 100644 --- a/ObjectsComparer/ObjectsComparer/ComparisonContext.cs +++ b/ObjectsComparer/ObjectsComparer/ComparisonContext.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Collections.ObjectModel; +using System.Linq; using System.Reflection; namespace ObjectsComparer @@ -11,6 +12,8 @@ namespace ObjectsComparer /// public sealed class ComparisonContext { + object _shrinkLock = new object(); + /// /// Creates comparison context root. /// @@ -36,6 +39,8 @@ private ComparisonContext(MemberInfo currentMember) /// public MemberInfo Member { get; } + public string MemberName => Member?.Name; + /// /// Ancestor context. /// @@ -46,6 +51,9 @@ private ComparisonContext(MemberInfo currentMember) /// public ReadOnlyCollection Descendants => _descendants.AsReadOnly(); + /// + /// A list of differences directly related to this context. + /// public ReadOnlyCollection Differences => _differences.AsReadOnly(); /// @@ -82,10 +90,49 @@ internal void AddDifference(Difference difference) _differences.Add(difference); } - //A list of differences directly related to this context. + /// + /// Whether there are differences directly or indirectly related to this context. + /// + /// If value is true, it also looks for in . + public bool HasDifferences(bool recursive) + { + if (_differences.Any()) + { + return true; + } + + if (recursive) + { + return _descendants.Any(d => d.HasDifferences(true)); + } + + return false; + } + + public void Shrink() + { + lock (_shrinkLock) + { + List removeDescendants = new List(); - //Whether the object has any properties (bool recursive). + _descendants.ForEach(d => + { + d.Shrink(); + + if (d.HasDifferences(true) == false) + { + removeDescendants.Add(d); + } + }); + + removeDescendants.ForEach(d => _descendants.Remove(d)); + } + + } - //HasDifferences(bool recursive) + //public bool ShouldSerializeMember() + //{ + // return false; + //} } } \ No newline at end of file From efdab8f32446eb74320ec23e186a4fbf575d4ce3 Mon Sep 17 00:00:00 2001 From: Daniel Nemec Date: Sun, 24 Oct 2021 00:40:18 +0200 Subject: [PATCH 034/181] Add ComparisonContext serialization. --- .../Comparer_NonGenericEnumerableTests.cs | 84 ++++++++++--------- .../CompareElementsByKeyOptions.cs | 6 +- .../ObjectsComparer/ComparisonContext.cs | 14 ++-- 3 files changed, 54 insertions(+), 50 deletions(-) diff --git a/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs b/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs index 261da2e..81f48ee 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs @@ -1,5 +1,6 @@ using System; using System.Collections; +using System.Diagnostics; using System.Linq; using System.Reflection; using Newtonsoft.Json; @@ -228,12 +229,13 @@ string SerializeComparisonContext(ComparisonContext context) { var settings = new JsonSerializerSettings() { - ContractResolver = ShouldSerializeContractResolver.Instance, + ContractResolver = ComparisonContextContractResolver.Instance, ReferenceLoopHandling = ReferenceLoopHandling.Ignore, }; - settings.Converters.Add(new StringEnumConverter { CamelCaseText = true }); + settings.Converters.Add(new StringEnumConverter { CamelCaseText = false }); + settings.Converters.Add(new MemberInfoConverter()); - return JsonConvert.SerializeObject(context, Formatting.None, settings); + return JsonConvert.SerializeObject(context, Formatting.Indented, settings); } [Test] @@ -382,63 +384,69 @@ public void NullAndEmptyEquality() } } - class ShouldSerializeContractResolver : DefaultContractResolver + internal class ComparisonContextContractResolver : DefaultContractResolver { - /* - * https://stackoverflow.com/questions/46977905/overriding-a-property-value-in-custom-json-net-contract-resolver - * https://dotnetfiddle.net/PAZULK - * https://stackoverflow.com/questions/2441290/javascriptserializer-json-serialization-of-enum-as-string - * - */ - public static readonly ShouldSerializeContractResolver Instance = new ShouldSerializeContractResolver(); + public static readonly ComparisonContextContractResolver Instance = new ComparisonContextContractResolver(); protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization) { JsonProperty property = base.CreateProperty(member, memberSerialization); - if (property.DeclaringType == typeof(ComparisonContext) && property.PropertyName == nameof(ComparisonContext.Member)) + if (property.DeclaringType == typeof(ComparisonContext)) { property.ShouldSerialize = instance => { - //ComparisonContext ctx = (ComparisonContext)instance; - return false; + ComparisonContext ctx = (ComparisonContext)instance; + + if (property.PropertyName == nameof(ComparisonContext.Descendants)) + { + return ctx.Descendants.Any(); + } + + if (property.PropertyName == nameof(ComparisonContext.Differences)) + { + return ctx.Differences.Any(); + } + + if (property.PropertyName == nameof(ComparisonContext.Member)) + { + return ctx.Member != null; + } + + if (property.PropertyName == nameof(ComparisonContext.Ancestor)) + { + return ctx.Ancestor != null; + } + + return true; }; } - //if (property.DeclaringType == typeof(Difference) && property.PropertyName == nameof(Difference.DifferenceType)) - //{ - // property.ValueProvider = new ValueProvider(differenceObj => - // { - // var difference = (Difference)differenceObj; - // return difference.DifferenceType.ToString(); - // }); - //} - return property; } } - class ValueProvider : IValueProvider + /// + /// Converts object to JSON. + /// + internal class MemberInfoConverter : JsonConverter { - readonly Func _getValueProviderImpl; - - public ValueProvider(Func valueProviderImpl) - { - _getValueProviderImpl = valueProviderImpl; - } - - - //Ser - public object GetValue(object target) - { - return _getValueProviderImpl(target); + public override void WriteJson(JsonWriter writer, MemberInfo value, JsonSerializer serializer) + { + writer.WriteStartObject(); + writer.WritePropertyName(nameof(MemberInfo.Name)); + writer.WriteValue(value.Name); + writer.WritePropertyName(nameof(MemberInfo.DeclaringType)); + writer.WriteValue(value.DeclaringType.FullName); + writer.WriteEndObject(); } - //Deser - public void SetValue(object target, object value) + public override MemberInfo ReadJson(JsonReader reader, Type objectType, MemberInfo existingValue, bool hasExistingValue, JsonSerializer serializer) { throw new NotImplementedException(); } + + public override bool CanRead => false; } } diff --git a/ObjectsComparer/ObjectsComparer/CompareElementsByKeyOptions.cs b/ObjectsComparer/ObjectsComparer/CompareElementsByKeyOptions.cs index 49ca65a..ec350f4 100644 --- a/ObjectsComparer/ObjectsComparer/CompareElementsByKeyOptions.cs +++ b/ObjectsComparer/ObjectsComparer/CompareElementsByKeyOptions.cs @@ -13,14 +13,14 @@ namespace ObjectsComparer public class CompareElementsByKeyOptions { /// - /// Default key prefix for an integer key. It will be used for formatting property, for example: "Addresses[KEY=123]". + /// Default key prefix for an integer key. It will be used as part of the property, for example: "Addresses[KEY=123]". /// See for more info. /// /// Addresses public const string DefaultIntKeyPrefix = "KEY="; /// - /// Default element identifier for element that refers to null. It will be used for formatting property, for example: "Addresses[NULLREF]". + /// Default element identifier for element that refers to null. It will be used as part of the property, for example: "Addresses[NULLREF]". /// See for more info. /// public const string DefaultNullElementIdentifier = "NULLREF"; @@ -50,7 +50,7 @@ public class CompareElementsByKeyOptions public string KeyPrefix { get; set; } = null; /// - /// If the list element refers to a null value, this symbol will eventually be used as list element identifier in the property. + /// If the list element refers to a null value, this symbol will eventually be used as a list element identifier in the property. /// Default value = . /// If you don't want to use it at all, set this property to . /// diff --git a/ObjectsComparer/ObjectsComparer/ComparisonContext.cs b/ObjectsComparer/ObjectsComparer/ComparisonContext.cs index 6c064af..a32e181 100644 --- a/ObjectsComparer/ObjectsComparer/ComparisonContext.cs +++ b/ObjectsComparer/ObjectsComparer/ComparisonContext.cs @@ -39,8 +39,6 @@ private ComparisonContext(MemberInfo currentMember) /// public MemberInfo Member { get; } - public string MemberName => Member?.Name; - /// /// Ancestor context. /// @@ -109,6 +107,9 @@ public bool HasDifferences(bool recursive) return false; } + /// + /// Removes all which have no directly or indirectly in their . + /// public void Shrink() { lock (_shrinkLock) @@ -125,14 +126,9 @@ public void Shrink() } }); - removeDescendants.ForEach(d => _descendants.Remove(d)); + _descendants.RemoveAll(ctx => removeDescendants.Contains(ctx)); + //removeDescendants.ForEach(d => _descendants.Remove(d)); } - } - - //public bool ShouldSerializeMember() - //{ - // return false; - //} } } \ No newline at end of file From f87ef63652faf34f3c06e42f2ad634fae066ef07 Mon Sep 17 00:00:00 2001 From: Daniel Nemec Date: Sun, 24 Oct 2021 09:42:00 +0200 Subject: [PATCH 035/181] Add ComparisonContext.ToJson extension (test project). --- .../Comparer_NonGenericEnumerableTests.cs | 94 ++------------- ...omparisonContextSerializationExtensions.cs | 114 ++++++++++++++++++ .../CompareElementsByKeyOptions.cs | 4 +- 3 files changed, 124 insertions(+), 88 deletions(-) create mode 100644 ObjectsComparer/ObjectsComparer.Tests/Utils/ComparisonContextSerializationExtensions.cs diff --git a/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs b/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs index 81f48ee..e5d7dc7 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs @@ -8,6 +8,7 @@ using Newtonsoft.Json.Serialization; using NUnit.Framework; using ObjectsComparer.Tests.TestClasses; +using ObjectsComparer.Tests.Utils; using ObjectsComparer.Utils; namespace ObjectsComparer.Tests @@ -162,7 +163,7 @@ public void InequalityCount_InequalityProperty_CompareByKey2() [Test] public void RightComparisonContextGraph() { - var p1 = new Person + var person1 = new Person { FirstName = "FirstName1", LastName = "LastName1", @@ -183,10 +184,10 @@ public void RightComparisonContextGraph() Id = 2, City = "City3" }, - } + }, }; - var p2 = new Person + var person2 = new Person { FirstName = "FirstName2", LastName = "LastName2", @@ -218,26 +219,13 @@ public void RightComparisonContextGraph() var comparer = new Comparer(settings); var rootContext = ComparisonContext.Create(); - var differences = comparer.CalculateDifferences(p1, p2, rootContext).ToList(); + var differences = comparer.CalculateDifferences(person1, person2, rootContext).ToList(); var hasDiffs = rootContext.HasDifferences(false); - var scontextBeforeShrink = SerializeComparisonContext(rootContext); + var scontextBeforeShrink = rootContext.ToJson(); rootContext.Shrink(); - var scontextAfterShrink = SerializeComparisonContext(rootContext); - } - - string SerializeComparisonContext(ComparisonContext context) - { - var settings = new JsonSerializerSettings() - { - ContractResolver = ComparisonContextContractResolver.Instance, - ReferenceLoopHandling = ReferenceLoopHandling.Ignore, - }; - settings.Converters.Add(new StringEnumConverter { CamelCaseText = false }); - settings.Converters.Add(new MemberInfoConverter()); - - return JsonConvert.SerializeObject(context, Formatting.Indented, settings); + var scontextAfterShrink = rootContext.ToJson(); } - + [Test] public void InequalityCount_InequalityProperty_CompareByIndex() { @@ -383,70 +371,4 @@ public void NullAndEmptyEquality() Assert.IsTrue(isEqual); } } - - internal class ComparisonContextContractResolver : DefaultContractResolver - { - public static readonly ComparisonContextContractResolver Instance = new ComparisonContextContractResolver(); - - protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization) - { - JsonProperty property = base.CreateProperty(member, memberSerialization); - - if (property.DeclaringType == typeof(ComparisonContext)) - { - property.ShouldSerialize = - instance => - { - ComparisonContext ctx = (ComparisonContext)instance; - - if (property.PropertyName == nameof(ComparisonContext.Descendants)) - { - return ctx.Descendants.Any(); - } - - if (property.PropertyName == nameof(ComparisonContext.Differences)) - { - return ctx.Differences.Any(); - } - - if (property.PropertyName == nameof(ComparisonContext.Member)) - { - return ctx.Member != null; - } - - if (property.PropertyName == nameof(ComparisonContext.Ancestor)) - { - return ctx.Ancestor != null; - } - - return true; - }; - } - - return property; - } - } - - /// - /// Converts object to JSON. - /// - internal class MemberInfoConverter : JsonConverter - { - public override void WriteJson(JsonWriter writer, MemberInfo value, JsonSerializer serializer) - { - writer.WriteStartObject(); - writer.WritePropertyName(nameof(MemberInfo.Name)); - writer.WriteValue(value.Name); - writer.WritePropertyName(nameof(MemberInfo.DeclaringType)); - writer.WriteValue(value.DeclaringType.FullName); - writer.WriteEndObject(); - } - - public override MemberInfo ReadJson(JsonReader reader, Type objectType, MemberInfo existingValue, bool hasExistingValue, JsonSerializer serializer) - { - throw new NotImplementedException(); - } - - public override bool CanRead => false; - } } diff --git a/ObjectsComparer/ObjectsComparer.Tests/Utils/ComparisonContextSerializationExtensions.cs b/ObjectsComparer/ObjectsComparer.Tests/Utils/ComparisonContextSerializationExtensions.cs new file mode 100644 index 0000000..f5139c8 --- /dev/null +++ b/ObjectsComparer/ObjectsComparer.Tests/Utils/ComparisonContextSerializationExtensions.cs @@ -0,0 +1,114 @@ +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; +using Newtonsoft.Json.Serialization; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; + +namespace ObjectsComparer.Tests.Utils +{ + //TODO: Move ToJson to Core. + + internal static class ComparisonContextSerializationExtensions + { + /// + /// Serializes object to json string. + /// + /// + /// + /// + /// + public static string ToJson(this ComparisonContext comparisonContext, bool skipEmptyList = true, bool skipNullReference = true) + { + return SerializeComparisonContext(comparisonContext, skipEmptyList, skipNullReference); + } + + static string SerializeComparisonContext(ComparisonContext context, bool skipEmptyList, bool skipNullReference) + { + var settings = new JsonSerializerSettings() + { + ContractResolver = new ComparisonContextContractResolver(skipEmptyList, skipNullReference), + ReferenceLoopHandling = ReferenceLoopHandling.Ignore, + }; + settings.Converters.Add(new StringEnumConverter { CamelCaseText = false }); + settings.Converters.Add(new MemberInfoConverter()); + + return JsonConvert.SerializeObject(context, Formatting.Indented, settings); + } + + /// + /// Converts object to JSON. + /// + class MemberInfoConverter : JsonConverter + { + public override void WriteJson(JsonWriter writer, MemberInfo value, JsonSerializer serializer) + { + writer.WriteStartObject(); + writer.WritePropertyName(nameof(MemberInfo.Name)); + writer.WriteValue(value.Name); + writer.WritePropertyName(nameof(MemberInfo.DeclaringType)); + writer.WriteValue(value.DeclaringType.FullName); + writer.WriteEndObject(); + } + + public override MemberInfo ReadJson(JsonReader reader, Type objectType, MemberInfo existingValue, bool hasExistingValue, JsonSerializer serializer) + { + throw new NotImplementedException(); + } + + public override bool CanRead => false; + } + + class ComparisonContextContractResolver : DefaultContractResolver + { + readonly bool _skipEmptyList; + readonly bool _skipNullReference; + + public ComparisonContextContractResolver(bool skipEmptyList = true, bool skipNullReference = true) + { + _skipEmptyList = skipEmptyList; + _skipNullReference = skipNullReference; + } + + protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization) + { + JsonProperty property = base.CreateProperty(member, memberSerialization); + + if (property.DeclaringType == typeof(ComparisonContext)) + { + property.ShouldSerialize = + instance => + { + ComparisonContext ctx = (ComparisonContext)instance; + + if (property.PropertyName == nameof(ComparisonContext.Descendants)) + { + return _skipEmptyList == false || ctx.Descendants.Any(); + } + + if (property.PropertyName == nameof(ComparisonContext.Differences)) + { + return _skipEmptyList == false || ctx.Differences.Any(); + } + + if (property.PropertyName == nameof(ComparisonContext.Member)) + { + return _skipNullReference == false || ctx.Member != null; + } + + if (property.PropertyName == nameof(ComparisonContext.Ancestor)) + { + return _skipNullReference == false || ctx.Ancestor != null; + } + + return true; + }; + } + + return property; + } + } + } +} diff --git a/ObjectsComparer/ObjectsComparer/CompareElementsByKeyOptions.cs b/ObjectsComparer/ObjectsComparer/CompareElementsByKeyOptions.cs index ec350f4..b9d4969 100644 --- a/ObjectsComparer/ObjectsComparer/CompareElementsByKeyOptions.cs +++ b/ObjectsComparer/ObjectsComparer/CompareElementsByKeyOptions.cs @@ -62,7 +62,7 @@ void Initialize() } /// - /// Compares list elements by key. It will try to find a property specified by argument . + /// Compares list elements by key. It will try to find a property specified by parameter. /// public void UseKey(string key, bool caseSensitive = false) { @@ -75,7 +75,7 @@ public void UseKey(string key, bool caseSensitive = false) } /// - /// Compares list elements by key. It will try to find one of the public properties specified by argument , in that order. + /// Compares list elements by key. It will try to find one of the public properties specified by parameter, in that order. /// public void UseKey(string[] keys, bool caseSensitive = false) { From 041f78a5a0ae919fd9d214473ba6c50af3fe8f81 Mon Sep 17 00:00:00 2001 From: Daniel Nemec Date: Sun, 24 Oct 2021 12:28:02 +0200 Subject: [PATCH 036/181] Add ListComparisonSettings.Configure overload. --- .../Comparer_NonGenericEnumerableTests.cs | 16 ++++++++------- ...omparisonContextSerializationExtensions.cs | 20 +++++++++++++++++++ .../ObjectsComparer/ListComparisonSettings.cs | 14 ++++++++++++- 3 files changed, 42 insertions(+), 8 deletions(-) diff --git a/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs b/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs index e5d7dc7..52e147f 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs @@ -166,13 +166,14 @@ public void RightComparisonContextGraph() var person1 = new Person { FirstName = "FirstName1", - LastName = "LastName1", + LastName = "LastName 1", NonGenericLiveAddresses = new ArrayList { new Address { Id = 1, - City = "City1" + City = "City 1", + State = "State 1" }, new Address{} @@ -182,15 +183,15 @@ public void RightComparisonContextGraph() new Address { Id = 2, - City = "City3" + City = "City 3" }, }, }; var person2 = new Person { - FirstName = "FirstName2", - LastName = "LastName2", + FirstName = "FirstName 2", + LastName = "LastName 2", NonGenericLiveAddresses = new ArrayList { null, @@ -198,7 +199,8 @@ public void RightComparisonContextGraph() new Address { Id = 1, - City = "City2" + City = "City 2", + State = "State 2" }, null @@ -207,7 +209,7 @@ public void RightComparisonContextGraph() var settings = new ComparisonSettings(); - settings.List.Configure((_, options) => + settings.List.Configure(options => { options.CompareUnequalLists = true; options.CompareElementsByKey(keyOptions => diff --git a/ObjectsComparer/ObjectsComparer.Tests/Utils/ComparisonContextSerializationExtensions.cs b/ObjectsComparer/ObjectsComparer.Tests/Utils/ComparisonContextSerializationExtensions.cs index f5139c8..0e549da 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/Utils/ComparisonContextSerializationExtensions.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/Utils/ComparisonContextSerializationExtensions.cs @@ -105,10 +105,30 @@ protected override JsonProperty CreateProperty(MemberInfo member, MemberSerializ return true; }; + + //if (property.PropertyName == nameof(ComparisonContext.Ancestor)) + //{ + // property.ValueProvider = new AncestorValueProvider(); + //} } return property; } } + + //class AncestorValueProvider : IValueProvider + //{ + // public object GetValue(object target) + // { + // var ancestor = (target as ComparisonContext).Ancestor; + // var newAncestor = ComparisonContext.Create(member: ancestor?.Member); + // return newAncestor; + // } + + // public void SetValue(object target, object value) + // { + // throw new NotImplementedException(); + // } + //} } } diff --git a/ObjectsComparer/ObjectsComparer/ListComparisonSettings.cs b/ObjectsComparer/ObjectsComparer/ListComparisonSettings.cs index 03603fc..a578f5c 100644 --- a/ObjectsComparer/ObjectsComparer/ListComparisonSettings.cs +++ b/ObjectsComparer/ObjectsComparer/ListComparisonSettings.cs @@ -14,7 +14,6 @@ public class ListComparisonSettings /// /// Configures list comparison behavior. /// - /// public void Configure(Action configureOptions) { if (configureOptions is null) @@ -24,5 +23,18 @@ public void Configure(Action config ConfigureOptionsAction = configureOptions; } + + /// + /// Configures list comparison behavior. + /// + public void Configure(Action configureOptions) + { + if (configureOptions is null) + { + throw new ArgumentNullException(nameof(configureOptions)); + } + + ConfigureOptionsAction = (_, opt) => configureOptions(opt); + } } } From facc1337ba81c2b30a4e73312cda60967e5ac8e2 Mon Sep 17 00:00:00 2001 From: "ASD\\nemec" Date: Mon, 25 Oct 2021 13:31:51 +0200 Subject: [PATCH 037/181] Add FormatElementKey, FormatNullElementIdentifier operation. Customize element key a null reference element identifier for Difference.MemberPath. --- .../Comparer_NonGenericEnumerableTests.cs | 8 +- .../CompareElementsByKeyOptions.cs | 91 ++++++++++--------- .../CustomComparers/EnumerablesComparer.cs | 25 +++-- 3 files changed, 68 insertions(+), 56 deletions(-) diff --git a/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs b/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs index 52e147f..9686b8a 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs @@ -209,13 +209,15 @@ public void RightComparisonContextGraph() var settings = new ComparisonSettings(); - settings.List.Configure(options => + settings.List.Configure((ctx, options) => { options.CompareUnequalLists = true; options.CompareElementsByKey(keyOptions => { - keyOptions.KeyPrefix = "Key: "; - keyOptions.NullElementIdentifier = "Null-ref"; + keyOptions.FormatElementKey((index, key) => $"Key: {key}"); + //keyOptions.FormatNullElementidentifier = index => $"NULLREFAT-{index}"; + //keyOptions.NullElementIdentifier = "Null-ref"; + //keyOptions.FormatNullElementIdentifier(index => $"NULLREFAT-{index}"); }); }); diff --git a/ObjectsComparer/ObjectsComparer/CompareElementsByKeyOptions.cs b/ObjectsComparer/ObjectsComparer/CompareElementsByKeyOptions.cs index b9d4969..c8e200b 100644 --- a/ObjectsComparer/ObjectsComparer/CompareElementsByKeyOptions.cs +++ b/ObjectsComparer/ObjectsComparer/CompareElementsByKeyOptions.cs @@ -13,24 +13,24 @@ namespace ObjectsComparer public class CompareElementsByKeyOptions { /// - /// Default key prefix for an integer key. It will be used as part of the property, for example: "Addresses[KEY=123]". - /// See for more info. + /// Default identifier template for those elements that refer null value. + /// It will be used as part of the property. + /// For example: "Addresses[NULL_74]" that means there is an element at index 74 in the property Addresses that refers null value. + /// See for more info. /// - /// Addresses - public const string DefaultIntKeyPrefix = "KEY="; - - /// - /// Default element identifier for element that refers to null. It will be used as part of the property, for example: "Addresses[NULLREF]". - /// See for more info. - /// - public const string DefaultNullElementIdentifier = "NULLREF"; + public const string DefaultNullElementIdentifierTemplate = "NULL_{0}"; CompareElementsByKeyOptions() { Initialize(); } - internal static CompareElementsByKeyOptions Default() => new CompareElementsByKeyOptions(); + /// + /// See . + /// + internal Func ElementKeyFormatter { get; private set; } + + internal Func NullElementIdentifierFormatter { get; private set; } /// /// If value = false and element key will not be found, the element will be excluded from comparison and no difference will be logged. If value = true and element key will not be found, an exception of type will be thrown. @@ -43,18 +43,14 @@ public class CompareElementsByKeyOptions /// internal Func KeyProvider { get; private set; } = null; - /// - /// To avoid confusion with the index, an optional key element prefix can be used. If value = null, which is the default value, will be used for integer key type and no prefix will be used for other types. - /// If you don't want to use prefix at all, set this property to . - /// - public string KeyPrefix { get; set; } = null; - /// /// If the list element refers to a null value, this symbol will eventually be used as a list element identifier in the property. - /// Default value = . + /// Default value = . /// If you don't want to use it at all, set this property to . /// - public string NullElementIdentifier { get; set; } = DefaultNullElementIdentifier; + public string NullElementIdentifier { get; set; } = DefaultNullElementIdentifierTemplate; + + internal static CompareElementsByKeyOptions Default() => new CompareElementsByKeyOptions(); void Initialize() { @@ -141,49 +137,58 @@ static object GetKeyValue(object instance, bool caseSensitive, params string[] k } /// - /// See . + /// Obtains formatted or unformatted . See . /// - internal static string ResolveKeyPrefix(object elementKey, CompareElementsByKeyOptions options) + /// + /// + /// + internal string GetFormattedElementKey(int elementIndex, object elementKey) { - if (elementKey is null) - { - throw new ArgumentNullException(nameof(elementKey)); - } + var formattedKey = ElementKeyFormatter?.Invoke(elementIndex, elementKey); - if (options is null) + if (string.IsNullOrWhiteSpace(formattedKey)) { - throw new ArgumentNullException(nameof(options)); + formattedKey = elementKey.ToString(); } - if (options.KeyPrefix == string.Empty) - { - return string.Empty; - } + return formattedKey.Left(50); //This must be enough for a long data type and some prefix. + } - if (options.KeyPrefix == null) + internal string GetFormattedNullElementIdentifier(int elementIndex) + { + var elementIdentifier = NullElementIdentifierFormatter?.Invoke(elementIndex); + + if (string.IsNullOrWhiteSpace(elementIdentifier)) { - if (elementKey is byte || elementKey is short || elementKey is int || elementKey is long) - { - return DefaultIntKeyPrefix; - } + elementIdentifier = string.Format(DefaultNullElementIdentifierTemplate, elementIndex); } - return options.KeyPrefix.Left(10); + return elementIdentifier.Left(20); } - internal static string ResolveNullElementIdentifier(CompareElementsByKeyOptions options) + /// + /// To avoid possible confusion of the element key with the element index, the element key can be formatted with any text, e.g. element key with value = 1 can be formatted as "Key=1". + /// The formatted key is then used as part of the property, e.g. "...Addresses[Key=1]". + /// + /// First parameter: Element index. Second parameter: Element key. Return value: Formatted key. + public void FormatElementKey(Func formatter) { - if (options is null) + if (formatter is null) { - throw new ArgumentNullException(nameof(options)); + throw new ArgumentNullException(nameof(formatter)); } - if (options.NullElementIdentifier == null) + ElementKeyFormatter = formatter; + } + + public void FormatNullElementIdentifier(Func formatter) + { + if (formatter is null) { - return string.Empty; + throw new ArgumentNullException(nameof(formatter)); } - return options.NullElementIdentifier.Left(10); + NullElementIdentifierFormatter = formatter; } } } diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs index 72b3cdf..338c3b8 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs @@ -96,10 +96,10 @@ private IEnumerable CalculateDifferencesByKey(object[] array1, objec var keyOptions = CompareElementsByKeyOptions.Default(); listConfigurationOptions.KeyOptionsAction?.Invoke(keyOptions); - var nullElementIdentifier = CompareElementsByKeyOptions.ResolveNullElementIdentifier(keyOptions); - foreach (var element1 in array1) + for (int element1Index = 0; element1Index < array1.Length; element1Index++) { + var element1 = array1[element1Index]; var elementContext = ComparisonContext.Create(member: null, ancestor: listComparisonContext); if (element1 == null) @@ -109,7 +109,9 @@ private IEnumerable CalculateDifferencesByKey(object[] array1, objec continue; } - yield return AddDifferenceToComparisonContext(new Difference($"[{nullElementIdentifier}]", string.Empty, string.Empty, DifferenceTypes.MissedElementInSecondObject), elementContext); + var formattedNullElementIdentifier = keyOptions.GetFormattedNullElementIdentifier(element1Index); + + yield return AddDifferenceToComparisonContext(new Difference($"[{formattedNullElementIdentifier}]", string.Empty, string.Empty, DifferenceTypes.MissedElementInSecondObject), elementContext); continue; } @@ -125,7 +127,7 @@ private IEnumerable CalculateDifferencesByKey(object[] array1, objec continue; } - var keyPrefix = CompareElementsByKeyOptions.ResolveKeyPrefix(element1Key, keyOptions); + var formattedElement1Key = keyOptions.GetFormattedElementKey(element1Index, element1Key); if (array2.Any(elm2 => object.Equals(element1Key, keyOptions.KeyProvider(elm2)))) { @@ -134,18 +136,20 @@ private IEnumerable CalculateDifferencesByKey(object[] array1, objec foreach (var failure in comparer.CalculateDifferences(element1.GetType(), element1, element2, elementContext)) { - yield return failure.InsertPath($"[{keyPrefix}{element1Key}]"); + yield return failure.InsertPath($"[{formattedElement1Key}]"); } } else { var valueComparer1 = OverridesCollection.GetComparer(element1.GetType()) ?? DefaultValueComparer; - yield return AddDifferenceToComparisonContext(new Difference($"[{keyPrefix}{element1Key}]", valueComparer1.ToString(element1), string.Empty, DifferenceTypes.MissedElementInSecondObject), elementContext); + yield return AddDifferenceToComparisonContext(new Difference($"[{formattedElement1Key}]", valueComparer1.ToString(element1), string.Empty, DifferenceTypes.MissedElementInSecondObject), elementContext); } } - foreach (var element2 in array2) + for (int element2Index = 0; element2Index < array2.Length; element2Index++) { + var element2 = array2[element2Index]; + if (element2 == null) { if (array1.Any(elm1 => elm1 == null)) @@ -154,8 +158,9 @@ private IEnumerable CalculateDifferencesByKey(object[] array1, objec } var elementContext = ComparisonContext.Create(member: null, ancestor: listComparisonContext); + var formattedNullElementIdentifier = keyOptions.GetFormattedNullElementIdentifier(element2Index); - yield return AddDifferenceToComparisonContext(new Difference($"[{nullElementIdentifier}]", string.Empty, string.Empty, DifferenceTypes.MissedElementInFirstObject), elementContext); + yield return AddDifferenceToComparisonContext(new Difference($"[{formattedNullElementIdentifier}]", string.Empty, string.Empty, DifferenceTypes.MissedElementInFirstObject), elementContext); continue; } @@ -174,9 +179,9 @@ private IEnumerable CalculateDifferencesByKey(object[] array1, objec if (array1.Any(elm1 => object.Equals(element2Key, keyOptions.KeyProvider(elm1))) == false) { var elementContext = ComparisonContext.Create(member: null, ancestor: listComparisonContext); - var keyPrefix = CompareElementsByKeyOptions.ResolveKeyPrefix(element2Key, keyOptions); + var formattedElement2Key = keyOptions.GetFormattedElementKey(element2Index, element2Key); var valueComparer2 = OverridesCollection.GetComparer(element2.GetType()) ?? DefaultValueComparer; - yield return AddDifferenceToComparisonContext(new Difference($"[{keyPrefix}{element2Key}]", string.Empty, valueComparer2.ToString(element2), DifferenceTypes.MissedElementInFirstObject), elementContext); + yield return AddDifferenceToComparisonContext(new Difference($"[{formattedElement2Key}]", string.Empty, valueComparer2.ToString(element2), DifferenceTypes.MissedElementInFirstObject), elementContext); } } } From 9e27115a77d5b09bff0e0d9a495c8afe265eacbb Mon Sep 17 00:00:00 2001 From: "ASD\\nemec" Date: Tue, 26 Oct 2021 08:30:01 +0200 Subject: [PATCH 038/181] Edit comments. --- .../CompareElementsByKeyOptions.cs | 29 +++++++++++-------- 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/ObjectsComparer/ObjectsComparer/CompareElementsByKeyOptions.cs b/ObjectsComparer/ObjectsComparer/CompareElementsByKeyOptions.cs index c8e200b..d0d8f49 100644 --- a/ObjectsComparer/ObjectsComparer/CompareElementsByKeyOptions.cs +++ b/ObjectsComparer/ObjectsComparer/CompareElementsByKeyOptions.cs @@ -13,9 +13,9 @@ namespace ObjectsComparer public class CompareElementsByKeyOptions { /// - /// Default identifier template for those elements that refer null value. + /// Default identifier template for those elements that refer to null value. /// It will be used as part of the property. - /// For example: "Addresses[NULL_74]" that means there is an element at index 74 in the property Addresses that refers null value. + /// For example value "Addresses[NULL_74]" in the property means that there is an element that refers to null value at index 74 in the Addresses property. /// See for more info. /// public const string DefaultNullElementIdentifierTemplate = "NULL_{0}"; @@ -30,10 +30,14 @@ public class CompareElementsByKeyOptions /// internal Func ElementKeyFormatter { get; private set; } + /// + /// See . + /// internal Func NullElementIdentifierFormatter { get; private set; } /// - /// If value = false and element key will not be found, the element will be excluded from comparison and no difference will be logged. If value = true and element key will not be found, an exception of type will be thrown. + /// If value = false and element key will not be found, the element will be excluded from comparison and no difference will be logged except for possible . + /// If value = true and element key will not be found, an exception of type will be thrown. /// Default value = true. /// public bool ThrowKeyNotFound { get; set; } = true; @@ -43,13 +47,6 @@ public class CompareElementsByKeyOptions /// internal Func KeyProvider { get; private set; } = null; - /// - /// If the list element refers to a null value, this symbol will eventually be used as a list element identifier in the property. - /// Default value = . - /// If you don't want to use it at all, set this property to . - /// - public string NullElementIdentifier { get; set; } = DefaultNullElementIdentifierTemplate; - internal static CompareElementsByKeyOptions Default() => new CompareElementsByKeyOptions(); void Initialize() @@ -99,6 +96,7 @@ public void UseKey(string[] keys, bool caseSensitive = false) /// /// Compares list elements by key using . /// + /// First parameter: The element whose key is required. Return value: The element's key. public void UseKey(Func keyProvider) { if (keyProvider is null) @@ -167,8 +165,10 @@ internal string GetFormattedNullElementIdentifier(int elementIndex) } /// - /// To avoid possible confusion of the element key with the element index, the element key can be formatted with any text, e.g. element key with value = 1 can be formatted as "Key=1". - /// The formatted key is then used as part of the property, e.g. "...Addresses[Key=1]". + /// To avoid possible confusion of the element key with the element index, the element key can be formatted with any text.
+ /// For example, element key with value = 1 can be formatted as "Id=1". + /// The formatted key is then used as part of the property, e.g. "...Addresses[Id=1]".
+ /// By default, the key will not be formatted. ///
/// First parameter: Element index. Second parameter: Element key. Return value: Formatted key. public void FormatElementKey(Func formatter) @@ -181,6 +181,11 @@ public void FormatElementKey(Func formatter) ElementKeyFormatter = formatter; } + /// + /// Formats identifier of the element that refers to null value. Formatted identifier is then used as part of the property.
+ /// By default, template will be used for format the identifier. + ///
+ /// First parameter: Element index. Return value: Formatted identifier. public void FormatNullElementIdentifier(Func formatter) { if (formatter is null) From 19b1bbb9ed7116486dd5a0f74d87c75f5df1a0ab Mon Sep 17 00:00:00 2001 From: "ASD\\nemec" Date: Tue, 26 Oct 2021 13:37:25 +0200 Subject: [PATCH 039/181] Edit comments. --- .../CompareElementsByKeyOptions.cs | 16 +++++++++++++--- .../ObjectsComparer/IComparerExtensions.cs | 13 +++++++++++++ 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/ObjectsComparer/ObjectsComparer/CompareElementsByKeyOptions.cs b/ObjectsComparer/ObjectsComparer/CompareElementsByKeyOptions.cs index d0d8f49..406d7c5 100644 --- a/ObjectsComparer/ObjectsComparer/CompareElementsByKeyOptions.cs +++ b/ObjectsComparer/ObjectsComparer/CompareElementsByKeyOptions.cs @@ -20,6 +20,16 @@ public class CompareElementsByKeyOptions /// public const string DefaultNullElementIdentifierTemplate = "NULL_{0}"; + /// + /// Max. length of the formatted key of the element. See . + /// + const int FormattedKeyMaxLength = 50; + + /// + /// Max. length of the identifier of the element that refers to null value. See . + /// + const int NullElementIdentifierMaxLength = 20; + CompareElementsByKeyOptions() { Initialize(); @@ -36,7 +46,7 @@ public class CompareElementsByKeyOptions internal Func NullElementIdentifierFormatter { get; private set; } /// - /// If value = false and element key will not be found, the element will be excluded from comparison and no difference will be logged except for possible . + /// If value = false and element key will not be found, the element will be excluded from comparison and no difference will be added except for possible difference. /// If value = true and element key will not be found, an exception of type will be thrown. /// Default value = true. /// @@ -149,7 +159,7 @@ internal string GetFormattedElementKey(int elementIndex, object elementKey) formattedKey = elementKey.ToString(); } - return formattedKey.Left(50); //This must be enough for a long data type and some prefix. + return formattedKey.Left(FormattedKeyMaxLength); //This must be enough for a long data type and some prefix. } internal string GetFormattedNullElementIdentifier(int elementIndex) @@ -161,7 +171,7 @@ internal string GetFormattedNullElementIdentifier(int elementIndex) elementIdentifier = string.Format(DefaultNullElementIdentifierTemplate, elementIndex); } - return elementIdentifier.Left(20); + return elementIdentifier.Left(NullElementIdentifierMaxLength); } ///
diff --git a/ObjectsComparer/ObjectsComparer/IComparerExtensions.cs b/ObjectsComparer/ObjectsComparer/IComparerExtensions.cs index 1bd9218..6817f95 100644 --- a/ObjectsComparer/ObjectsComparer/IComparerExtensions.cs +++ b/ObjectsComparer/ObjectsComparer/IComparerExtensions.cs @@ -3,8 +3,21 @@ namespace ObjectsComparer { + /// + /// Extends interface with an overloaded operation CalculateDifferences, that accepts parameter. + /// public static class IComparerExtensions { + /// + /// Calculates list of differences between objects. Accepts comparison context. + /// At the beginning of the comparison you can create instance using the operation and pass it as a parameter. + /// For more info about comparison context see class. + /// + /// Type. + /// Object 1. + /// Object 2. + /// Current comparison context. For more info see class. + /// List of differences between objects. public static IEnumerable CalculateDifferences(this IComparer comparer, Type type, object obj1, object obj2, ComparisonContext comparisonContext) { if (comparer is IContextableComparer contextableComparer) From 33bbb3e8ff6322aa4c6c9181d756cef4a6acaa45 Mon Sep 17 00:00:00 2001 From: "ASD\\nemec" Date: Wed, 27 Oct 2021 10:38:26 +0200 Subject: [PATCH 040/181] Set ListComparisonSettings constructor as private. Improve comments in source code. --- .../CompareElementsByKeyOptions.cs | 34 ++++++++++--------- .../ObjectsComparer/ComparisonSettings.cs | 2 +- .../CustomComparers/EnumerablesComparer.cs | 28 +++++++-------- .../ObjectsComparer/ListComparisonSettings.cs | 4 +++ 4 files changed, 37 insertions(+), 31 deletions(-) diff --git a/ObjectsComparer/ObjectsComparer/CompareElementsByKeyOptions.cs b/ObjectsComparer/ObjectsComparer/CompareElementsByKeyOptions.cs index 406d7c5..ef32213 100644 --- a/ObjectsComparer/ObjectsComparer/CompareElementsByKeyOptions.cs +++ b/ObjectsComparer/ObjectsComparer/CompareElementsByKeyOptions.cs @@ -13,12 +13,9 @@ namespace ObjectsComparer public class CompareElementsByKeyOptions { /// - /// Default identifier template for those elements that refer to null value. - /// It will be used as part of the property. - /// For example value "Addresses[NULL_74]" in the property means that there is an element that refers to null value at index 74 in the Addresses property. - /// See for more info. + /// Default element identifier template for element that refers to null value. See for more info. /// - public const string DefaultNullElementIdentifierTemplate = "NULL_{0}"; + public const string DefaultNullElementIdentifierTemplate = "NullAtIdx:{0}"; /// /// Max. length of the formatted key of the element. See . @@ -38,12 +35,12 @@ public class CompareElementsByKeyOptions /// /// See . /// - internal Func ElementKeyFormatter { get; private set; } + Func ElementKeyFormatter { get; set; } /// /// See . /// - internal Func NullElementIdentifierFormatter { get; private set; } + Func NullElementIdentifierFormatter { get; set; } /// /// If value = false and element key will not be found, the element will be excluded from comparison and no difference will be added except for possible difference. @@ -145,13 +142,15 @@ static object GetKeyValue(object instance, bool caseSensitive, params string[] k } /// - /// Obtains formatted or unformatted . See . + /// Returns optional formatted or unformatted . See . /// - /// - /// - /// internal string GetFormattedElementKey(int elementIndex, object elementKey) { + if (elementKey is null) + { + throw new ArgumentNullException(nameof(elementKey)); + } + var formattedKey = ElementKeyFormatter?.Invoke(elementIndex, elementKey); if (string.IsNullOrWhiteSpace(formattedKey)) @@ -159,9 +158,12 @@ internal string GetFormattedElementKey(int elementIndex, object elementKey) formattedKey = elementKey.ToString(); } - return formattedKey.Left(FormattedKeyMaxLength); //This must be enough for a long data type and some prefix. + return formattedKey.Left(FormattedKeyMaxLength); } + /// + /// Returns formatted element identifier that referes to null. See . + /// internal string GetFormattedNullElementIdentifier(int elementIndex) { var elementIdentifier = NullElementIdentifierFormatter?.Invoke(elementIndex); @@ -177,8 +179,8 @@ internal string GetFormattedNullElementIdentifier(int elementIndex) /// /// To avoid possible confusion of the element key with the element index, the element key can be formatted with any text.
/// For example, element key with value = 1 can be formatted as "Id=1". - /// The formatted key is then used as part of the property, e.g. "...Addresses[Id=1]".
- /// By default, the key will not be formatted. + /// The formatted element key is then used as part of the property, e.g. "Addresses[Id=1]".
+ /// By default, the element key will not be formatted. ///
/// First parameter: Element index. Second parameter: Element key. Return value: Formatted key. public void FormatElementKey(Func formatter) @@ -192,8 +194,8 @@ public void FormatElementKey(Func formatter) } /// - /// Formats identifier of the element that refers to null value. Formatted identifier is then used as part of the property.
- /// By default, template will be used for format the identifier. + /// Formats the element identifier if it refers to null. Formatted identifier is then used as part of the property.
+ /// By default, template will be used to format the identifier. ///
/// First parameter: Element index. Return value: Formatted identifier. public void FormatNullElementIdentifier(Func formatter) diff --git a/ObjectsComparer/ObjectsComparer/ComparisonSettings.cs b/ObjectsComparer/ObjectsComparer/ComparisonSettings.cs index ad86244..9a9b159 100644 --- a/ObjectsComparer/ObjectsComparer/ComparisonSettings.cs +++ b/ObjectsComparer/ObjectsComparer/ComparisonSettings.cs @@ -30,7 +30,7 @@ public class ComparisonSettings /// /// List comparison settings. /// - public ListComparisonSettings List { get; } = new ListComparisonSettings(); + public ListComparisonSettings List { get; } = ListComparisonSettings.Default(); /// /// Initializes a new instance of the class. diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs index 338c3b8..0310968 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs @@ -100,7 +100,7 @@ private IEnumerable CalculateDifferencesByKey(object[] array1, objec for (int element1Index = 0; element1Index < array1.Length; element1Index++) { var element1 = array1[element1Index]; - var elementContext = ComparisonContext.Create(member: null, ancestor: listComparisonContext); + var elementComparisonContext = ComparisonContext.Create(ancestor: listComparisonContext); if (element1 == null) { @@ -111,7 +111,7 @@ private IEnumerable CalculateDifferencesByKey(object[] array1, objec var formattedNullElementIdentifier = keyOptions.GetFormattedNullElementIdentifier(element1Index); - yield return AddDifferenceToComparisonContext(new Difference($"[{formattedNullElementIdentifier}]", string.Empty, string.Empty, DifferenceTypes.MissedElementInSecondObject), elementContext); + yield return AddDifferenceToComparisonContext(new Difference($"[{formattedNullElementIdentifier}]", string.Empty, string.Empty, DifferenceTypes.MissedElementInSecondObject), elementComparisonContext); continue; } @@ -134,7 +134,7 @@ private IEnumerable CalculateDifferencesByKey(object[] array1, objec var element2 = array2.First(elm2 => object.Equals(element1Key, keyOptions.KeyProvider(elm2))); var comparer = Factory.GetObjectsComparer(element1.GetType(), Settings, this); - foreach (var failure in comparer.CalculateDifferences(element1.GetType(), element1, element2, elementContext)) + foreach (var failure in comparer.CalculateDifferences(element1.GetType(), element1, element2, elementComparisonContext)) { yield return failure.InsertPath($"[{formattedElement1Key}]"); } @@ -142,7 +142,7 @@ private IEnumerable CalculateDifferencesByKey(object[] array1, objec else { var valueComparer1 = OverridesCollection.GetComparer(element1.GetType()) ?? DefaultValueComparer; - yield return AddDifferenceToComparisonContext(new Difference($"[{formattedElement1Key}]", valueComparer1.ToString(element1), string.Empty, DifferenceTypes.MissedElementInSecondObject), elementContext); + yield return AddDifferenceToComparisonContext(new Difference($"[{formattedElement1Key}]", valueComparer1.ToString(element1), string.Empty, DifferenceTypes.MissedElementInSecondObject), elementComparisonContext); } } @@ -157,10 +157,10 @@ private IEnumerable CalculateDifferencesByKey(object[] array1, objec continue; } - var elementContext = ComparisonContext.Create(member: null, ancestor: listComparisonContext); + var elementComparisonContext = ComparisonContext.Create(ancestor: listComparisonContext); var formattedNullElementIdentifier = keyOptions.GetFormattedNullElementIdentifier(element2Index); - yield return AddDifferenceToComparisonContext(new Difference($"[{formattedNullElementIdentifier}]", string.Empty, string.Empty, DifferenceTypes.MissedElementInFirstObject), elementContext); + yield return AddDifferenceToComparisonContext(new Difference($"[{formattedNullElementIdentifier}]", string.Empty, string.Empty, DifferenceTypes.MissedElementInFirstObject), elementComparisonContext); continue; } @@ -178,10 +178,10 @@ private IEnumerable CalculateDifferencesByKey(object[] array1, objec if (array1.Any(elm1 => object.Equals(element2Key, keyOptions.KeyProvider(elm1))) == false) { - var elementContext = ComparisonContext.Create(member: null, ancestor: listComparisonContext); + var elementComparisonContext = ComparisonContext.Create(ancestor: listComparisonContext); var formattedElement2Key = keyOptions.GetFormattedElementKey(element2Index, element2Key); var valueComparer2 = OverridesCollection.GetComparer(element2.GetType()) ?? DefaultValueComparer; - yield return AddDifferenceToComparisonContext(new Difference($"[{formattedElement2Key}]", string.Empty, valueComparer2.ToString(element2), DifferenceTypes.MissedElementInFirstObject), elementContext); + yield return AddDifferenceToComparisonContext(new Difference($"[{formattedElement2Key}]", string.Empty, valueComparer2.ToString(element2), DifferenceTypes.MissedElementInFirstObject), elementComparisonContext); } } } @@ -197,7 +197,7 @@ private IEnumerable CalculateDifferencesByIndex(object[] array1, obj //ToDo Extract type for (var i = 0; i < smallerCount; i++) { - var elementContext = ComparisonContext.Create(member: null, ancestor: listComparisonContext); + var elementComparisonContext = ComparisonContext.Create(ancestor: listComparisonContext); if (array1[i] == null && array2[i] == null) { @@ -209,25 +209,25 @@ private IEnumerable CalculateDifferencesByIndex(object[] array1, obj if (array1[i] == null) { - yield return AddDifferenceToComparisonContext(new Difference($"[{i}]", string.Empty, valueComparer2.ToString(array2[i])), elementContext); + yield return AddDifferenceToComparisonContext(new Difference($"[{i}]", string.Empty, valueComparer2.ToString(array2[i])), elementComparisonContext); continue; } if (array2[i] == null) { - yield return AddDifferenceToComparisonContext(new Difference($"[{i}]", valueComparer1.ToString(array1[i]), string.Empty), elementContext); + yield return AddDifferenceToComparisonContext(new Difference($"[{i}]", valueComparer1.ToString(array1[i]), string.Empty), elementComparisonContext); continue; } if (array1[i].GetType() != array2[i].GetType()) { - yield return AddDifferenceToComparisonContext(new Difference($"[{i}]", valueComparer1.ToString(array1[i]), valueComparer2.ToString(array2[i]), DifferenceTypes.TypeMismatch), elementContext); + yield return AddDifferenceToComparisonContext(new Difference($"[{i}]", valueComparer1.ToString(array1[i]), valueComparer2.ToString(array2[i]), DifferenceTypes.TypeMismatch), elementComparisonContext); continue; } var comparer = Factory.GetObjectsComparer(array1[i].GetType(), Settings, this); - foreach (var failure in comparer.CalculateDifferences(array1[i].GetType(), array1[i], array2[i], elementContext)) + foreach (var failure in comparer.CalculateDifferences(array1[i].GetType(), array1[i], array2[i], elementComparisonContext)) { yield return failure.InsertPath($"[{i}]"); } @@ -248,7 +248,7 @@ private IEnumerable CalculateDifferencesByIndex(object[] array1, obj value2: array2Count > array1Count ? valueComparer.ToString(largerArray[i]) : string.Empty, differenceType: array1Count > array2Count ? DifferenceTypes.MissedElementInSecondObject : DifferenceTypes.MissedElementInFirstObject); - yield return AddDifferenceToComparisonContext(difference, ComparisonContext.Create(member: null, ancestor: listComparisonContext)); + yield return AddDifferenceToComparisonContext(difference, ComparisonContext.Create(ancestor: listComparisonContext)); } } } diff --git a/ObjectsComparer/ObjectsComparer/ListComparisonSettings.cs b/ObjectsComparer/ObjectsComparer/ListComparisonSettings.cs index a578f5c..39633cf 100644 --- a/ObjectsComparer/ObjectsComparer/ListComparisonSettings.cs +++ b/ObjectsComparer/ObjectsComparer/ListComparisonSettings.cs @@ -9,8 +9,12 @@ namespace ObjectsComparer /// public class ListComparisonSettings { + ListComparisonSettings() { } + internal Action ConfigureOptionsAction { get; private set; } = null; + internal static ListComparisonSettings Default() => new ListComparisonSettings(); + /// /// Configures list comparison behavior. /// From 0cc079e546e5f651d65d9bd25b0ac5a08ea5b63e Mon Sep 17 00:00:00 2001 From: "ASD\\nemec" Date: Wed, 27 Oct 2021 10:58:57 +0200 Subject: [PATCH 041/181] Add KeylessElementComparisonContext property to ElementKeyNotFoundException class. --- .../CompareElementsByKeyOptions.cs | 4 ++-- .../CustomComparers/EnumerablesComparer.cs | 16 ++++++++-------- .../Exceptions/ElementKeyNotFoundException.cs | 8 +++++++- 3 files changed, 17 insertions(+), 11 deletions(-) diff --git a/ObjectsComparer/ObjectsComparer/CompareElementsByKeyOptions.cs b/ObjectsComparer/ObjectsComparer/CompareElementsByKeyOptions.cs index ef32213..1e270bb 100644 --- a/ObjectsComparer/ObjectsComparer/CompareElementsByKeyOptions.cs +++ b/ObjectsComparer/ObjectsComparer/CompareElementsByKeyOptions.cs @@ -162,9 +162,9 @@ internal string GetFormattedElementKey(int elementIndex, object elementKey) } /// - /// Returns formatted element identifier that referes to null. See . + /// Returns element identifier for element that referes to null. See . /// - internal string GetFormattedNullElementIdentifier(int elementIndex) + internal string GetNullElementIdentifier(int elementIndex) { var elementIdentifier = NullElementIdentifierFormatter?.Invoke(elementIndex); diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs index 0310968..d601de9 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs @@ -109,9 +109,9 @@ private IEnumerable CalculateDifferencesByKey(object[] array1, objec continue; } - var formattedNullElementIdentifier = keyOptions.GetFormattedNullElementIdentifier(element1Index); + var nullElementIdentifier = keyOptions.GetNullElementIdentifier(element1Index); - yield return AddDifferenceToComparisonContext(new Difference($"[{formattedNullElementIdentifier}]", string.Empty, string.Empty, DifferenceTypes.MissedElementInSecondObject), elementComparisonContext); + yield return AddDifferenceToComparisonContext(new Difference($"[{nullElementIdentifier}]", string.Empty, string.Empty, DifferenceTypes.MissedElementInSecondObject), elementComparisonContext); continue; } @@ -121,7 +121,7 @@ private IEnumerable CalculateDifferencesByKey(object[] array1, objec { if (keyOptions.ThrowKeyNotFound) { - throw new ElementKeyNotFoundException(element1); + throw new ElementKeyNotFoundException(element1, elementComparisonContext); } continue; @@ -149,6 +149,7 @@ private IEnumerable CalculateDifferencesByKey(object[] array1, objec for (int element2Index = 0; element2Index < array2.Length; element2Index++) { var element2 = array2[element2Index]; + var elementComparisonContext = ComparisonContext.Create(ancestor: listComparisonContext); if (element2 == null) { @@ -157,10 +158,9 @@ private IEnumerable CalculateDifferencesByKey(object[] array1, objec continue; } - var elementComparisonContext = ComparisonContext.Create(ancestor: listComparisonContext); - var formattedNullElementIdentifier = keyOptions.GetFormattedNullElementIdentifier(element2Index); + var nullElementIdentifier = keyOptions.GetNullElementIdentifier(element2Index); - yield return AddDifferenceToComparisonContext(new Difference($"[{formattedNullElementIdentifier}]", string.Empty, string.Empty, DifferenceTypes.MissedElementInFirstObject), elementComparisonContext); + yield return AddDifferenceToComparisonContext(new Difference($"[{nullElementIdentifier}]", string.Empty, string.Empty, DifferenceTypes.MissedElementInFirstObject), elementComparisonContext); continue; } @@ -170,7 +170,7 @@ private IEnumerable CalculateDifferencesByKey(object[] array1, objec { if (keyOptions.ThrowKeyNotFound) { - throw new ElementKeyNotFoundException(element2); + throw new ElementKeyNotFoundException(element2, elementComparisonContext); } continue; @@ -178,7 +178,7 @@ private IEnumerable CalculateDifferencesByKey(object[] array1, objec if (array1.Any(elm1 => object.Equals(element2Key, keyOptions.KeyProvider(elm1))) == false) { - var elementComparisonContext = ComparisonContext.Create(ancestor: listComparisonContext); + //var elementComparisonContext = ComparisonContext.Create(ancestor: listComparisonContext); var formattedElement2Key = keyOptions.GetFormattedElementKey(element2Index, element2Key); var valueComparer2 = OverridesCollection.GetComparer(element2.GetType()) ?? DefaultValueComparer; yield return AddDifferenceToComparisonContext(new Difference($"[{formattedElement2Key}]", string.Empty, valueComparer2.ToString(element2), DifferenceTypes.MissedElementInFirstObject), elementComparisonContext); diff --git a/ObjectsComparer/ObjectsComparer/Exceptions/ElementKeyNotFoundException.cs b/ObjectsComparer/ObjectsComparer/Exceptions/ElementKeyNotFoundException.cs index 5ddb00e..9b0681e 100644 --- a/ObjectsComparer/ObjectsComparer/Exceptions/ElementKeyNotFoundException.cs +++ b/ObjectsComparer/ObjectsComparer/Exceptions/ElementKeyNotFoundException.cs @@ -16,14 +16,20 @@ public class ElementKeyNotFoundException : Exception ///
/// An element that is missing a key. /// - internal ElementKeyNotFoundException(object keylessElement, string message = ElementKeyNotFoundExceptionMsg) : base(message) + internal ElementKeyNotFoundException(object keylessElement, ComparisonContext keylessElementComparisonContext, string message = ElementKeyNotFoundExceptionMsg) : base(message) { KeylessElement = keylessElement ?? throw new ArgumentNullException(nameof(keylessElement)); + KeylessElementComparisonContext = keylessElementComparisonContext ?? throw new ArgumentNullException(nameof(keylessElementComparisonContext)); } /// /// An element that is missing a key. /// public object KeylessElement { get; } + + /// + /// The current in which the exception occurred. + /// + public ComparisonContext KeylessElementComparisonContext { get; } } } From fcc8b2645a7b75af9c5677ccef00f7fa5a3ef878 Mon Sep 17 00:00:00 2001 From: "ASD\\nemec" Date: Wed, 27 Oct 2021 13:21:56 +0200 Subject: [PATCH 042/181] Edit comments. --- .../Comparer_NonGenericEnumerableTests.cs | 7 +++---- .../ObjectsComparer/CompareElementsByKeyOptions.cs | 9 +++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs b/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs index 9686b8a..b9b2efb 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs @@ -213,11 +213,10 @@ public void RightComparisonContextGraph() { options.CompareUnequalLists = true; options.CompareElementsByKey(keyOptions => - { + { keyOptions.FormatElementKey((index, key) => $"Key: {key}"); - //keyOptions.FormatNullElementidentifier = index => $"NULLREFAT-{index}"; - //keyOptions.NullElementIdentifier = "Null-ref"; - //keyOptions.FormatNullElementIdentifier(index => $"NULLREFAT-{index}"); + keyOptions.UseKey(""); + }); }); diff --git a/ObjectsComparer/ObjectsComparer/CompareElementsByKeyOptions.cs b/ObjectsComparer/ObjectsComparer/CompareElementsByKeyOptions.cs index 1e270bb..164a316 100644 --- a/ObjectsComparer/ObjectsComparer/CompareElementsByKeyOptions.cs +++ b/ObjectsComparer/ObjectsComparer/CompareElementsByKeyOptions.cs @@ -62,7 +62,7 @@ void Initialize() } /// - /// Compares list elements by key. It will try to find a property specified by parameter. + /// Key identification. It attempts to find the key using the property specified by the parameter. /// public void UseKey(string key, bool caseSensitive = false) { @@ -75,7 +75,7 @@ public void UseKey(string key, bool caseSensitive = false) } /// - /// Compares list elements by key. It will try to find one of the public properties specified by parameter, in that order. + /// Key identification. It attempts to find the key using one of the public properties specified by the parameter, in the specified order. /// public void UseKey(string[] keys, bool caseSensitive = false) { @@ -101,7 +101,7 @@ public void UseKey(string[] keys, bool caseSensitive = false) } /// - /// Compares list elements by key using . + /// Key identification. It attempts to find the key using the parameter. /// /// First parameter: The element whose key is required. Return value: The element's key. public void UseKey(Func keyProvider) @@ -115,7 +115,7 @@ public void UseKey(Func keyProvider) } /// - /// It will try to find one of the public properties specified by , then it returns its value. + /// It will try to find one of the public properties specified by the parameter, then it returns its value. /// /// Returns the value of the property that corresponds to the specified key. If no property matches the specified key, it returns the itself. static object GetKeyValue(object instance, bool caseSensitive, params string[] keys) @@ -164,6 +164,7 @@ internal string GetFormattedElementKey(int elementIndex, object elementKey) /// /// Returns element identifier for element that referes to null. See . /// + /// Element index. internal string GetNullElementIdentifier(int elementIndex) { var elementIdentifier = NullElementIdentifierFormatter?.Invoke(elementIndex); From 00563572ba5b4a43fd000051a8fdaea4638fb499 Mon Sep 17 00:00:00 2001 From: Daniel Nemec Date: Thu, 28 Oct 2021 10:13:45 +0200 Subject: [PATCH 043/181] Edit template: NullAtIdx={0} --- .../Comparer_NonGenericEnumerableTests.cs | 9 ++------- .../ObjectsComparer/CompareElementsByKeyOptions.cs | 2 +- .../ObjectsComparer/ListComparisonSettings.cs | 1 + 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs b/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs index b9b2efb..a4cfdaf 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs @@ -209,15 +209,10 @@ public void RightComparisonContextGraph() var settings = new ComparisonSettings(); - settings.List.Configure((ctx, options) => + settings.List.Configure(options => { options.CompareUnequalLists = true; - options.CompareElementsByKey(keyOptions => - { - keyOptions.FormatElementKey((index, key) => $"Key: {key}"); - keyOptions.UseKey(""); - - }); + options.CompareElementsByKey(); }); var comparer = new Comparer(settings); diff --git a/ObjectsComparer/ObjectsComparer/CompareElementsByKeyOptions.cs b/ObjectsComparer/ObjectsComparer/CompareElementsByKeyOptions.cs index 164a316..04a4655 100644 --- a/ObjectsComparer/ObjectsComparer/CompareElementsByKeyOptions.cs +++ b/ObjectsComparer/ObjectsComparer/CompareElementsByKeyOptions.cs @@ -15,7 +15,7 @@ public class CompareElementsByKeyOptions /// /// Default element identifier template for element that refers to null value. See for more info. /// - public const string DefaultNullElementIdentifierTemplate = "NullAtIdx:{0}"; + public const string DefaultNullElementIdentifierTemplate = "NullAtIdx={0}"; ///
/// Max. length of the formatted key of the element. See . diff --git a/ObjectsComparer/ObjectsComparer/ListComparisonSettings.cs b/ObjectsComparer/ObjectsComparer/ListComparisonSettings.cs index 39633cf..6b02053 100644 --- a/ObjectsComparer/ObjectsComparer/ListComparisonSettings.cs +++ b/ObjectsComparer/ObjectsComparer/ListComparisonSettings.cs @@ -31,6 +31,7 @@ public void Configure(Action config /// /// Configures list comparison behavior. /// + /// See . public void Configure(Action configureOptions) { if (configureOptions is null) From 21a7c64811b82b8825bed8e78a5e4ecc83dd22ca Mon Sep 17 00:00:00 2001 From: Daniel Nemec Date: Sat, 30 Oct 2021 21:36:33 +0200 Subject: [PATCH 044/181] Add EnumerablesComparerBase class. Move CalculateDifferencesByIndex, CalculateDifferencesByKey into it. --- .../Comparer_NonGenericEnumerableTests.cs | 149 +------------ .../ComparisonSettingsTests.cs | 2 +- .../CustomComparers/EnumerablesComparer.cs | 38 ++-- .../EnumerablesComparerBase.cs | 203 ++++++++++++++++++ .../CustomComparers/EnumerablesComparer~1.cs | 49 +++-- 5 files changed, 247 insertions(+), 194 deletions(-) create mode 100644 ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparerBase.cs diff --git a/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs b/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs index a4cfdaf..32fb063 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs @@ -59,107 +59,6 @@ public void InequalityProperty() Assert.AreEqual("Str3", differences.First().Value2); } - [Test] - public void InequalityCount_InequalityProperty_CompareByKey() - { - var a1 = new A - { - NonGenericEnumerable = new ArrayList - { - new B { Property1 = "Str2" }, - new B { Property1 = "Str1" } , - null - } - }; - - var a2 = new A - { - NonGenericEnumerable = new ArrayList - { - new B { Property1 = "Str1" } - } - }; - - //ComparisonContext.BelongsTo(): Returns true if current context's Member belongs to the member or if it is the member itself. - //var r = PropertyHelper.GetMemberInfo(() => new B().Property1); - - var settings = new ComparisonSettings(); - - settings.List.Configure((ctx, options) => - { - options.CompareUnequalLists = true; - options.CompareElementsByKey(keyOptions => keyOptions.UseKey(nameof(B.Property1))); - }); - - var comparer = new Comparer(settings); - var rootContext = ComparisonContext.Create(); - var differences = comparer.CalculateDifferences(a1, a2, rootContext).ToList(); - - CollectionAssert.IsNotEmpty(differences); - Assert.AreEqual("NonGenericEnumerable", differences.First().MemberPath); - Assert.AreEqual(DifferenceTypes.NumberOfElementsMismatch, differences.First().DifferenceType); - Assert.AreEqual("3", differences.First().Value1); - Assert.AreEqual("1", differences.First().Value2); - Assert.AreEqual(DifferenceTypes.MissedElementInSecondObject, differences[1].DifferenceType); - Assert.AreEqual("NonGenericEnumerable[Str2]", differences[1].MemberPath); - Assert.AreEqual(false, string.IsNullOrWhiteSpace(differences[1].Value1)); - Assert.AreEqual(true, string.IsNullOrWhiteSpace(differences[1].Value2)); - Assert.AreEqual(DifferenceTypes.MissedElementInSecondObject, differences[2].DifferenceType); - Assert.AreEqual("NonGenericEnumerable[NULL]", differences[2].MemberPath); - Assert.AreEqual(true, differences[2].Value2 == string.Empty); - } - - [Test] - public void InequalityCount_InequalityProperty_CompareByKey2() - { - var a1 = new A - { - NonGenericEnumerable = new ArrayList - { - new B { Property1 = "Str1" } - } - }; - - var a2 = new A - { - NonGenericEnumerable = new ArrayList - { - new B { Property1 = "Str2" }, - new B { Property1 = "Str1" } , - null - } - }; - - //ComparisonContext.BelongsTo(): Returns true if current context's Member belongs to the member or if it is the member itself. - //var r = PropertyHelper.GetMemberInfo(() => new B().Property1); - - var settings = new ComparisonSettings(); - - settings.List.Configure((ctx, options) => - { - options.CompareUnequalLists = true; - options.CompareElementsByKey(keyOptions => keyOptions.UseKey(nameof(B.Property1))); - }); - - var comparer = new Comparer(settings); - var rootContext = ComparisonContext.Create(); - var differences = comparer.CalculateDifferences(a1, a2, rootContext).ToList(); - - CollectionAssert.IsNotEmpty(differences); - Assert.AreEqual("NonGenericEnumerable", differences.First().MemberPath); - Assert.AreEqual(DifferenceTypes.NumberOfElementsMismatch, differences.First().DifferenceType); - Assert.AreEqual("1", differences.First().Value1); - Assert.AreEqual("3", differences.First().Value2); - Assert.AreEqual(DifferenceTypes.MissedElementInFirstObject, differences[1].DifferenceType); - Assert.AreEqual("NonGenericEnumerable[Str2]", differences[1].MemberPath); - Assert.AreEqual(true, string.IsNullOrWhiteSpace(differences[1].Value1)); - Assert.AreEqual(false, string.IsNullOrWhiteSpace(differences[1].Value2)); - Assert.AreEqual(DifferenceTypes.MissedElementInFirstObject, differences[2].DifferenceType); - Assert.AreEqual("NonGenericEnumerable[NULL]", differences[2].MemberPath); - Assert.AreEqual(true, differences[2].Value2 == string.Empty); - Assert.AreEqual(true, differences[2].Value2 == string.Empty); - } - [Test] public void RightComparisonContextGraph() { @@ -212,7 +111,7 @@ public void RightComparisonContextGraph() settings.List.Configure(options => { options.CompareUnequalLists = true; - options.CompareElementsByKey(); + //options.CompareElementsByKey(); }); var comparer = new Comparer(settings); @@ -224,52 +123,6 @@ public void RightComparisonContextGraph() var scontextAfterShrink = rootContext.ToJson(); } - [Test] - public void InequalityCount_InequalityProperty_CompareByIndex() - { - var a1 = new A - { - NonGenericEnumerable = new ArrayList - { - new B { Property1 = "Str2" }, - new B { Property1 = "Str1" } , - null - } - }; - - var a2 = new A - { - NonGenericEnumerable = new ArrayList - { - new B { Property1 = "Str1" } - } - }; - - var settings = new ComparisonSettings(); - - settings.List.Configure((ctx, options) => - { - options.CompareUnequalLists = true; - }); - - var comparer = new Comparer(settings); - var rootContext = ComparisonContext.Create(); - var differences = comparer.CalculateDifferences(a1, a2, rootContext).ToList(); - - CollectionAssert.IsNotEmpty(differences); - Assert.AreEqual("NonGenericEnumerable", differences.First().MemberPath); - Assert.AreEqual(DifferenceTypes.NumberOfElementsMismatch, differences.First().DifferenceType); - Assert.AreEqual("3", differences.First().Value1); - Assert.AreEqual("1", differences.First().Value2); - Assert.AreEqual(DifferenceTypes.ValueMismatch, differences[1].DifferenceType); - Assert.AreEqual("NonGenericEnumerable[0].Property1", differences[1].MemberPath); - Assert.AreEqual("Str2", differences[1].Value1); - Assert.AreEqual("Str1", differences[1].Value2); - Assert.AreEqual(DifferenceTypes.MissedElementInSecondObject, differences[2].DifferenceType); - Assert.AreEqual(true, differences[2].Value1 != string.Empty); - Assert.AreEqual(true, differences[2].Value2 == string.Empty); - } - [Test] public void NullElementsEquality() { diff --git a/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs b/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs index d5ecc0e..e52fcf4 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs @@ -81,7 +81,7 @@ public void CompareListElementsByKeyIsCorrectlySet() Assert.AreEqual(true, listConfigurationOptions.CompareUnequalLists); Assert.AreEqual(true, listConfigurationOptions.ElementSearchMode == ListElementSearchMode.Key); - Assert.AreEqual(true, compareElementsByKeyOptions.ThrowKeyNotFound); + Assert.AreEqual(false, compareElementsByKeyOptions.ThrowKeyNotFound); } /// diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs index d601de9..41951b2 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs @@ -9,10 +9,9 @@ namespace ObjectsComparer { - internal class EnumerablesComparer : AbstractComparer, IComparerWithCondition, IContextableComparer + internal class EnumerablesComparer : EnumerablesComparerBase, IComparerWithCondition, IContextableComparer { - public EnumerablesComparer(ComparisonSettings settings, BaseComparer parentComparer, IComparersFactory factory) - : base(settings, parentComparer, factory) + public EnumerablesComparer(ComparisonSettings settings, BaseComparer parentComparer, IComparersFactory factory) : base(settings, parentComparer, factory) { } @@ -21,17 +20,17 @@ public override IEnumerable CalculateDifferences(Type type, object o return CalculateDifferences(type, obj1, obj2, ComparisonContext.CreateRoot()); } - public IEnumerable CalculateDifferences(Type type, object obj1, object obj2, ComparisonContext comparisonContext) + public IEnumerable CalculateDifferences(Type type, object obj1, object obj2, ComparisonContext listComparisonContext) { - if (comparisonContext is null) + if (listComparisonContext is null) { - throw new ArgumentNullException(nameof(comparisonContext)); + throw new ArgumentNullException(nameof(listComparisonContext)); } if (!Settings.EmptyAndNullEnumerablesEqual && (obj1 == null || obj2 == null) && obj1 != obj2) { - yield return AddDifferenceToComparisonContext(new Difference("[]", obj1?.ToString() ?? string.Empty, obj2?.ToString() ?? string.Empty), comparisonContext); + yield return AddDifferenceToComparisonContext(new Difference("[]", obj1?.ToString() ?? string.Empty, obj2?.ToString() ?? string.Empty), listComparisonContext); yield break; } @@ -57,11 +56,11 @@ public IEnumerable CalculateDifferences(Type type, object obj1, obje var array2 = ((IEnumerable)obj2).Cast().ToArray(); var listConfigurationOptions = ListConfigurationOptions.Default(); - Settings.List.ConfigureOptionsAction?.Invoke(comparisonContext, listConfigurationOptions); + Settings.List.ConfigureOptionsAction?.Invoke(listComparisonContext, listConfigurationOptions); if (array1.Length != array2.Length) { - yield return AddDifferenceToComparisonContext(new Difference("", array1.Length.ToString(), array2.Length.ToString(), DifferenceTypes.NumberOfElementsMismatch), comparisonContext); + yield return AddDifferenceToComparisonContext(new Difference("", array1.Length.ToString(), array2.Length.ToString(), DifferenceTypes.NumberOfElementsMismatch), listComparisonContext); if (listConfigurationOptions.CompareUnequalLists == false) { @@ -69,28 +68,15 @@ public IEnumerable CalculateDifferences(Type type, object obj1, obje } } - IEnumerable failrues; - - if (listConfigurationOptions.ElementSearchMode == ListElementSearchMode.Key) - { - failrues = CalculateDifferencesByKey(array1, array2, comparisonContext, listConfigurationOptions); - } - else if (listConfigurationOptions.ElementSearchMode == ListElementSearchMode.Index) - { - failrues = CalculateDifferencesByIndex(array1, array2, comparisonContext); - } - else - { - throw new NotImplementedException($"{listConfigurationOptions.ElementSearchMode} implemented yet."); - } - + IEnumerable failrues = CalculateDifferences(array1, array2, listComparisonContext, listConfigurationOptions); + foreach (var failrue in failrues) { yield return failrue; } } - private IEnumerable CalculateDifferencesByKey(object[] array1, object[] array2, ComparisonContext listComparisonContext, ListConfigurationOptions listConfigurationOptions) + private IEnumerable _CalculateDifferencesByKey(object[] array1, object[] array2, ComparisonContext listComparisonContext, ListConfigurationOptions listConfigurationOptions) { Debug.WriteLine(nameof(CalculateDifferencesByKey)); @@ -186,7 +172,7 @@ private IEnumerable CalculateDifferencesByKey(object[] array1, objec } } - private IEnumerable CalculateDifferencesByIndex(object[] array1, object[] array2, ComparisonContext listComparisonContext) + private IEnumerable _CalculateDifferencesByIndex(object[] array1, object[] array2, ComparisonContext listComparisonContext) { Debug.WriteLine(nameof(CalculateDifferencesByIndex)); diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparerBase.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparerBase.cs new file mode 100644 index 0000000..69faf01 --- /dev/null +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparerBase.cs @@ -0,0 +1,203 @@ +using ObjectsComparer.Exceptions; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; + +namespace ObjectsComparer +{ + internal abstract class EnumerablesComparerBase : AbstractComparer + { + public EnumerablesComparerBase(ComparisonSettings settings, BaseComparer parentComparer, IComparersFactory factory) : base(settings, parentComparer, factory) + { + } + + /// + /// Selects calculation operation based on the current value of the property. + /// + protected virtual IEnumerable CalculateDifferences(IList list1, IList list2, ComparisonContext listComparisonContext, ListConfigurationOptions listConfigurationOptions) + { + if (listConfigurationOptions.ElementSearchMode == ListElementSearchMode.Key) + { + return CalculateDifferencesByKey(list1, list2, listComparisonContext, listConfigurationOptions); + } + else if (listConfigurationOptions.ElementSearchMode == ListElementSearchMode.Index) + { + return CalculateDifferencesByIndex(list1, list2, listComparisonContext); + } + else + { + throw new NotImplementedException($"{listConfigurationOptions.ElementSearchMode} not implemented yet."); + } + } + + /// + /// Calculates differences using comparison mode. + /// + protected virtual IEnumerable CalculateDifferencesByKey(IList array1, IList array2, ComparisonContext listComparisonContext, ListConfigurationOptions listConfigurationOptions) + { + Debug.WriteLine(nameof(CalculateDifferencesByKey)); + + var keyOptions = CompareElementsByKeyOptions.Default(); + listConfigurationOptions.KeyOptionsAction?.Invoke(keyOptions); + + for (int element1Index = 0; element1Index < array1.Count(); element1Index++) + { + var element1 = array1[element1Index]; + var elementComparisonContext = ComparisonContext.Create(ancestor: listComparisonContext); + + if (element1 == null) + { + if (array2.Any(elm2 => elm2 == null)) + { + continue; + } + + var nullElementIdentifier = keyOptions.GetNullElementIdentifier(element1Index); + + yield return AddDifferenceToComparisonContext(new Difference($"[{nullElementIdentifier}]", string.Empty, string.Empty, DifferenceTypes.MissedElementInSecondObject), elementComparisonContext); + continue; + } + + var element1Key = keyOptions.KeyProvider(element1); + + if (element1Key == null) + { + if (keyOptions.ThrowKeyNotFound) + { + throw new ElementKeyNotFoundException(element1, elementComparisonContext); + } + + continue; + } + + var formattedElement1Key = keyOptions.GetFormattedElementKey(element1Index, element1Key); + + if (array2.Any(elm2 => object.Equals(element1Key, keyOptions.KeyProvider(elm2)))) + { + var element2 = array2.First(elm2 => object.Equals(element1Key, keyOptions.KeyProvider(elm2))); + var comparer = Factory.GetObjectsComparer(element1.GetType(), Settings, this); + + foreach (var failure in comparer.CalculateDifferences(element1.GetType(), element1, element2, elementComparisonContext)) + { + yield return failure.InsertPath($"[{formattedElement1Key}]"); + } + } + else + { + var valueComparer1 = OverridesCollection.GetComparer(element1.GetType()) ?? DefaultValueComparer; + yield return AddDifferenceToComparisonContext(new Difference($"[{formattedElement1Key}]", valueComparer1.ToString(element1), string.Empty, DifferenceTypes.MissedElementInSecondObject), elementComparisonContext); + } + } + + for (int element2Index = 0; element2Index < array2.Count(); element2Index++) + { + var element2 = array2[element2Index]; + var elementComparisonContext = ComparisonContext.Create(ancestor: listComparisonContext); + + if (element2 == null) + { + if (array1.Any(elm1 => elm1 == null)) + { + continue; + } + + var nullElementIdentifier = keyOptions.GetNullElementIdentifier(element2Index); + + yield return AddDifferenceToComparisonContext(new Difference($"[{nullElementIdentifier}]", string.Empty, string.Empty, DifferenceTypes.MissedElementInFirstObject), elementComparisonContext); + continue; + } + + var element2Key = keyOptions.KeyProvider(element2); + + if (element2Key == null) + { + if (keyOptions.ThrowKeyNotFound) + { + throw new ElementKeyNotFoundException(element2, elementComparisonContext); + } + + continue; + } + + if (array1.Any(elm1 => object.Equals(element2Key, keyOptions.KeyProvider(elm1))) == false) + { + //var elementComparisonContext = ComparisonContext.Create(ancestor: listComparisonContext); + var formattedElement2Key = keyOptions.GetFormattedElementKey(element2Index, element2Key); + var valueComparer2 = OverridesCollection.GetComparer(element2.GetType()) ?? DefaultValueComparer; + yield return AddDifferenceToComparisonContext(new Difference($"[{formattedElement2Key}]", string.Empty, valueComparer2.ToString(element2), DifferenceTypes.MissedElementInFirstObject), elementComparisonContext); + } + } + } + + /// + /// Calculates differences using comparison mode. + /// + protected virtual IEnumerable CalculateDifferencesByIndex(IList array1, IList array2, ComparisonContext listComparisonContext) + { + Debug.WriteLine(nameof(CalculateDifferencesByIndex)); + + int array1Count = array1.Count(); + int array2Count = array2.Count(); + int smallerCount = array1Count <= array2Count ? array1Count : array2Count; + + //ToDo Extract type + for (var i = 0; i < smallerCount; i++) + { + var elementComparisonContext = ComparisonContext.Create(ancestor: listComparisonContext); + + if (array1[i] == null && array2[i] == null) + { + continue; + } + + var valueComparer1 = array1[i] != null ? OverridesCollection.GetComparer(array1[i].GetType()) ?? DefaultValueComparer : DefaultValueComparer; + var valueComparer2 = array2[i] != null ? OverridesCollection.GetComparer(array2[i].GetType()) ?? DefaultValueComparer : DefaultValueComparer; + + if (array1[i] == null) + { + yield return AddDifferenceToComparisonContext(new Difference($"[{i}]", string.Empty, valueComparer2.ToString(array2[i])), elementComparisonContext); + continue; + } + + if (array2[i] == null) + { + yield return AddDifferenceToComparisonContext(new Difference($"[{i}]", valueComparer1.ToString(array1[i]), string.Empty), elementComparisonContext); + continue; + } + + if (array1[i].GetType() != array2[i].GetType()) + { + yield return AddDifferenceToComparisonContext(new Difference($"[{i}]", valueComparer1.ToString(array1[i]), valueComparer2.ToString(array2[i]), DifferenceTypes.TypeMismatch), elementComparisonContext); + continue; + } + + var comparer = Factory.GetObjectsComparer(array1[i].GetType(), Settings, this); + + foreach (var failure in comparer.CalculateDifferences(array1[i].GetType(), array1[i], array2[i], elementComparisonContext)) + { + yield return failure.InsertPath($"[{i}]"); + } + } + + //Add a "missed element" difference for each element that is in array1 and that is not in array2 or vice versa. + if (array1Count != array2Count) + { + var largerArray = array1Count > array2Count ? array1 : array2; + + for (int i = smallerCount; i < largerArray.Count(); i++) + { + var valueComparer = largerArray[i] != null ? OverridesCollection.GetComparer(largerArray[i].GetType()) ?? DefaultValueComparer : DefaultValueComparer; + + var difference = new Difference( + memberPath: $"[{i}]", + value1: array1Count > array2Count ? valueComparer.ToString(largerArray[i]) : string.Empty, + value2: array2Count > array1Count ? valueComparer.ToString(largerArray[i]) : string.Empty, + differenceType: array1Count > array2Count ? DifferenceTypes.MissedElementInSecondObject : DifferenceTypes.MissedElementInFirstObject); + + yield return AddDifferenceToComparisonContext(difference, ComparisonContext.Create(ancestor: listComparisonContext)); + } + } + } + } +} diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer~1.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer~1.cs index 3271f07..b2c0993 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer~1.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer~1.cs @@ -6,12 +6,11 @@ namespace ObjectsComparer { - internal class EnumerablesComparer : AbstractComparer, IContextableComparer, IContextableComparer + internal class EnumerablesComparer : EnumerablesComparerBase, IContextableComparer, IContextableComparer { private readonly IComparer _comparer; - public EnumerablesComparer(ComparisonSettings settings, BaseComparer parentComparer, IComparersFactory factory) - :base(settings, parentComparer, factory) + public EnumerablesComparer(ComparisonSettings settings, BaseComparer parentComparer, IComparersFactory factory) : base(settings, parentComparer, factory) { _comparer = Factory.GetObjectsComparer(Settings, this); } @@ -21,11 +20,11 @@ public override IEnumerable CalculateDifferences(Type type, object o return CalculateDifferences(type, obj1, obj2, ComparisonContext.CreateRoot()); } - public IEnumerable CalculateDifferences(Type type, object obj1, object obj2, ComparisonContext comparisonContext) + public IEnumerable CalculateDifferences(Type type, object obj1, object obj2, ComparisonContext listComparisonContext) { - if (comparisonContext is null) + if (listComparisonContext is null) { - throw new ArgumentNullException(nameof(comparisonContext)); + throw new ArgumentNullException(nameof(listComparisonContext)); } if (!type.InheritsFrom(typeof(IEnumerable<>))) @@ -55,32 +54,44 @@ public IEnumerable CalculateDifferences(Type type, object obj1, obje var list1 = ((IEnumerable)obj1).ToList(); var list2 = ((IEnumerable)obj2).ToList(); + var listConfigurationOptions = ListConfigurationOptions.Default(); + Settings.List.ConfigureOptionsAction?.Invoke(listComparisonContext, listConfigurationOptions); + if (list1.Count != list2.Count) { if (!type.GetTypeInfo().IsArray) { - yield return new Difference("", list1.Count.ToString(), list2.Count.ToString(), - DifferenceTypes.NumberOfElementsMismatch); + yield return AddDifferenceToComparisonContext(new Difference("", list1.Count().ToString(), list2.Count().ToString(), DifferenceTypes.NumberOfElementsMismatch), listComparisonContext); } - yield break; + if (listConfigurationOptions.CompareUnequalLists == false) + { + yield break; + } } - for (var i = 0; i < list2.Count; i++) - { - //List item has not got its MemberInfo, but has got its ancestor - list. - var context = ComparisonContext.Create(member: null, ancestor: comparisonContext); + //for (var i = 0; i < list2.Count; i++) + //{ + // //List item has not got its MemberInfo, but has got its ancestor - list. + // var context = ComparisonContext.Create(member: null, ancestor: comparisonContext); - foreach (var failure in _comparer.CalculateDifferences(list1[i], list2[i], context)) - { - yield return failure.InsertPath($"[{i}]"); - } + // foreach (var failure in _comparer.CalculateDifferences(list1[i], list2[i], context)) + // { + // yield return failure.InsertPath($"[{i}]"); + // } + //} + + IEnumerable failrues = CalculateDifferences(list1, list2, listComparisonContext, listConfigurationOptions); + + foreach (var failrue in failrues) + { + yield return failrue; } } - public IEnumerable CalculateDifferences(T obj1, T obj2, ComparisonContext comparisonContext) + public IEnumerable CalculateDifferences(T obj1, T obj2, ComparisonContext listComparisonContext) { - return CalculateDifferences(((object)obj1 ?? obj2).GetType(), obj1, obj2, comparisonContext); + return CalculateDifferences(((object)obj1 ?? obj2).GetType(), obj1, obj2, listComparisonContext); } } } From f85b35a57420e26a6e3a757a06d7222b084f24d1 Mon Sep 17 00:00:00 2001 From: Daniel Nemec Date: Sun, 31 Oct 2021 18:34:25 +0100 Subject: [PATCH 045/181] Add additional test methods into ComparerNonGenericEnumerableTests class. Add methods for testing comparison elemets by key and index. Add methods for testing null element support. --- .../Comparer_NonGenericEnumerableTests.cs | 226 +++++++++++++----- .../ObjectsComparer.Tests/TestClasses/B.cs | 2 + .../CompareElementsByKeyOptions.cs | 2 +- .../ObjectsComparer/ComparisonContext.cs | 24 ++ 4 files changed, 196 insertions(+), 58 deletions(-) diff --git a/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs b/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs index 32fb063..57e7c84 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs @@ -28,6 +28,20 @@ public void Equality() Assert.IsTrue(isEqual); } + [Test] + public void Equality_CompareByKey() + { + var a1 = new A { NonGenericEnumerable = new ArrayList { new B { Property1 = "Str2" }, new B { Property1 = "Str1" } } }; + var a2 = new A { NonGenericEnumerable = new ArrayList { new B { Property1 = "Str1" }, new B { Property1 = "Str2" } } }; + var settings = new ComparisonSettings(); + settings.List.Configure(listOptions => listOptions.CompareElementsByKey(keyOptions => keyOptions.UseKey("Property1"))); + var comparer = new Comparer(settings); + + var isEqual = comparer.Compare(a1, a2); + + Assert.IsTrue(isEqual); + } + [Test] public void InequalityCount() { @@ -44,6 +58,91 @@ public void InequalityCount() Assert.AreEqual("1", differences.First().Value2); } + [Test] + public void InequalityCount_CompareUnequalLists() + { + var a1 = new A { NonGenericEnumerable = new ArrayList { new B { Property1 = "Str1" }, new B { Property1 = "Str2" } } }; + var a2 = new A { NonGenericEnumerable = new ArrayList { new B { Property1 = "Str1" } } }; + var settings = new ComparisonSettings(); + settings.List.Configure(listOptions => listOptions.CompareUnequalLists = true); + var comparer = new Comparer(settings); + + var differences = comparer.CalculateDifferences(a1, a2).ToList(); + + CollectionAssert.IsNotEmpty(differences); + Assert.AreEqual("NonGenericEnumerable", differences.First().MemberPath); + Assert.AreEqual(DifferenceTypes.NumberOfElementsMismatch, differences.First().DifferenceType); + Assert.AreEqual("2", differences.First().Value1); + Assert.AreEqual("1", differences.First().Value2); + + var diff2 = differences[1]; + Assert.AreEqual(DifferenceTypes.MissedElementInSecondObject, diff2.DifferenceType); + Assert.AreEqual("NonGenericEnumerable[1]", diff2.MemberPath); + Assert.AreNotEqual(string.Empty, diff2.Value1); + Assert.AreEqual(string.Empty, diff2.Value2); + } + + [Test] + public void InequalityCount_CompareUnequalLists_CompareByKey() + { + var a1 = new A { NonGenericEnumerable = new ArrayList { new B { Property1 = "Str1" }, new B { Property1 = "Str2" } } }; + var a2 = new A { NonGenericEnumerable = new ArrayList { new B { Property1 = "Str1" } } }; + var settings = new ComparisonSettings(); + settings.List.Configure(listOptions => + { + listOptions.CompareUnequalLists = true; + listOptions.CompareElementsByKey(keyOptions => + { + keyOptions.UseKey("Property1"); + keyOptions.FormatElementKey((elementIndex, elementKey) => $"Property1={elementKey}"); + }); + }); + var comparer = new Comparer(settings); + + var differences = comparer.CalculateDifferences(a1, a2).ToList(); + + CollectionAssert.IsNotEmpty(differences); + Assert.AreEqual("NonGenericEnumerable", differences.First().MemberPath); + Assert.AreEqual(DifferenceTypes.NumberOfElementsMismatch, differences.First().DifferenceType); + Assert.AreEqual("2", differences.First().Value1); + Assert.AreEqual("1", differences.First().Value2); + + var diff2 = differences[1]; + Assert.AreEqual(DifferenceTypes.MissedElementInSecondObject, diff2.DifferenceType); + Assert.AreEqual("NonGenericEnumerable[Property1=Str2]", diff2.MemberPath); + Assert.AreNotEqual(string.Empty, diff2.Value1); + Assert.AreEqual(string.Empty, diff2.Value2); + } + + [Test] + public void InequalityCount_CompareUnequalLists_CompareByKey_DontFormatKey() + { + var a1 = new A { NonGenericEnumerable = new ArrayList { new B { Property1 = "Str1" }, new B { Property1 = "Str2" } } }; + var a2 = new A { NonGenericEnumerable = new ArrayList { new B { Property1 = "Str1" } } }; + var settings = new ComparisonSettings(); + settings.List.Configure(listOptions => + { + listOptions.CompareUnequalLists = true; + listOptions.CompareElementsByKey(keyOptions => keyOptions.UseKey("Property1")); + }); + + var comparer = new Comparer(settings); + + var differences = comparer.CalculateDifferences(a1, a2).ToList(); + + CollectionAssert.IsNotEmpty(differences); + Assert.AreEqual("NonGenericEnumerable", differences.First().MemberPath); + Assert.AreEqual(DifferenceTypes.NumberOfElementsMismatch, differences.First().DifferenceType); + Assert.AreEqual("2", differences.First().Value1); + Assert.AreEqual("1", differences.First().Value2); + + var diff2 = differences[1]; + Assert.AreEqual(DifferenceTypes.MissedElementInSecondObject, diff2.DifferenceType); + Assert.AreEqual("NonGenericEnumerable[Str2]", diff2.MemberPath); + Assert.AreNotEqual(string.Empty, diff2.Value1); + Assert.AreEqual(string.Empty, diff2.Value2); + } + [Test] public void InequalityProperty() { @@ -60,69 +159,30 @@ public void InequalityProperty() } [Test] - public void RightComparisonContextGraph() + public void InequalityProperty_CompareByKey() { - var person1 = new Person - { - FirstName = "FirstName1", - LastName = "LastName 1", - NonGenericLiveAddresses = new ArrayList - { - new Address - { - Id = 1, - City = "City 1", - State = "State 1" - }, - - new Address{} - }, - NonGenericStayAddresses = new ArrayList - { - new Address - { - Id = 2, - City = "City 3" - }, - }, - }; - - var person2 = new Person - { - FirstName = "FirstName 2", - LastName = "LastName 2", - NonGenericLiveAddresses = new ArrayList - { - null, - - new Address - { - Id = 1, - City = "City 2", - State = "State 2" - }, - - null - } - }; + var a1 = new A { NonGenericEnumerable = new ArrayList { new B { Property1 = "Str1", Id = 1 }, new B { Property1 = "Str2", Id = 2 } } }; + var a2 = new A { NonGenericEnumerable = new ArrayList { new B { Property1 = "Str3", Id = 2 }, new B { Property1 = "Str1", Id = 1 } } }; var settings = new ComparisonSettings(); + settings.List.Configure(listOptions => listOptions.CompareElementsByKey()); - settings.List.Configure(options => - { - options.CompareUnequalLists = true; - //options.CompareElementsByKey(); - }); + var comparer = new Comparer(settings); - var comparer = new Comparer(settings); - var rootContext = ComparisonContext.Create(); - var differences = comparer.CalculateDifferences(person1, person2, rootContext).ToList(); - var hasDiffs = rootContext.HasDifferences(false); - var scontextBeforeShrink = rootContext.ToJson(); - rootContext.Shrink(); - var scontextAfterShrink = rootContext.ToJson(); + var rootCtx = ComparisonContext.CreateRoot(); + var differences = comparer.CalculateDifferences(a1, a2, rootCtx).ToList(); + + CollectionAssert.IsNotEmpty(differences); + var diff = differences.First(); + Assert.AreEqual("NonGenericEnumerable[2].Property1", diff.MemberPath); + Assert.AreEqual("Str2", diff.Value1); + Assert.AreEqual("Str3", diff.Value2); + + var diffFromCtx = rootCtx.GetDifferences(recursive: true).FirstOrDefault(); + Assert.NotNull(diffFromCtx); + Assert.AreEqual(diff, diffFromCtx); } - + [Test] public void NullElementsEquality() { @@ -135,6 +195,58 @@ public void NullElementsEquality() Assert.IsTrue(isEqual); } + [Test] + public void NullElementsEquality_CompareUnequalLists() + { + //DaN + var a1 = new A { NonGenericEnumerable = new ArrayList { null } }; + var a2 = new A { NonGenericEnumerable = new ArrayList { null, null } }; + + var settings = new ComparisonSettings(); + settings.List.Configure(listOptions => listOptions.CompareUnequalLists = true); + + var comparer = new Comparer(settings); + var isEqual = comparer.Compare(a1, a2, out var diffs); + var differences = diffs.ToArray(); + Assert.IsTrue(differences.Count() == 2); + Assert.IsTrue(differences[0].DifferenceType == DifferenceTypes.NumberOfElementsMismatch); + Assert.IsTrue(differences[0].Value1 == "1"); + Assert.IsTrue(differences[0].Value2 == "2"); + Assert.IsTrue(differences[1].DifferenceType == DifferenceTypes.MissedElementInFirstObject); + Assert.IsTrue(differences[1].MemberPath == "NonGenericEnumerable[1]"); + Assert.IsTrue(differences[1].Value1 == string.Empty); + Assert.IsTrue(differences[1].Value2 == string.Empty); + Assert.IsFalse(isEqual); + } + + [Test] + public void NullElementsEquality_CompareUnequalLists_CompareByKey() + { + //DaN + var a1 = new A { NonGenericEnumerable = new ArrayList { null } }; + var a2 = new A { NonGenericEnumerable = new ArrayList { null, null } }; + + var settings = new ComparisonSettings(); + settings.List.Configure(listOptions => + { + listOptions.CompareUnequalLists = true; + listOptions.CompareElementsByKey(); //Because all elements are null, no key definition is required for this test method. + }); + + var comparer = new Comparer(settings); + var isEqual = comparer.Compare(a1, a2, out var diffs); + var differences = diffs.ToArray(); + Assert.IsTrue(differences.Count() == 2); + Assert.IsTrue(differences[0].DifferenceType == DifferenceTypes.NumberOfElementsMismatch); + Assert.IsTrue(differences[0].Value1 == "1"); + Assert.IsTrue(differences[0].Value2 == "2"); + Assert.IsTrue(differences[1].DifferenceType == DifferenceTypes.MissedElementInFirstObject); + Assert.IsTrue(differences[1].MemberPath == "NonGenericEnumerable[1]"); + Assert.IsTrue(differences[1].Value1 == string.Empty); + Assert.IsTrue(differences[1].Value2 == string.Empty); + Assert.IsFalse(isEqual); + } + [Test] public void NullAndNotNullElementsInequality() { diff --git a/ObjectsComparer/ObjectsComparer.Tests/TestClasses/B.cs b/ObjectsComparer/ObjectsComparer.Tests/TestClasses/B.cs index ed42975..c500bf3 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/TestClasses/B.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/TestClasses/B.cs @@ -3,5 +3,7 @@ public class B { public string Property1 { get; set; } + + public int? Id { get; set; } } } diff --git a/ObjectsComparer/ObjectsComparer/CompareElementsByKeyOptions.cs b/ObjectsComparer/ObjectsComparer/CompareElementsByKeyOptions.cs index 04a4655..98cf01a 100644 --- a/ObjectsComparer/ObjectsComparer/CompareElementsByKeyOptions.cs +++ b/ObjectsComparer/ObjectsComparer/CompareElementsByKeyOptions.cs @@ -181,7 +181,7 @@ internal string GetNullElementIdentifier(int elementIndex) /// To avoid possible confusion of the element key with the element index, the element key can be formatted with any text.
/// For example, element key with value = 1 can be formatted as "Id=1". /// The formatted element key is then used as part of the property, e.g. "Addresses[Id=1]".
- /// By default, the element key will not be formatted. + /// By default the element key is not formatted. /// /// First parameter: Element index. Second parameter: Element key. Return value: Formatted key. public void FormatElementKey(Func formatter) diff --git a/ObjectsComparer/ObjectsComparer/ComparisonContext.cs b/ObjectsComparer/ObjectsComparer/ComparisonContext.cs index a32e181..1c8fc0c 100644 --- a/ObjectsComparer/ObjectsComparer/ComparisonContext.cs +++ b/ObjectsComparer/ObjectsComparer/ComparisonContext.cs @@ -107,6 +107,30 @@ public bool HasDifferences(bool recursive) return false; } + /// + /// Returns differences directly or indirectly related to this context. + /// + /// If value is true, it also looks for in . + public IEnumerable GetDifferences(bool recursive) + { + foreach (var difference in _differences) + { + yield return difference; + } + + if (recursive) + { + foreach (var descendant in _descendants) + { + var differences = descendant.GetDifferences(true); + foreach (var difference in differences) + { + yield return difference; + } + } + } + } + /// /// Removes all which have no directly or indirectly in their . /// From fefa5adda7261ec60c59f60b52eecfa19f95fbdf Mon Sep 17 00:00:00 2001 From: "ASD\\nemec" Date: Mon, 1 Nov 2021 14:16:36 +0100 Subject: [PATCH 046/181] Add NullAndNotNullElementsInequality_CompareByKey test method. --- .../Comparer_NonGenericEnumerableTests.cs | 39 +++++++++++++++---- 1 file changed, 32 insertions(+), 7 deletions(-) diff --git a/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs b/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs index 57e7c84..3c9b457 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs @@ -198,7 +198,6 @@ public void NullElementsEquality() [Test] public void NullElementsEquality_CompareUnequalLists() { - //DaN var a1 = new A { NonGenericEnumerable = new ArrayList { null } }; var a2 = new A { NonGenericEnumerable = new ArrayList { null, null } }; @@ -222,7 +221,6 @@ public void NullElementsEquality_CompareUnequalLists() [Test] public void NullElementsEquality_CompareUnequalLists_CompareByKey() { - //DaN var a1 = new A { NonGenericEnumerable = new ArrayList { null } }; var a2 = new A { NonGenericEnumerable = new ArrayList { null, null } }; @@ -236,14 +234,10 @@ public void NullElementsEquality_CompareUnequalLists_CompareByKey() var comparer = new Comparer
(settings); var isEqual = comparer.Compare(a1, a2, out var diffs); var differences = diffs.ToArray(); - Assert.IsTrue(differences.Count() == 2); + Assert.IsTrue(differences.Count() == 1); Assert.IsTrue(differences[0].DifferenceType == DifferenceTypes.NumberOfElementsMismatch); Assert.IsTrue(differences[0].Value1 == "1"); Assert.IsTrue(differences[0].Value2 == "2"); - Assert.IsTrue(differences[1].DifferenceType == DifferenceTypes.MissedElementInFirstObject); - Assert.IsTrue(differences[1].MemberPath == "NonGenericEnumerable[1]"); - Assert.IsTrue(differences[1].Value1 == string.Empty); - Assert.IsTrue(differences[1].Value2 == string.Empty); Assert.IsFalse(isEqual); } @@ -252,6 +246,7 @@ public void NullAndNotNullElementsInequality() { var a1 = new A { NonGenericEnumerable = new ArrayList { null, "Str1" } }; var a2 = new A { NonGenericEnumerable = new ArrayList { "Str2", null } }; + var comparer = new Comparer(); var differences = comparer.CalculateDifferences(a1, a2).ToList(); @@ -265,6 +260,36 @@ public void NullAndNotNullElementsInequality() Assert.AreEqual(string.Empty, differences[1].Value2); } + [Test] + public void NullAndNotNullElementsInequality_CompareByKey() + { + var a1 = new A { NonGenericEnumerable = new ArrayList { null, "Str1" } }; + var a2 = new A { NonGenericEnumerable = new ArrayList { "Str2", null } }; + + var settings = new ComparisonSettings(); + settings.List.Configure(listOptions => + { + listOptions.CompareElementsByKey(); + }); + + var comparer = new Comparer(settings); + + var differences = comparer.CalculateDifferences(a1, a2).ToList(); + + Assert.AreEqual(2, differences.Count); + + //Missed element given a key in second object. + Assert.AreEqual(DifferenceTypes.MissedElementInSecondObject, differences[0].DifferenceType); + Assert.AreEqual("NonGenericEnumerable[Str1]", differences[0].MemberPath); + Assert.AreEqual("Str1", differences[0].Value1); + Assert.AreEqual(string.Empty, differences[0].Value2); + + Assert.AreEqual(DifferenceTypes.MissedElementInFirstObject, differences[1].DifferenceType); + Assert.AreEqual("NonGenericEnumerable[Str2]", differences[0].MemberPath); + Assert.AreEqual(string.Empty, differences[0].Value1); + Assert.AreEqual("Str2", differences[0].Value2); + } + [Test] public void InequalityType() { From 20190dfa9b3277f52fa77fd3d82bb4e1cebe4782 Mon Sep 17 00:00:00 2001 From: nemec Date: Tue, 2 Nov 2021 05:42:00 +0100 Subject: [PATCH 047/181] Add test methods into ComparerGenericEnumerableTests. ValueTypeArrayEquality_CompareByKey. --- .../Comparer_GenericEnumerableTests.cs | 53 +++++++++++++++++++ .../Comparer_NonGenericEnumerableTests.cs | 1 - 2 files changed, 53 insertions(+), 1 deletion(-) diff --git a/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs b/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs index 4123e52..dda5bde 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs @@ -21,6 +21,25 @@ public void ValueTypeArrayEquality() Assert.IsTrue(isEqual); } + [Test] + public void ValueTypeArrayEquality_CompareByKey() + { + var a1 = new A { IntArray = new[] { 2, 1 } }; + var a2 = new A { IntArray = new[] { 1, 2 } }; + + var settings = new ComparisonSettings(); + settings.List.Configure(listOptions => + { + listOptions.CompareElementsByKey(); + }); + + var comparer = new Comparer(settings); + + var isEqual = comparer.Compare(a1, a2); + + Assert.IsTrue(isEqual); + } + [Test] public void PrimitiveTypeArrayInequalityCount() { @@ -37,6 +56,40 @@ public void PrimitiveTypeArrayInequalityCount() Assert.AreEqual("3", differences[0].Value2); } + [Test] + public void PrimitiveTypeArrayInequalityCount_CompareUnequalLists() + { + var a1 = new A { IntArray = new[] { 1, 2 } }; + var a2 = new A { IntArray = new[] { 1, 2, 3 } }; + + var settings = new ComparisonSettings(); + settings.List.Configure(listOptions => + { + listOptions.CompareUnequalLists = true; + }); + + var comparer = new Comparer(settings); + var rootCtx = ComparisonContext.CreateRoot(); + var differences = comparer.CalculateDifferences(a1, a2, rootCtx).ToList(); + + CollectionAssert.IsNotEmpty(differences); + Assert.AreEqual(2, differences.Count); + + Assert.AreEqual(DifferenceTypes.MissedElementInFirstObject, differences[0].DifferenceType); + Assert.AreEqual("IntArray[2]", differences[0].MemberPath); + Assert.AreEqual(string.Empty, differences[0].Value1); + Assert.AreEqual("3", differences[0].Value2); + + Assert.AreEqual("IntArray.Length", differences[1].MemberPath); + Assert.AreEqual("2", differences[1].Value1); + Assert.AreEqual("3", differences[1].Value2); + + var diffsFromCtx = rootCtx.GetDifferences(recursive: true).ToList(); + Assert.AreEqual(2, diffsFromCtx.Count); + Assert.AreEqual(differences[0], diffsFromCtx[0]); + Assert.AreEqual(differences[1], diffsFromCtx[1]); + } + [Test] public void PrimitiveTypeArrayInequalityMember() { diff --git a/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs b/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs index 3c9b457..0992843 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs @@ -278,7 +278,6 @@ public void NullAndNotNullElementsInequality_CompareByKey() Assert.AreEqual(2, differences.Count); - //Missed element given a key in second object. Assert.AreEqual(DifferenceTypes.MissedElementInSecondObject, differences[0].DifferenceType); Assert.AreEqual("NonGenericEnumerable[Str1]", differences[0].MemberPath); Assert.AreEqual("Str1", differences[0].Value1); From 97040bac85f13a810beab6eb60e11bd77c5a5f2a Mon Sep 17 00:00:00 2001 From: "ASD\\nemec" Date: Tue, 2 Nov 2021 14:56:12 +0100 Subject: [PATCH 048/181] Add additional test methods into ComparerGenericEnumerableTests class. Code cleaning. --- .../Comparer_GenericEnumerableTests.cs | 238 ++++++++++++++++++ .../CustomComparers/EnumerablesComparer.cs | 163 ------------ .../EnumerablesComparerBase.cs | 5 +- .../CustomComparers/EnumerablesComparer~1.cs | 11 - 4 files changed, 240 insertions(+), 177 deletions(-) diff --git a/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs b/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs index dda5bde..5703d88 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs @@ -3,6 +3,7 @@ using NUnit.Framework; using ObjectsComparer.Tests.TestClasses; using System.Collections.Generic; +using ObjectsComparer.Exceptions; namespace ObjectsComparer.Tests { @@ -105,6 +106,68 @@ public void PrimitiveTypeArrayInequalityMember() Assert.AreEqual("3", differences.First().Value2); } + [Test] + public void PrimitiveTypeArrayInequalityMember_CompareByKey() + { + var a1 = new A { IntArray = new[] { 1, 2 } }; + var a2 = new A { IntArray = new[] { 1, 3 } }; + + var settings = new ComparisonSettings(); + settings.List.Configure(listOptions => + { + listOptions.CompareElementsByKey(); + }); + + var comparer = new Comparer(settings); + + var differences = comparer.CalculateDifferences(a1, a2).ToList(); + + Assert.IsTrue(differences.Count == 2); + + var diff1 = differences[0]; + Assert.AreEqual(DifferenceTypes.MissedElementInSecondObject, diff1.DifferenceType); + Assert.AreEqual("IntArray[2]", diff1.MemberPath); + Assert.AreEqual("2", diff1.Value1); + Assert.AreEqual(string.Empty, diff1.Value2); + + var diff2 = differences[1]; + Assert.AreEqual(DifferenceTypes.MissedElementInFirstObject, diff2.DifferenceType); + Assert.AreEqual("IntArray[3]", diff2.MemberPath); + Assert.AreEqual(string.Empty, diff2.Value1); + Assert.AreEqual("3", diff2.Value2); + } + + [Test] + public void PrimitiveTypeArrayInequalityMember_CompareByKey_FormatKey() + { + var a1 = new A { IntArray = new[] { 1, 2 } }; + var a2 = new A { IntArray = new[] { 1, 3 } }; + + var settings = new ComparisonSettings(); + settings.List.Configure(listOptions => + { + listOptions.CompareElementsByKey(keyOptions => keyOptions.FormatElementKey((idx, elementKey) => $"Key={elementKey}")); + }); + + var comparer = new Comparer(settings); + + var differences = comparer.CalculateDifferences(a1, a2).ToList(); + + Assert.IsTrue(differences.Count == 2); + + var diff1 = differences[0]; + Assert.AreEqual(DifferenceTypes.MissedElementInSecondObject, diff1.DifferenceType); + Assert.AreEqual("IntArray[Key=2]", diff1.MemberPath); + Assert.AreEqual("2", diff1.Value1); + Assert.AreEqual(string.Empty, diff1.Value2); + + var diff2 = differences[1]; + Assert.AreEqual(DifferenceTypes.MissedElementInFirstObject, diff2.DifferenceType); + Assert.AreEqual("IntArray[Key=3]", diff2.MemberPath); + Assert.AreEqual(string.Empty, diff2.Value1); + Assert.AreEqual("3", diff2.Value2); + } + [Test] public void PrimitiveTypeArrayInequalityFirstNull() { @@ -121,6 +184,28 @@ public void PrimitiveTypeArrayInequalityFirstNull() Assert.AreEqual(DifferenceTypes.ValueMismatch, differences.First().DifferenceType); } + [Test] + public void PrimitiveTypeArrayInequalityFirstNull_CompareBykey() + { + var a1 = new A(); + var a2 = new A { IntArray = new int[0] }; + var settings = new ComparisonSettings(); + settings.List.Configure(listOptions => + { + listOptions.CompareElementsByKey(); + }); + + var comparer = new Comparer(settings); + + var differences = comparer.CalculateDifferences(a1, a2).ToList(); + + CollectionAssert.IsNotEmpty(differences); + Assert.AreEqual("IntArray", differences.First().MemberPath); + Assert.AreEqual(string.Empty, differences.First().Value1); + Assert.AreEqual(a2.IntArray.ToString(), differences.First().Value2); + Assert.AreEqual(DifferenceTypes.ValueMismatch, differences.First().DifferenceType); + } + [Test] public void PrimitiveTypeArrayInequalitySecondNull() { @@ -136,6 +221,28 @@ public void PrimitiveTypeArrayInequalitySecondNull() Assert.AreEqual(string.Empty, differences.First().Value2); } + [Test] + public void PrimitiveTypeArrayInequalitySecondNull_CompareByKey() + { + var a1 = new A { IntArray = new int[0] }; + var a2 = new A(); + + var settings = new ComparisonSettings(); + settings.List.Configure(listOptions => + { + listOptions.CompareElementsByKey(); + }); + + var comparer = new Comparer(settings); + + var differences = comparer.CalculateDifferences(a1, a2).ToList(); + + CollectionAssert.IsNotEmpty(differences); + Assert.AreEqual("IntArray", differences.First().MemberPath); + Assert.AreEqual(a1.IntArray.ToString(), differences.First().Value1); + Assert.AreEqual(string.Empty, differences.First().Value2); + } + [Test] public void ClassArrayEquality() { @@ -148,6 +255,43 @@ public void ClassArrayEquality() Assert.IsTrue(isEqual); } + [Test] + public void ClassArrayEquality_ComareByKey_Throw_ElementKeyNotFoundException() + { + var a1 = new A { ArrayOfB = new[] { new B { Property1 = "Str1" }, new B { Property1 = "Str2" } } }; + var a2 = new A { ArrayOfB = new[] { new B { Property1 = "Str1" }, new B { Property1 = "Str2" } } }; + + var settings = new ComparisonSettings(); + settings.List.Configure(listOptions => + { + listOptions.CompareElementsByKey(); + }); + + var comparer = new Comparer(settings); + + Assert.Throws(() => + { + var isEqual = comparer.Compare(a1, a2); + }); + } + + [Test] + public void ClassArrayEquality_ComareByKey_DoesNotThrow_ElementKeyNotFoundException() + { + var a1 = new A { ArrayOfB = new[] { new B { Property1 = "Str1" }, new B { Property1 = "Str2" } } }; + var a2 = new A { ArrayOfB = new[] { new B { Property1 = "Str1" }, new B { Property1 = "Str2" } } }; + + var settings = new ComparisonSettings(); + settings.List.Configure(listOptions => listOptions.CompareElementsByKey(keyOptions => keyOptions.ThrowKeyNotFound = false)); + + var comparer = new Comparer(settings); + + Assert.DoesNotThrow(() => + { + var isEqual = comparer.Compare(a1, a2); + }); + } + [Test] public void ClassArrayInequalityCount() { @@ -164,6 +308,61 @@ public void ClassArrayInequalityCount() Assert.AreEqual("2", differences[0].Value2); } + [Test] + public void ClassArrayInequalityCount_CompareByKey_DoesNotThrow_ElementKeyNotFoundException() + { + var a1 = new A { ArrayOfB = new[] { new B { Property1 = "Str1" } } }; + var a2 = new A { ArrayOfB = new[] { new B { Property1 = "Str1" }, new B { Property1 = "Str2" } } }; + + var settings = new ComparisonSettings(); + settings.List.Configure(listOptions => + { + listOptions.CompareUnequalLists = true; + listOptions.CompareElementsByKey(keyOptions => keyOptions.ThrowKeyNotFound = false); + }); + + var comparer = new Comparer(settings); + + List differences = null; + + Assert.DoesNotThrow(() => differences = comparer.CalculateDifferences(a1, a2).ToList()); + + CollectionAssert.IsNotEmpty(differences); + Assert.AreEqual(1, differences.Count); + Assert.AreEqual("ArrayOfB.Length", differences[0].MemberPath); + Assert.AreEqual("1", differences[0].Value1); + Assert.AreEqual("2", differences[0].Value2); + } + + [Test] + public void ClassArrayInequalityCount_CompareUnequalLists() + { + var a1 = new A { ArrayOfB = new[] { new B { Property1 = "Str1" } } }; + var a2 = new A { ArrayOfB = new[] { new B { Property1 = "Str1" }, new B { Property1 = "Str2" } } }; + + var settings = new ComparisonSettings(); + settings.List.Configure(listOptions => + { + listOptions.CompareUnequalLists = true; + }); + + var comparer = new Comparer(settings); + + var differences = comparer.CalculateDifferences(a1, a2).ToList(); + + CollectionAssert.IsNotEmpty(differences); + Assert.AreEqual(2, differences.Count); + + Assert.AreEqual(DifferenceTypes.MissedElementInFirstObject, differences[0].DifferenceType); + Assert.AreEqual("ArrayOfB[1]", differences[0].MemberPath); + Assert.AreEqual(string.Empty, differences[0].Value1); + Assert.AreEqual("ObjectsComparer.Tests.TestClasses.B", differences[0].Value2); + + Assert.AreEqual("ArrayOfB.Length", differences[1].MemberPath); + Assert.AreEqual("1", differences[1].Value1); + Assert.AreEqual("2", differences[1].Value2); + } + [Test] public void ClassArrayInequalityProperty() { @@ -179,6 +378,45 @@ public void ClassArrayInequalityProperty() Assert.AreEqual("Str3", differences.First().Value2); } + [Test] + public void ClassArrayInequalityProperty_CompareByKey() + { + var a1 = new A { ArrayOfB = new[] { new B { Property1 = "Str2", Id = 1 }, new B { Property1 = "Str1", Id = 2 } } }; + var a2 = new A { ArrayOfB = new[] { new B { Property1 = "Str1", Id = 2 }, new B { Property1 = "Str3", Id = 1 } } }; + + var settings = new ComparisonSettings(); + settings.List.Configure(listOptions => listOptions.CompareElementsByKey()); + + var comparer = new Comparer(settings); + + var differences = comparer.CalculateDifferences(a1, a2).ToList(); + + CollectionAssert.IsNotEmpty(differences); + Assert.AreEqual("ArrayOfB[1].Property1", differences.First().MemberPath); + Assert.AreEqual("Str2", differences.First().Value1); + Assert.AreEqual("Str3", differences.First().Value2); + } + + [Test] + public void ClassArrayInequalityProperty_CompareByKey_FormatKey() + { + //!!! + var a1 = new A { ArrayOfB = new[] { new B { Property1 = "Str2", Id = 4 }, new B { Property1 = "Str1", Id = 9 } } }; + var a2 = new A { ArrayOfB = new[] { new B { Property1 = "Str1", Id = 9 }, new B { Property1 = "Str3", Id = 4 } } }; + + var settings = new ComparisonSettings(); + settings.List.Configure(listOptions => listOptions.CompareElementsByKey(keyOptions => keyOptions.FormatElementKey((idx, elementKey) => $"Key={elementKey}"))); + + var comparer = new Comparer(settings); + + var differences = comparer.CalculateDifferences(a1, a2).ToList(); + + CollectionAssert.IsNotEmpty(differences); + Assert.AreEqual("ArrayOfB[Key=4].Property1", differences.First().MemberPath); + Assert.AreEqual("Str2", differences.First().Value1); + Assert.AreEqual("Str3", differences.First().Value2); + } + [Test] public void CollectionEquality() { diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs index 41951b2..abc31c4 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs @@ -76,169 +76,6 @@ public IEnumerable CalculateDifferences(Type type, object obj1, obje } } - private IEnumerable _CalculateDifferencesByKey(object[] array1, object[] array2, ComparisonContext listComparisonContext, ListConfigurationOptions listConfigurationOptions) - { - Debug.WriteLine(nameof(CalculateDifferencesByKey)); - - var keyOptions = CompareElementsByKeyOptions.Default(); - listConfigurationOptions.KeyOptionsAction?.Invoke(keyOptions); - - for (int element1Index = 0; element1Index < array1.Length; element1Index++) - { - var element1 = array1[element1Index]; - var elementComparisonContext = ComparisonContext.Create(ancestor: listComparisonContext); - - if (element1 == null) - { - if (array2.Any(elm2 => elm2 == null)) - { - continue; - } - - var nullElementIdentifier = keyOptions.GetNullElementIdentifier(element1Index); - - yield return AddDifferenceToComparisonContext(new Difference($"[{nullElementIdentifier}]", string.Empty, string.Empty, DifferenceTypes.MissedElementInSecondObject), elementComparisonContext); - continue; - } - - var element1Key = keyOptions.KeyProvider(element1); - - if (element1Key == null) - { - if (keyOptions.ThrowKeyNotFound) - { - throw new ElementKeyNotFoundException(element1, elementComparisonContext); - } - - continue; - } - - var formattedElement1Key = keyOptions.GetFormattedElementKey(element1Index, element1Key); - - if (array2.Any(elm2 => object.Equals(element1Key, keyOptions.KeyProvider(elm2)))) - { - var element2 = array2.First(elm2 => object.Equals(element1Key, keyOptions.KeyProvider(elm2))); - var comparer = Factory.GetObjectsComparer(element1.GetType(), Settings, this); - - foreach (var failure in comparer.CalculateDifferences(element1.GetType(), element1, element2, elementComparisonContext)) - { - yield return failure.InsertPath($"[{formattedElement1Key}]"); - } - } - else - { - var valueComparer1 = OverridesCollection.GetComparer(element1.GetType()) ?? DefaultValueComparer; - yield return AddDifferenceToComparisonContext(new Difference($"[{formattedElement1Key}]", valueComparer1.ToString(element1), string.Empty, DifferenceTypes.MissedElementInSecondObject), elementComparisonContext); - } - } - - for (int element2Index = 0; element2Index < array2.Length; element2Index++) - { - var element2 = array2[element2Index]; - var elementComparisonContext = ComparisonContext.Create(ancestor: listComparisonContext); - - if (element2 == null) - { - if (array1.Any(elm1 => elm1 == null)) - { - continue; - } - - var nullElementIdentifier = keyOptions.GetNullElementIdentifier(element2Index); - - yield return AddDifferenceToComparisonContext(new Difference($"[{nullElementIdentifier}]", string.Empty, string.Empty, DifferenceTypes.MissedElementInFirstObject), elementComparisonContext); - continue; - } - - var element2Key = keyOptions.KeyProvider(element2); - - if (element2Key == null) - { - if (keyOptions.ThrowKeyNotFound) - { - throw new ElementKeyNotFoundException(element2, elementComparisonContext); - } - - continue; - } - - if (array1.Any(elm1 => object.Equals(element2Key, keyOptions.KeyProvider(elm1))) == false) - { - //var elementComparisonContext = ComparisonContext.Create(ancestor: listComparisonContext); - var formattedElement2Key = keyOptions.GetFormattedElementKey(element2Index, element2Key); - var valueComparer2 = OverridesCollection.GetComparer(element2.GetType()) ?? DefaultValueComparer; - yield return AddDifferenceToComparisonContext(new Difference($"[{formattedElement2Key}]", string.Empty, valueComparer2.ToString(element2), DifferenceTypes.MissedElementInFirstObject), elementComparisonContext); - } - } - } - - private IEnumerable _CalculateDifferencesByIndex(object[] array1, object[] array2, ComparisonContext listComparisonContext) - { - Debug.WriteLine(nameof(CalculateDifferencesByIndex)); - - int array1Count = array1.Count(); - int array2Count = array2.Count(); - int smallerCount = array1Count <= array2Count ? array1Count : array2Count; - - //ToDo Extract type - for (var i = 0; i < smallerCount; i++) - { - var elementComparisonContext = ComparisonContext.Create(ancestor: listComparisonContext); - - if (array1[i] == null && array2[i] == null) - { - continue; - } - - var valueComparer1 = array1[i] != null ? OverridesCollection.GetComparer(array1[i].GetType()) ?? DefaultValueComparer : DefaultValueComparer; - var valueComparer2 = array2[i] != null ? OverridesCollection.GetComparer(array2[i].GetType()) ?? DefaultValueComparer : DefaultValueComparer; - - if (array1[i] == null) - { - yield return AddDifferenceToComparisonContext(new Difference($"[{i}]", string.Empty, valueComparer2.ToString(array2[i])), elementComparisonContext); - continue; - } - - if (array2[i] == null) - { - yield return AddDifferenceToComparisonContext(new Difference($"[{i}]", valueComparer1.ToString(array1[i]), string.Empty), elementComparisonContext); - continue; - } - - if (array1[i].GetType() != array2[i].GetType()) - { - yield return AddDifferenceToComparisonContext(new Difference($"[{i}]", valueComparer1.ToString(array1[i]), valueComparer2.ToString(array2[i]), DifferenceTypes.TypeMismatch), elementComparisonContext); - continue; - } - - var comparer = Factory.GetObjectsComparer(array1[i].GetType(), Settings, this); - - foreach (var failure in comparer.CalculateDifferences(array1[i].GetType(), array1[i], array2[i], elementComparisonContext)) - { - yield return failure.InsertPath($"[{i}]"); - } - } - - //Add a "missed element" difference for each element that is in array1 and that is not in array2 or vice versa. - if (array1Count != array2Count) - { - var largerArray = array1Count > array2Count ? array1 : array2; - - for (int i = smallerCount; i < largerArray.Length; i++) - { - var valueComparer = largerArray[i] != null ? OverridesCollection.GetComparer(largerArray[i].GetType()) ?? DefaultValueComparer : DefaultValueComparer; - - var difference = new Difference( - memberPath: $"[{i}]", - value1: array1Count > array2Count ? valueComparer.ToString(largerArray[i]) : string.Empty, - value2: array2Count > array1Count ? valueComparer.ToString(largerArray[i]) : string.Empty, - differenceType: array1Count > array2Count ? DifferenceTypes.MissedElementInSecondObject : DifferenceTypes.MissedElementInFirstObject); - - yield return AddDifferenceToComparisonContext(difference, ComparisonContext.Create(ancestor: listComparisonContext)); - } - } - } - public bool IsMatch(Type type, object obj1, object obj2) { return type.InheritsFrom(typeof(IEnumerable)) && !type.InheritsFrom(typeof(IEnumerable<>)); diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparerBase.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparerBase.cs index 69faf01..34dc57c 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparerBase.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparerBase.cs @@ -36,7 +36,7 @@ protected virtual IEnumerable CalculateDifferences(IList list1 /// protected virtual IEnumerable CalculateDifferencesByKey(IList array1, IList array2, ComparisonContext listComparisonContext, ListConfigurationOptions listConfigurationOptions) { - Debug.WriteLine(nameof(CalculateDifferencesByKey)); + Debug.WriteLine($"{nameof(CalculateDifferencesByKey)}: {array1?.GetType().Name}"); var keyOptions = CompareElementsByKeyOptions.Default(); listConfigurationOptions.KeyOptionsAction?.Invoke(keyOptions); @@ -122,7 +122,6 @@ protected virtual IEnumerable CalculateDifferencesByKey(IList if (array1.Any(elm1 => object.Equals(element2Key, keyOptions.KeyProvider(elm1))) == false) { - //var elementComparisonContext = ComparisonContext.Create(ancestor: listComparisonContext); var formattedElement2Key = keyOptions.GetFormattedElementKey(element2Index, element2Key); var valueComparer2 = OverridesCollection.GetComparer(element2.GetType()) ?? DefaultValueComparer; yield return AddDifferenceToComparisonContext(new Difference($"[{formattedElement2Key}]", string.Empty, valueComparer2.ToString(element2), DifferenceTypes.MissedElementInFirstObject), elementComparisonContext); @@ -135,7 +134,7 @@ protected virtual IEnumerable CalculateDifferencesByKey(IList /// protected virtual IEnumerable CalculateDifferencesByIndex(IList array1, IList array2, ComparisonContext listComparisonContext) { - Debug.WriteLine(nameof(CalculateDifferencesByIndex)); + Debug.WriteLine($"{nameof(CalculateDifferencesByIndex)}: {array1?.GetType().Name}"); int array1Count = array1.Count(); int array2Count = array2.Count(); diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer~1.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer~1.cs index b2c0993..37c7caf 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer~1.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer~1.cs @@ -70,17 +70,6 @@ public IEnumerable CalculateDifferences(Type type, object obj1, obje } } - //for (var i = 0; i < list2.Count; i++) - //{ - // //List item has not got its MemberInfo, but has got its ancestor - list. - // var context = ComparisonContext.Create(member: null, ancestor: comparisonContext); - - // foreach (var failure in _comparer.CalculateDifferences(list1[i], list2[i], context)) - // { - // yield return failure.InsertPath($"[{i}]"); - // } - //} - IEnumerable failrues = CalculateDifferences(list1, list2, listComparisonContext, listConfigurationOptions); foreach (var failrue in failrues) From dedecd9ab980c83c6ac822ef802f4f1bfde6906c Mon Sep 17 00:00:00 2001 From: nemec Date: Tue, 2 Nov 2021 22:09:36 +0100 Subject: [PATCH 049/181] CompareElementsByKeyOptions: Add ElementKeyFormatter overloads. Func formatter, Func formatter. --- .../Comparer_GenericEnumerableTests.cs | 21 ++++++++++++-- .../CompareElementsByKeyOptions.cs | 28 +++++++++++++++---- .../EnumerablesComparerBase.cs | 4 +-- 3 files changed, 43 insertions(+), 10 deletions(-) diff --git a/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs b/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs index 5703d88..f4d2a91 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs @@ -146,7 +146,7 @@ public void PrimitiveTypeArrayInequalityMember_CompareByKey_FormatKey() var settings = new ComparisonSettings(); settings.List.Configure(listOptions => { - listOptions.CompareElementsByKey(keyOptions => keyOptions.FormatElementKey((idx, elementKey) => $"Key={elementKey}")); + listOptions.CompareElementsByKey(keyOptions => keyOptions.FormatElementKey(elementKey => $"Key={elementKey}")); }); var comparer = new Comparer(settings); @@ -400,12 +400,11 @@ public void ClassArrayInequalityProperty_CompareByKey() [Test] public void ClassArrayInequalityProperty_CompareByKey_FormatKey() { - //!!! var a1 = new A { ArrayOfB = new[] { new B { Property1 = "Str2", Id = 4 }, new B { Property1 = "Str1", Id = 9 } } }; var a2 = new A { ArrayOfB = new[] { new B { Property1 = "Str1", Id = 9 }, new B { Property1 = "Str3", Id = 4 } } }; var settings = new ComparisonSettings(); - settings.List.Configure(listOptions => listOptions.CompareElementsByKey(keyOptions => keyOptions.FormatElementKey((idx, elementKey) => $"Key={elementKey}"))); + settings.List.Configure(listOptions => listOptions.CompareElementsByKey(keyOptions => keyOptions.FormatElementKey(elementKey => $"Key={elementKey}"))); var comparer = new Comparer(settings); @@ -429,6 +428,22 @@ public void CollectionEquality() Assert.IsTrue(isEqual); } + [Test] + public void CollectionEquality_CompareByKey() + { + var a1 = new A { CollectionOfB = new Collection { new B { Property1 = "Str2", Id = 1 }, new B { Property1 = "Str1", Id = 2 } } }; + var a2 = new A { CollectionOfB = new Collection { new B { Property1 = "Str1", Id = 2 }, new B { Property1 = "Str2", Id = 1 } } }; + + var settings = new ComparisonSettings(); + settings.List.Configure(listOptions => listOptions.CompareElementsByKey()); + + var comparer = new Comparer(settings); + + var isEqual = comparer.Compare(a1, a2); + + Assert.IsTrue(isEqual); + } + [Test] public void CollectionInequalityCount() { diff --git a/ObjectsComparer/ObjectsComparer/CompareElementsByKeyOptions.cs b/ObjectsComparer/ObjectsComparer/CompareElementsByKeyOptions.cs index 98cf01a..3d639f5 100644 --- a/ObjectsComparer/ObjectsComparer/CompareElementsByKeyOptions.cs +++ b/ObjectsComparer/ObjectsComparer/CompareElementsByKeyOptions.cs @@ -35,7 +35,7 @@ public class CompareElementsByKeyOptions /// /// See . /// - Func ElementKeyFormatter { get; set; } + Func ElementKeyFormatter { get; set; } /// /// See . @@ -144,14 +144,14 @@ static object GetKeyValue(object instance, bool caseSensitive, params string[] k /// /// Returns optional formatted or unformatted . See . /// - internal string GetFormattedElementKey(int elementIndex, object elementKey) + internal string GetFormattedElementKey(int elementIndex, object elementKey, object element) { if (elementKey is null) { throw new ArgumentNullException(nameof(elementKey)); } - var formattedKey = ElementKeyFormatter?.Invoke(elementIndex, elementKey); + var formattedKey = ElementKeyFormatter?.Invoke(elementIndex, elementKey, element); if (string.IsNullOrWhiteSpace(formattedKey)) { @@ -177,14 +177,32 @@ internal string GetNullElementIdentifier(int elementIndex) return elementIdentifier.Left(NullElementIdentifierMaxLength); } + /// + /// Formats element key. For more info, see . + /// + /// Parameter: Element key. Return value: Formatted element key. + public void FormatElementKey(Func formatter) + { + FormatElementKey((elementIndex, elementKey, element) => formatter(elementKey)); + } + + /// + /// Formats element key. For more info, see . + /// + /// First parameter: Element index. Second parameter: Element key. Return value: Formatted element key. + public void FormatElementKey(Func formatter) + { + FormatElementKey((elementIndex, elementKey, element) => formatter(elementIndex, elementKey)); + } + /// /// To avoid possible confusion of the element key with the element index, the element key can be formatted with any text.
/// For example, element key with value = 1 can be formatted as "Id=1". /// The formatted element key is then used as part of the property, e.g. "Addresses[Id=1]".
/// By default the element key is not formatted. ///
- /// First parameter: Element index. Second parameter: Element key. Return value: Formatted key. - public void FormatElementKey(Func formatter) + /// First parameter: Element index. Second parameter: Element key. Third parameter: Element. Return value: Formatted element key. + public void FormatElementKey(Func formatter) { if (formatter is null) { diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparerBase.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparerBase.cs index 34dc57c..b62cdbf 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparerBase.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparerBase.cs @@ -71,7 +71,7 @@ protected virtual IEnumerable CalculateDifferencesByKey(IList continue; } - var formattedElement1Key = keyOptions.GetFormattedElementKey(element1Index, element1Key); + var formattedElement1Key = keyOptions.GetFormattedElementKey(element1Index, element1Key, element1); if (array2.Any(elm2 => object.Equals(element1Key, keyOptions.KeyProvider(elm2)))) { @@ -122,7 +122,7 @@ protected virtual IEnumerable CalculateDifferencesByKey(IList if (array1.Any(elm1 => object.Equals(element2Key, keyOptions.KeyProvider(elm1))) == false) { - var formattedElement2Key = keyOptions.GetFormattedElementKey(element2Index, element2Key); + var formattedElement2Key = keyOptions.GetFormattedElementKey(element2Index, element2Key, element2); var valueComparer2 = OverridesCollection.GetComparer(element2.GetType()) ?? DefaultValueComparer; yield return AddDifferenceToComparisonContext(new Difference($"[{formattedElement2Key}]", string.Empty, valueComparer2.ToString(element2), DifferenceTypes.MissedElementInFirstObject), elementComparisonContext); } From e79bf14dad7a0f8c5708acad6908fd8b7c977fff Mon Sep 17 00:00:00 2001 From: "ASD\\nemec" Date: Wed, 3 Nov 2021 14:33:35 +0100 Subject: [PATCH 050/181] Add aditional test methods into ComparerGenericEnumerableTests class. --- .../Comparer_GenericEnumerableTests.cs | 337 ++++++++++++++++-- .../Comparer_MultidimensionalArraysTests.cs | 29 ++ .../CompareElementsByKeyOptions.cs | 15 + .../EnumerablesComparerBase.cs | 4 +- 4 files changed, 359 insertions(+), 26 deletions(-) diff --git a/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs b/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs index f4d2a91..efde44a 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs @@ -4,6 +4,7 @@ using ObjectsComparer.Tests.TestClasses; using System.Collections.Generic; using ObjectsComparer.Exceptions; +using System; namespace ObjectsComparer.Tests { @@ -31,7 +32,7 @@ public void ValueTypeArrayEquality_CompareByKey() var settings = new ComparisonSettings(); settings.List.Configure(listOptions => { - listOptions.CompareElementsByKey(); + listOptions.CompareElementsByKey(opt => opt.UseKey("MyKey")); }); var comparer = new Comparer
(settings); @@ -113,10 +114,7 @@ public void PrimitiveTypeArrayInequalityMember_CompareByKey() var a2 = new A { IntArray = new[] { 1, 3 } }; var settings = new ComparisonSettings(); - settings.List.Configure(listOptions => - { - listOptions.CompareElementsByKey(); - }); + settings.List.Configure(listOptions => listOptions.CompareElementsByKey()); var comparer = new Comparer(settings); @@ -190,10 +188,7 @@ public void PrimitiveTypeArrayInequalityFirstNull_CompareBykey() var a1 = new A(); var a2 = new A { IntArray = new int[0] }; var settings = new ComparisonSettings(); - settings.List.Configure(listOptions => - { - listOptions.CompareElementsByKey(); - }); + settings.List.Configure(listOptions => listOptions.CompareElementsByKey()); var comparer = new Comparer(settings); @@ -228,10 +223,7 @@ public void PrimitiveTypeArrayInequalitySecondNull_CompareByKey() var a2 = new A(); var settings = new ComparisonSettings(); - settings.List.Configure(listOptions => - { - listOptions.CompareElementsByKey(); - }); + settings.List.Configure(listOptions => listOptions.CompareElementsByKey()); var comparer = new Comparer(settings); @@ -262,10 +254,7 @@ public void ClassArrayEquality_ComareByKey_Throw_ElementKeyNotFoundException() var a2 = new A { ArrayOfB = new[] { new B { Property1 = "Str1" }, new B { Property1 = "Str2" } } }; var settings = new ComparisonSettings(); - settings.List.Configure(listOptions => - { - listOptions.CompareElementsByKey(); - }); + settings.List.Configure(listOptions => listOptions.CompareElementsByKey()); var comparer = new Comparer(settings); @@ -285,11 +274,14 @@ public void ClassArrayEquality_ComareByKey_DoesNotThrow_ElementKeyNotFoundExcept settings.List.Configure(listOptions => listOptions.CompareElementsByKey(keyOptions => keyOptions.ThrowKeyNotFound = false)); var comparer = new Comparer(settings); + bool isEqual = false; Assert.DoesNotThrow(() => { - var isEqual = comparer.Compare(a1, a2); + isEqual = comparer.Compare(a1, a2); }); + + Assert.IsTrue(isEqual); } [Test] @@ -400,18 +392,18 @@ public void ClassArrayInequalityProperty_CompareByKey() [Test] public void ClassArrayInequalityProperty_CompareByKey_FormatKey() { - var a1 = new A { ArrayOfB = new[] { new B { Property1 = "Str2", Id = 4 }, new B { Property1 = "Str1", Id = 9 } } }; - var a2 = new A { ArrayOfB = new[] { new B { Property1 = "Str1", Id = 9 }, new B { Property1 = "Str3", Id = 4 } } }; + var a1 = new A { ArrayOfB = new[] { new B { Property1 = "Str2", Id = 2 }, new B { Property1 = "Str1", Id = 1 } } }; + var a2 = new A { ArrayOfB = new[] { new B { Property1 = "Str1", Id = 1 }, new B { Property1 = "Str3", Id = 2 } } }; var settings = new ComparisonSettings(); - settings.List.Configure(listOptions => listOptions.CompareElementsByKey(keyOptions => keyOptions.FormatElementKey(elementKey => $"Key={elementKey}"))); + settings.List.Configure(listOptions => listOptions.CompareElementsByKey(keyOptions => keyOptions.FormatElementKey(elementKey => $"Id={elementKey}"))); var comparer = new Comparer(settings); var differences = comparer.CalculateDifferences(a1, a2).ToList(); - CollectionAssert.IsNotEmpty(differences); - Assert.AreEqual("ArrayOfB[Key=4].Property1", differences.First().MemberPath); + Assert.AreEqual(1, differences.Count); + Assert.AreEqual("ArrayOfB[Id=2].Property1", differences.First().MemberPath); Assert.AreEqual("Str2", differences.First().Value1); Assert.AreEqual("Str3", differences.First().Value2); } @@ -461,6 +453,36 @@ public void CollectionInequalityCount() Assert.AreEqual("1", differences[0].Value2); } + [Test] + public void CollectionInequalityCount_CompareUnequalLists() + { + var a1 = new A { CollectionOfB = new Collection { new B { Property1 = "Str1" }, new B { Property1 = "Str2" } } }; + var a2 = new A { CollectionOfB = new Collection { new B { Property1 = "Str1" } } }; + + var settings = new ComparisonSettings(); + settings.List.Configure(listOptions => + { + listOptions.CompareUnequalLists = true; + }); + + var comparer = new Comparer(settings); + + var differences = comparer.CalculateDifferences(a1, a2).ToList(); + + CollectionAssert.IsNotEmpty(differences); + Assert.AreEqual(2, differences.Count); + + Assert.AreEqual(DifferenceTypes.NumberOfElementsMismatch, differences[0].DifferenceType); + Assert.AreEqual("CollectionOfB", differences[0].MemberPath); + Assert.AreEqual("2", differences[0].Value1); + Assert.AreEqual("1", differences[0].Value2); + + Assert.AreEqual(DifferenceTypes.MissedElementInSecondObject, differences[1].DifferenceType); + Assert.AreEqual("CollectionOfB[1]", differences[1].MemberPath); + Assert.AreEqual("ObjectsComparer.Tests.TestClasses.B", differences[1].Value1); + Assert.AreEqual("", differences[1].Value2); + } + [Test] public void CollectionAndNullInequality() { @@ -477,6 +499,29 @@ public void CollectionAndNullInequality() Assert.AreEqual(string.Empty, differences[0].Value2); } + [Test] + public void CollectionAndNullInequality_CompareByKey() + { + var a1 = new A { CollectionOfB = new Collection { new B { Property1 = "Str1" }, new B { Property1 = "Str2" } } }; + var a2 = new A(); + + var settings = new ComparisonSettings(); + settings.List.Configure(listOptions => + { + listOptions.CompareElementsByKey(); + }); + + var comparer = new Comparer(settings); + + var differences = comparer.CalculateDifferences(a1, a2).ToList(); + + CollectionAssert.IsNotEmpty(differences); + Assert.AreEqual(1, differences.Count); + Assert.AreEqual("CollectionOfB", differences[0].MemberPath); + Assert.AreEqual(a1.CollectionOfB.ToString(), differences[0].Value1); + Assert.AreEqual(string.Empty, differences[0].Value2); + } + [Test] public void NullAndCollectionInequality() { @@ -493,6 +538,29 @@ public void NullAndCollectionInequality() Assert.AreEqual(a2.CollectionOfB.ToString(), differences[0].Value2); } + [Test] + public void NullAndCollectionInequality_CompareByKey() + { + var a1 = new A(); + var a2 = new A { CollectionOfB = new Collection { new B { Property1 = "Str1" }, new B { Property1 = "Str2" } } }; + + var settings = new ComparisonSettings(); + settings.List.Configure(listOptions => + { + listOptions.CompareElementsByKey(); + }); + + var comparer = new Comparer(settings); + + var differences = comparer.CalculateDifferences(a1, a2).ToList(); + + CollectionAssert.IsNotEmpty(differences); + Assert.AreEqual(1, differences.Count); + Assert.AreEqual("CollectionOfB", differences[0].MemberPath); + Assert.AreEqual(string.Empty, differences[0].Value1); + Assert.AreEqual(a2.CollectionOfB.ToString(), differences[0].Value2); + } + [Test] public void CollectionInequalityProperty() { @@ -508,6 +576,25 @@ public void CollectionInequalityProperty() Assert.AreEqual("Str3", differences.First().Value2); } + [Test] + public void CollectionInequalityProperty_CompareByKey() + { + var a1 = new A { CollectionOfB = new Collection { new B { Property1 = "Str2", Id = 1 }, new B { Property1 = "Str1", Id = 2 } } }; + var a2 = new A { CollectionOfB = new Collection { new B { Property1 = "Str1", Id = 2 }, new B { Property1 = "Str3", Id = 1 } } }; + + var settings = new ComparisonSettings(); + settings.List.Configure(listOptions => listOptions.CompareElementsByKey()); + + var comparer = new Comparer(settings); + + var differences = comparer.CalculateDifferences(a1, a2).ToList(); + + CollectionAssert.IsNotEmpty(differences); + Assert.AreEqual("CollectionOfB[1].Property1", differences.First().MemberPath); + Assert.AreEqual("Str2", differences.First().Value1); + Assert.AreEqual("Str3", differences.First().Value2); + } + [Test] public void ClassImplementsCollectionEquality() { @@ -520,6 +607,22 @@ public void ClassImplementsCollectionEquality() Assert.IsTrue(isEqual); } + [Test] + public void ClassImplementsCollectionEquality_CompareByKey() + { + var a1 = new A { ClassImplementsCollectionOfB = new CollectionOfB { new B { Property1 = "Str1", Id = 1 }, new B { Property1 = "Str2", Id = 2 } } }; + var a2 = new A { ClassImplementsCollectionOfB = new CollectionOfB { new B { Property1 = "Str1", Id = 1 }, new B { Property1 = "Str2", Id = 2 } } }; + + var settings = new ComparisonSettings(); + settings.List.Configure(listOptions => listOptions.CompareElementsByKey()); + + var comparer = new Comparer(settings); + + var isEqual = comparer.Compare(a1, a2); + + Assert.IsTrue(isEqual); + } + [Test] public void ClassImplementsCollectionInequalityCount() { @@ -537,6 +640,64 @@ public void ClassImplementsCollectionInequalityCount() Assert.AreEqual("1", differences[0].Value2); } + [Test] + public void ClassImplementsCollectionInequalityCount_CompareUnequalLists() + { + var a1 = new A { ClassImplementsCollectionOfB = new CollectionOfB { new B { Property1 = "Str1" }, new B { Property1 = "Str2" } } }; + var a2 = new A { ClassImplementsCollectionOfB = new CollectionOfB { new B { Property1 = "Str1" } } }; + + var settings = new ComparisonSettings(); + settings.List.Configure(listOptions => listOptions.CompareUnequalLists = true); + + var comparer = new Comparer(settings); + + var differences = comparer.CalculateDifferences(a1, a2).ToList(); + + CollectionAssert.IsNotEmpty(differences); + Assert.AreEqual(2, differences.Count); + + Assert.AreEqual(DifferenceTypes.NumberOfElementsMismatch, differences[0].DifferenceType); + Assert.AreEqual("ClassImplementsCollectionOfB", differences[0].MemberPath); + Assert.AreEqual("2", differences[0].Value1); + Assert.AreEqual("1", differences[0].Value2); + + Assert.AreEqual(DifferenceTypes.MissedElementInSecondObject, differences[1].DifferenceType); + Assert.AreEqual("ClassImplementsCollectionOfB[1]", differences[1].MemberPath); + Assert.AreEqual("ObjectsComparer.Tests.TestClasses.B", differences[1].Value1); + Assert.AreEqual("", differences[1].Value2); + } + + [Test] + public void ClassImplementsCollectionInequalityCount_CompareUnequalLists_CompareByKey() + { + var a1 = new A { ClassImplementsCollectionOfB = new CollectionOfB { new B { Property1 = "Str1", Id = 1 }, new B { Property1 = "Str2", Id = 2 } } }; + var a2 = new A { ClassImplementsCollectionOfB = new CollectionOfB { new B { Property1 = "Str1", Id = 1 } } }; + + var settings = new ComparisonSettings(); + settings.List.Configure(listOptions => + { + listOptions.CompareUnequalLists = true; + listOptions.CompareElementsByKey(); + }); + + var comparer = new Comparer(settings); + + var differences = comparer.CalculateDifferences(a1, a2).ToList(); + + CollectionAssert.IsNotEmpty(differences); + Assert.AreEqual(2, differences.Count); + + Assert.AreEqual(DifferenceTypes.NumberOfElementsMismatch, differences[0].DifferenceType); + Assert.AreEqual("ClassImplementsCollectionOfB", differences[0].MemberPath); + Assert.AreEqual("2", differences[0].Value1); + Assert.AreEqual("1", differences[0].Value2); + + Assert.AreEqual(DifferenceTypes.MissedElementInSecondObject, differences[1].DifferenceType); + Assert.AreEqual("ClassImplementsCollectionOfB[2]", differences[1].MemberPath); + Assert.AreEqual("ObjectsComparer.Tests.TestClasses.B", differences[1].Value1); + Assert.AreEqual("", differences[1].Value2); + } + [Test] public void ClassImplementsCollectionInequalityProperty() { @@ -552,6 +713,29 @@ public void ClassImplementsCollectionInequalityProperty() Assert.AreEqual("Str3", differences.First().Value2); } + [Test] + public void ClassImplementsCollectionInequalityProperty_CompareByKey() + { + var a1 = new A { ClassImplementsCollectionOfB = new CollectionOfB { new B { Property1 = "Str1", Id = 1 }, new B { Property1 = "Str2", Id = 2 } } }; + var a2 = new A { ClassImplementsCollectionOfB = new CollectionOfB { new B { Property1 = "Str1", Id = 1 }, new B { Property1 = "Str3", Id = 2 } } }; + + var settings = new ComparisonSettings(); + settings.List.Configure(listOptions => + { + listOptions.CompareUnequalLists = true; + listOptions.CompareElementsByKey(); + }); + + var comparer = new Comparer(settings); + + var differences = comparer.CalculateDifferences(a1, a2).ToList(); + + CollectionAssert.IsNotEmpty(differences); + Assert.AreEqual("ClassImplementsCollectionOfB[2].Property1", differences.First().MemberPath); + Assert.AreEqual("Str2", differences.First().Value1); + Assert.AreEqual("Str3", differences.First().Value2); + } + [Test] public void NullAndEmptyComparisonGenericInequality() { @@ -640,6 +824,74 @@ public void CollectionOfBCountInequality1() Assert.AreEqual("2", differences.First().Value2); } + [Test] + public void CollectionOfBCountInequality1_CompareElementsByKey() + { + var a1 = new A + { + EnumerableOfB = new[] { new B { Property1 = "B1" } } + }; + var a2 = new A + { + EnumerableOfB = new[] { new B { Property1 = "B1" }, new B { Property1 = "B2" } } + }; + + var settings = new ComparisonSettings(); + settings.List.Configure(listOptions => listOptions.CompareElementsByKey()); + + var comparer = new Comparer(settings); + + var isEqual = comparer.Compare(a1, a2, out var differencesEnum); + var differences = differencesEnum.ToList(); + + Assert.IsFalse(isEqual); + CollectionAssert.IsNotEmpty(differences); + Assert.AreEqual(1, differences.Count); + Assert.AreEqual("EnumerableOfB", differences.First().MemberPath); + Assert.AreEqual(DifferenceTypes.NumberOfElementsMismatch, differences.First().DifferenceType); + Assert.AreEqual("1", differences.First().Value1); + Assert.AreEqual("2", differences.First().Value2); + } + + [Test] + public void CollectionOfBCountInequality1_CompareElementsByKey_CompareUnequalLists() + { + var a1 = new A + { + EnumerableOfB = new[] { new B { Property1 = "B1", Id = 1 } } + }; + var a2 = new A + { + EnumerableOfB = new[] { new B { Property1 = "B1", Id = 1 }, new B { Property1 = "B2", Id = 2 } } + }; + + var settings = new ComparisonSettings(); + settings.List.Configure(listOptions => + { + listOptions.CompareUnequalLists = true; + listOptions.CompareElementsByKey(); + }); + + var comparer = new Comparer(settings); + + var isEqual = comparer.Compare(a1, a2, out var differencesEnum); + var differences = differencesEnum.ToList(); + + Assert.IsFalse(isEqual); + CollectionAssert.IsNotEmpty(differences); + Assert.AreEqual(2, differences.Count); + + Assert.AreEqual("EnumerableOfB", differences.First().MemberPath); + Assert.AreEqual(DifferenceTypes.NumberOfElementsMismatch, differences.First().DifferenceType); + Assert.AreEqual("1", differences.First().Value1); + Assert.AreEqual("2", differences.First().Value2); + + Assert.AreEqual("EnumerableOfB[2]", differences[1].MemberPath); + Assert.AreEqual(DifferenceTypes.MissedElementInFirstObject, differences[1].DifferenceType); + Assert.AreEqual("", differences[1].Value1); + Assert.AreEqual("ObjectsComparer.Tests.TestClasses.B", differences[1].Value2); + } + [Test] public void CollectionOfBCountInequality2() { @@ -650,7 +902,7 @@ public void CollectionOfBCountInequality2() var a2 = new A { EnumerableOfB = new B[0] - }; + }; var comparer = new Comparer(); var isEqual = comparer.Compare(a1, a2, out var differencesEnum); @@ -665,6 +917,43 @@ public void CollectionOfBCountInequality2() Assert.AreEqual("0", differences.First().Value2); } + [Test] + public void CollectionOfBCountInequality2_CompareByKey() + { + var a1 = new A + { + EnumerableOfB = new[] { new B { Property1 = "B1", Id = 1 } } + }; + var a2 = new A + { + EnumerableOfB = new B[0] + }; + + var settings = new ComparisonSettings(); + settings.List.Configure(listOptions => + { + listOptions.CompareUnequalLists = true; + listOptions.CompareElementsByKey(); + }); + var comparer = new Comparer(settings); + + var isEqual = comparer.Compare(a1, a2, out var differencesEnum); + var differences = differencesEnum.ToList(); + + Assert.IsFalse(isEqual); + CollectionAssert.IsNotEmpty(differences); + Assert.AreEqual(2, differences.Count); + + Assert.AreEqual("EnumerableOfB", differences.First().MemberPath); + Assert.AreEqual(DifferenceTypes.NumberOfElementsMismatch, differences.First().DifferenceType); + Assert.AreEqual("1", differences.First().Value1); + Assert.AreEqual("0", differences.First().Value2); + + Assert.AreEqual("EnumerableOfB[1]", differences[1].MemberPath); + Assert.AreEqual(DifferenceTypes.MissedElementInSecondObject, differences[1].DifferenceType); + Assert.AreEqual("ObjectsComparer.Tests.TestClasses.B", differences[1].Value1); + Assert.AreEqual("", differences[1].Value2); + } [Test] public void HashSetEqualitySameOrder() diff --git a/ObjectsComparer/ObjectsComparer.Tests/Comparer_MultidimensionalArraysTests.cs b/ObjectsComparer/ObjectsComparer.Tests/Comparer_MultidimensionalArraysTests.cs index b498c3f..3d629c9 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/Comparer_MultidimensionalArraysTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/Comparer_MultidimensionalArraysTests.cs @@ -25,6 +25,35 @@ public void IntOfIntInequality1() Assert.AreEqual("3", differences[0].Value2); } + [Test] + public void IntOfIntInequality1_CompareByKey() + { + //??? + var a1 = new MultidimensionalArrays { IntOfInt = new[] { new[] { 1, 3 } } }; + var a2 = new MultidimensionalArrays { IntOfInt = new[] { new[] { 3, 1 } } }; + + var settings = new ComparisonSettings(); + settings.List.Configure((ctx, listOptions) => + { + if (ctx.Member?.Name == "IntOfInt") + { + + } + else + { + listOptions.CompareElementsByKey(); + } + }); + + var comparer = new Comparer(settings); + + var isEqual = comparer.Compare(a1, a2, out var differencesEnum); + var differences = differencesEnum.ToList(); + + Assert.IsTrue(isEqual); + CollectionAssert.IsEmpty(differences); + } + [Test] public void IntOfIntInequality2() { diff --git a/ObjectsComparer/ObjectsComparer/CompareElementsByKeyOptions.cs b/ObjectsComparer/ObjectsComparer/CompareElementsByKeyOptions.cs index 3d639f5..90d6f71 100644 --- a/ObjectsComparer/ObjectsComparer/CompareElementsByKeyOptions.cs +++ b/ObjectsComparer/ObjectsComparer/CompareElementsByKeyOptions.cs @@ -151,6 +151,11 @@ internal string GetFormattedElementKey(int elementIndex, object elementKey, obje throw new ArgumentNullException(nameof(elementKey)); } + if (element is null) + { + throw new ArgumentNullException(nameof(element)); + } + var formattedKey = ElementKeyFormatter?.Invoke(elementIndex, elementKey, element); if (string.IsNullOrWhiteSpace(formattedKey)) @@ -183,6 +188,11 @@ internal string GetNullElementIdentifier(int elementIndex) /// Parameter: Element key. Return value: Formatted element key. public void FormatElementKey(Func formatter) { + if (formatter is null) + { + throw new ArgumentNullException(nameof(formatter)); + } + FormatElementKey((elementIndex, elementKey, element) => formatter(elementKey)); } @@ -192,6 +202,11 @@ public void FormatElementKey(Func formatter) /// First parameter: Element index. Second parameter: Element key. Return value: Formatted element key. public void FormatElementKey(Func formatter) { + if (formatter is null) + { + throw new ArgumentNullException(nameof(formatter)); + } + FormatElementKey((elementIndex, elementKey, element) => formatter(elementIndex, elementKey)); } diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparerBase.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparerBase.cs index b62cdbf..89e42a0 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparerBase.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparerBase.cs @@ -36,7 +36,7 @@ protected virtual IEnumerable CalculateDifferences(IList list1 ///
protected virtual IEnumerable CalculateDifferencesByKey(IList array1, IList array2, ComparisonContext listComparisonContext, ListConfigurationOptions listConfigurationOptions) { - Debug.WriteLine($"{nameof(CalculateDifferencesByKey)}: {array1?.GetType().Name}"); + Debug.WriteLine($"{GetType().Name}.{nameof(CalculateDifferencesByKey)}: {array1?.GetType().Name}"); var keyOptions = CompareElementsByKeyOptions.Default(); listConfigurationOptions.KeyOptionsAction?.Invoke(keyOptions); @@ -134,7 +134,7 @@ protected virtual IEnumerable CalculateDifferencesByKey(IList /// protected virtual IEnumerable CalculateDifferencesByIndex(IList array1, IList array2, ComparisonContext listComparisonContext) { - Debug.WriteLine($"{nameof(CalculateDifferencesByIndex)}: {array1?.GetType().Name}"); + Debug.WriteLine($"{GetType().Name}.{nameof(CalculateDifferencesByIndex)}: {array1?.GetType().Name}"); int array1Count = array1.Count(); int array2Count = array2.Count(); From fed394176621b73e5958ba3a85ac4df6019e788a Mon Sep 17 00:00:00 2001 From: "ASD\\nemec" Date: Fri, 5 Nov 2021 13:59:09 +0100 Subject: [PATCH 051/181] Add additional test methods. --- .../Comparer_GenericEnumerableTests.cs | 116 ++++++++++++++++++ 1 file changed, 116 insertions(+) diff --git a/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs b/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs index efde44a..1dcbe2e 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs @@ -1069,6 +1069,105 @@ public void CompareAsIList() Assert.AreEqual("1", differences.First().Value2); } + [Test] + public void CompareAsIList_CompareUnequalLists() + { + var list1 = new List { 1, 2 }; + var list2 = new List { 1 }; + + var settings = new ComparisonSettings(); + settings.List.Configure(listOptions => listOptions.CompareUnequalLists = true); + + var comparer = new Comparer>(settings); + + var differences = comparer.CalculateDifferences(list1, list2).ToList(); + + Assert.AreEqual(2, differences.Count); + + Assert.AreEqual(DifferenceTypes.NumberOfElementsMismatch, differences.First().DifferenceType); + Assert.AreEqual("2", differences.First().Value1); + Assert.AreEqual("1", differences.First().Value2); + + Assert.AreEqual(DifferenceTypes.MissedElementInSecondObject, differences[1].DifferenceType); + Assert.AreEqual("[1]", differences[1].MemberPath); + Assert.AreEqual("2", differences[1].Value1); + Assert.AreEqual(string.Empty, differences[1].Value2); + } + + [Test] + public void CompareAsIList_CompareUnequalLists_CompareElementsByKey() + { + var list1 = new List { 1, 2 }; + var list2 = new List { 1 }; + + var settings = new ComparisonSettings(); + settings.List.Configure(listOptions => + { + listOptions.CompareUnequalLists = true; + listOptions.CompareElementsByKey(); + }); + + var comparer = new Comparer>(settings); + + var differences = comparer.CalculateDifferences(list1, list2).ToList(); + + Assert.AreEqual(2, differences.Count); + + Assert.AreEqual(DifferenceTypes.NumberOfElementsMismatch, differences.First().DifferenceType); + Assert.AreEqual("2", differences.First().Value1); + Assert.AreEqual("1", differences.First().Value2); + + Assert.AreEqual(DifferenceTypes.MissedElementInSecondObject, differences[1].DifferenceType); + Assert.AreEqual("[2]", differences[1].MemberPath); + Assert.AreEqual("2", differences[1].Value1); + Assert.AreEqual(string.Empty, differences[1].Value2); + } + + [Test] + public void CompareAsIList_CompareUnequalLists_CompareElementsByKey_FormatKey() + { + var list1 = new List { 1, 2 }; + var list2 = new List { 1 }; + + var settings = new ComparisonSettings(); + settings.List.Configure(listOptions => + { + //DaN Fluent. + //listOptions.CompareUnequalLists().CompareElementsByKey(keyOptions => keyOptions.FormatElementKey(elementKey => $"Key={elementKey}")); + + /* + * listOptions + * .CompareUnequalLists() + * .CompareElementsByKey(keyOptions => keyOptions.FormatElementKey(elementKey => $"Key={elementKey}")); + */ + + listOptions.CompareUnequalLists = true; + + listOptions.CompareElementsByKey(keyOptions => + { + keyOptions.FormatElementKey(elementKey => + { + return $"Key={elementKey}"; + }); + }); + }); + + var comparer = new Comparer>(settings); + + var differences = comparer.CalculateDifferences(list1, list2).ToList(); + + Assert.AreEqual(2, differences.Count); + + Assert.AreEqual(DifferenceTypes.NumberOfElementsMismatch, differences.First().DifferenceType); + Assert.AreEqual("2", differences.First().Value1); + Assert.AreEqual("1", differences.First().Value2); + + Assert.AreEqual(DifferenceTypes.MissedElementInSecondObject, differences[1].DifferenceType); + Assert.AreEqual("[Key=2]", differences[1].MemberPath); + Assert.AreEqual("2", differences[1].Value1); + Assert.AreEqual(string.Empty, differences[1].Value2); + } + [Test] public void DictionaryEqualitySameOrder() { @@ -1081,6 +1180,23 @@ public void DictionaryEqualitySameOrder() Assert.IsTrue(isEqual); } + [Test] + public void DictionaryEqualitySameOrder_CompareByKey() + { + var a1 = new Dictionary { { 1, "One" }, { 2, "TwoXXX" } }; + var a2 = new Dictionary { { 1, "One" }, { 2, "Two" } }; + + var settings = new ComparisonSettings(); + settings.List.Configure(listOptions => listOptions.CompareElementsByKey()); + + var comparer = new Comparer>(settings); + + var isEqual = comparer.Compare(a1, a2, out var differences); + var diffs = differences.ToArray(); + + Assert.IsTrue(isEqual); + } + [Test] public void DictionaryInequalityDifferentOrder() { From 14fc9a7ce196b9beb71facfcd5ca7593e35a1430 Mon Sep 17 00:00:00 2001 From: Daniel Nemec Date: Sat, 6 Nov 2021 11:25:17 +0100 Subject: [PATCH 052/181] Add IntOfIntInequality1_CompareByKey() test method. --- .../Comparer_MultidimensionalArraysTests.cs | 33 ++++++++++++++----- .../CustomComparers/EnumerablesComparer.cs | 2 ++ .../CustomComparers/EnumerablesComparer~1.cs | 3 ++ 3 files changed, 29 insertions(+), 9 deletions(-) diff --git a/ObjectsComparer/ObjectsComparer.Tests/Comparer_MultidimensionalArraysTests.cs b/ObjectsComparer/ObjectsComparer.Tests/Comparer_MultidimensionalArraysTests.cs index 3d629c9..2024319 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/Comparer_MultidimensionalArraysTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/Comparer_MultidimensionalArraysTests.cs @@ -33,16 +33,31 @@ public void IntOfIntInequality1_CompareByKey() var a2 = new MultidimensionalArrays { IntOfInt = new[] { new[] { 3, 1 } } }; var settings = new ComparisonSettings(); - settings.List.Configure((ctx, listOptions) => + + settings.List.Configure((ctx, listOptions) => { - if (ctx.Member?.Name == "IntOfInt") - { - - } - else - { - listOptions.CompareElementsByKey(); - } + listOptions.CompareElementsByKey( + keyOptions => + { + keyOptions.FormatElementKey(element => + { + if (ctx.Ancestor == null) + { + return "a"; + } + + return "b"; + }); + + if (ctx.Member.Name == "IntOfInt") + { + keyOptions.UseKey(element => ""); + } + else + { + keyOptions.UseKey("Key"); + } + }); }); var comparer = new Comparer(settings); diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs index abc31c4..ebcfb72 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs @@ -22,6 +22,8 @@ public override IEnumerable CalculateDifferences(Type type, object o public IEnumerable CalculateDifferences(Type type, object obj1, object obj2, ComparisonContext listComparisonContext) { + Debug.WriteLine($"{GetType().Name}.{nameof(CalculateDifferences)}: {type.Name}"); + if (listComparisonContext is null) { throw new ArgumentNullException(nameof(listComparisonContext)); diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer~1.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer~1.cs index 37c7caf..7e6944c 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer~1.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer~1.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; using System.Reflection; using ObjectsComparer.Utils; @@ -22,6 +23,8 @@ public override IEnumerable CalculateDifferences(Type type, object o public IEnumerable CalculateDifferences(Type type, object obj1, object obj2, ComparisonContext listComparisonContext) { + Debug.WriteLine($"{GetType().Name}.{nameof(CalculateDifferences)}: {type.Name}"); + if (listComparisonContext is null) { throw new ArgumentNullException(nameof(listComparisonContext)); From 2fb606f9b87d4b6e1a47523b86f5eee795e5f7fe Mon Sep 17 00:00:00 2001 From: Daniel Nemec Date: Sat, 6 Nov 2021 12:35:53 +0100 Subject: [PATCH 053/181] Replace overloaded Func arguments with FormatListElementKeyArgs. --- .../Comparer_GenericEnumerableTests.cs | 8 +-- .../Comparer_MultidimensionalArraysTests.cs | 2 +- .../Comparer_NonGenericEnumerableTests.cs | 8 +-- .../CompareElementsByKeyOptions.cs | 53 ++++--------------- .../EnumerablesComparerBase.cs | 4 +- .../FormatListElementKeyArgs.cs | 23 ++++++++ 6 files changed, 44 insertions(+), 54 deletions(-) create mode 100644 ObjectsComparer/ObjectsComparer/FormatListElementKeyArgs.cs diff --git a/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs b/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs index 1dcbe2e..dcb3b25 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs @@ -144,7 +144,7 @@ public void PrimitiveTypeArrayInequalityMember_CompareByKey_FormatKey() var settings = new ComparisonSettings(); settings.List.Configure(listOptions => { - listOptions.CompareElementsByKey(keyOptions => keyOptions.FormatElementKey(elementKey => $"Key={elementKey}")); + listOptions.CompareElementsByKey(keyOptions => keyOptions.FormatElementKey(args => $"Key={args.ElementKey}")); }); var comparer = new Comparer(settings); @@ -396,7 +396,7 @@ public void ClassArrayInequalityProperty_CompareByKey_FormatKey() var a2 = new A { ArrayOfB = new[] { new B { Property1 = "Str1", Id = 1 }, new B { Property1 = "Str3", Id = 2 } } }; var settings = new ComparisonSettings(); - settings.List.Configure(listOptions => listOptions.CompareElementsByKey(keyOptions => keyOptions.FormatElementKey(elementKey => $"Id={elementKey}"))); + settings.List.Configure(listOptions => listOptions.CompareElementsByKey(keyOptions => keyOptions.FormatElementKey(args => $"Id={args.ElementKey}"))); var comparer = new Comparer(settings); @@ -1145,9 +1145,9 @@ public void CompareAsIList_CompareUnequalLists_CompareElementsByKey_FormatKey() listOptions.CompareElementsByKey(keyOptions => { - keyOptions.FormatElementKey(elementKey => + keyOptions.FormatElementKey(args => { - return $"Key={elementKey}"; + return $"Key={args.ElementKey}"; }); }); }); diff --git a/ObjectsComparer/ObjectsComparer.Tests/Comparer_MultidimensionalArraysTests.cs b/ObjectsComparer/ObjectsComparer.Tests/Comparer_MultidimensionalArraysTests.cs index 2024319..6a521a8 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/Comparer_MultidimensionalArraysTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/Comparer_MultidimensionalArraysTests.cs @@ -39,7 +39,7 @@ public void IntOfIntInequality1_CompareByKey() listOptions.CompareElementsByKey( keyOptions => { - keyOptions.FormatElementKey(element => + keyOptions.FormatElementKey(args => { if (ctx.Ancestor == null) { diff --git a/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs b/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs index 0992843..797ffe2 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs @@ -94,7 +94,7 @@ public void InequalityCount_CompareUnequalLists_CompareByKey() listOptions.CompareElementsByKey(keyOptions => { keyOptions.UseKey("Property1"); - keyOptions.FormatElementKey((elementIndex, elementKey) => $"Property1={elementKey}"); + keyOptions.FormatElementKey(args => $"Property1={args.ElementKey}"); }); }); var comparer = new Comparer(settings); @@ -284,9 +284,9 @@ public void NullAndNotNullElementsInequality_CompareByKey() Assert.AreEqual(string.Empty, differences[0].Value2); Assert.AreEqual(DifferenceTypes.MissedElementInFirstObject, differences[1].DifferenceType); - Assert.AreEqual("NonGenericEnumerable[Str2]", differences[0].MemberPath); - Assert.AreEqual(string.Empty, differences[0].Value1); - Assert.AreEqual("Str2", differences[0].Value2); + Assert.AreEqual("NonGenericEnumerable[Str2]", differences[1].MemberPath); + Assert.AreEqual(string.Empty, differences[1].Value1); + Assert.AreEqual("Str2", differences[1].Value2); } [Test] diff --git a/ObjectsComparer/ObjectsComparer/CompareElementsByKeyOptions.cs b/ObjectsComparer/ObjectsComparer/CompareElementsByKeyOptions.cs index 90d6f71..2fd3b7d 100644 --- a/ObjectsComparer/ObjectsComparer/CompareElementsByKeyOptions.cs +++ b/ObjectsComparer/ObjectsComparer/CompareElementsByKeyOptions.cs @@ -7,6 +7,7 @@ namespace ObjectsComparer { + /// /// Configures the behavior of list elements if elements are to be compared by key. /// @@ -35,7 +36,7 @@ public class CompareElementsByKeyOptions /// /// See . /// - Func ElementKeyFormatter { get; set; } + Func ElementKeyFormatter { get; set; } /// /// See . @@ -142,25 +143,20 @@ static object GetKeyValue(object instance, bool caseSensitive, params string[] k } /// - /// Returns optional formatted or unformatted . See . + /// Returns optional formatted or unformatted . See /// - internal string GetFormattedElementKey(int elementIndex, object elementKey, object element) + internal string GetFormattedElementKey(FormatListElementKeyArgs formatElementKeyArgs) { - if (elementKey is null) - { - throw new ArgumentNullException(nameof(elementKey)); - } - - if (element is null) + if (formatElementKeyArgs is null) { - throw new ArgumentNullException(nameof(element)); + throw new ArgumentNullException(nameof(formatElementKeyArgs)); } - var formattedKey = ElementKeyFormatter?.Invoke(elementIndex, elementKey, element); + var formattedKey = ElementKeyFormatter?.Invoke(formatElementKeyArgs); if (string.IsNullOrWhiteSpace(formattedKey)) { - formattedKey = elementKey.ToString(); + formattedKey = formatElementKeyArgs.ElementKey.ToString(); } return formattedKey.Left(FormattedKeyMaxLength); @@ -182,42 +178,13 @@ internal string GetNullElementIdentifier(int elementIndex) return elementIdentifier.Left(NullElementIdentifierMaxLength); } - /// - /// Formats element key. For more info, see . - /// - /// Parameter: Element key. Return value: Formatted element key. - public void FormatElementKey(Func formatter) - { - if (formatter is null) - { - throw new ArgumentNullException(nameof(formatter)); - } - - FormatElementKey((elementIndex, elementKey, element) => formatter(elementKey)); - } - - /// - /// Formats element key. For more info, see . - /// - /// First parameter: Element index. Second parameter: Element key. Return value: Formatted element key. - public void FormatElementKey(Func formatter) - { - if (formatter is null) - { - throw new ArgumentNullException(nameof(formatter)); - } - - FormatElementKey((elementIndex, elementKey, element) => formatter(elementIndex, elementKey)); - } - /// /// To avoid possible confusion of the element key with the element index, the element key can be formatted with any text.
/// For example, element key with value = 1 can be formatted as "Id=1". - /// The formatted element key is then used as part of the property, e.g. "Addresses[Id=1]".
+ /// The formatted element key is then used as part of the property, e.g. "Addresses[Id=1]" instead of "Addresses[1]".
/// By default the element key is not formatted. ///
- /// First parameter: Element index. Second parameter: Element key. Third parameter: Element. Return value: Formatted element key. - public void FormatElementKey(Func formatter) + public void FormatElementKey(Func formatter) { if (formatter is null) { diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparerBase.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparerBase.cs index 89e42a0..2ee2da7 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparerBase.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparerBase.cs @@ -71,7 +71,7 @@ protected virtual IEnumerable CalculateDifferencesByKey(IList continue; } - var formattedElement1Key = keyOptions.GetFormattedElementKey(element1Index, element1Key, element1); + var formattedElement1Key = keyOptions.GetFormattedElementKey(new FormatListElementKeyArgs(element1Index, element1Key, element1)); if (array2.Any(elm2 => object.Equals(element1Key, keyOptions.KeyProvider(elm2)))) { @@ -122,7 +122,7 @@ protected virtual IEnumerable CalculateDifferencesByKey(IList if (array1.Any(elm1 => object.Equals(element2Key, keyOptions.KeyProvider(elm1))) == false) { - var formattedElement2Key = keyOptions.GetFormattedElementKey(element2Index, element2Key, element2); + var formattedElement2Key = keyOptions.GetFormattedElementKey(new FormatListElementKeyArgs(element2Index, element2Key, element2)); var valueComparer2 = OverridesCollection.GetComparer(element2.GetType()) ?? DefaultValueComparer; yield return AddDifferenceToComparisonContext(new Difference($"[{formattedElement2Key}]", string.Empty, valueComparer2.ToString(element2), DifferenceTypes.MissedElementInFirstObject), elementComparisonContext); } diff --git a/ObjectsComparer/ObjectsComparer/FormatListElementKeyArgs.cs b/ObjectsComparer/ObjectsComparer/FormatListElementKeyArgs.cs new file mode 100644 index 0000000..0647100 --- /dev/null +++ b/ObjectsComparer/ObjectsComparer/FormatListElementKeyArgs.cs @@ -0,0 +1,23 @@ +using System; + +namespace ObjectsComparer +{ + /// + /// Useful arguments for list element key formatter, see . + /// + public class FormatListElementKeyArgs + { + internal FormatListElementKeyArgs(int elementIndex, object elementKey, object element) + { + ElementIndex = elementIndex; + ElementKey = elementKey ?? throw new ArgumentNullException(nameof(elementKey)); + Element = element ?? throw new ArgumentNullException(nameof(element)); + } + + public int ElementIndex { get; } + + public object ElementKey { get; } + + public object Element { get; } + } +} From a45108166f2cd98f4893425f4d60740dfba9bc75 Mon Sep 17 00:00:00 2001 From: Daniel Nemec Date: Sat, 6 Nov 2021 12:43:53 +0100 Subject: [PATCH 054/181] Rename CompareElementsByKeyOptions >CompareListElementsByKeyOptions class. --- .../ObjectsComparer.Tests/ComparisonSettingsTests.cs | 2 +- ...yKeyOptions.cs => CompareListElementsByKeyOptions.cs} | 9 ++++----- .../CustomComparers/EnumerablesComparerBase.cs | 2 +- .../Exceptions/ElementKeyNotFoundException.cs | 2 +- .../ObjectsComparer/FormatListElementKeyArgs.cs | 2 +- .../ObjectsComparer/ListConfigurationOptions.cs | 4 ++-- 6 files changed, 10 insertions(+), 11 deletions(-) rename ObjectsComparer/ObjectsComparer/{CompareElementsByKeyOptions.cs => CompareListElementsByKeyOptions.cs} (96%) diff --git a/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs b/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs index e52fcf4..5d96663 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs @@ -76,7 +76,7 @@ public void CompareListElementsByKeyIsCorrectlySet() var listConfigurationOptions = ListConfigurationOptions.Default(); var ctx = ComparisonContext.Create(); settings.List.ConfigureOptionsAction(ctx, listConfigurationOptions); - var compareElementsByKeyOptions = CompareElementsByKeyOptions.Default(); + var compareElementsByKeyOptions = CompareListElementsByKeyOptions.Default(); listConfigurationOptions.KeyOptionsAction(compareElementsByKeyOptions); Assert.AreEqual(true, listConfigurationOptions.CompareUnequalLists); diff --git a/ObjectsComparer/ObjectsComparer/CompareElementsByKeyOptions.cs b/ObjectsComparer/ObjectsComparer/CompareListElementsByKeyOptions.cs similarity index 96% rename from ObjectsComparer/ObjectsComparer/CompareElementsByKeyOptions.cs rename to ObjectsComparer/ObjectsComparer/CompareListElementsByKeyOptions.cs index 2fd3b7d..6970656 100644 --- a/ObjectsComparer/ObjectsComparer/CompareElementsByKeyOptions.cs +++ b/ObjectsComparer/ObjectsComparer/CompareListElementsByKeyOptions.cs @@ -7,11 +7,10 @@ namespace ObjectsComparer { - /// - /// Configures the behavior of list elements if elements are to be compared by key. + /// Configures the behavior of list elements if list elements are to be compared by key. /// - public class CompareElementsByKeyOptions + public class CompareListElementsByKeyOptions { /// /// Default element identifier template for element that refers to null value. See for more info. @@ -28,7 +27,7 @@ public class CompareElementsByKeyOptions /// const int NullElementIdentifierMaxLength = 20; - CompareElementsByKeyOptions() + CompareListElementsByKeyOptions() { Initialize(); } @@ -55,7 +54,7 @@ public class CompareElementsByKeyOptions ///
internal Func KeyProvider { get; private set; } = null; - internal static CompareElementsByKeyOptions Default() => new CompareElementsByKeyOptions(); + internal static CompareListElementsByKeyOptions Default() => new CompareListElementsByKeyOptions(); void Initialize() { diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparerBase.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparerBase.cs index 2ee2da7..483319d 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparerBase.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparerBase.cs @@ -38,7 +38,7 @@ protected virtual IEnumerable CalculateDifferencesByKey(IList { Debug.WriteLine($"{GetType().Name}.{nameof(CalculateDifferencesByKey)}: {array1?.GetType().Name}"); - var keyOptions = CompareElementsByKeyOptions.Default(); + var keyOptions = CompareListElementsByKeyOptions.Default(); listConfigurationOptions.KeyOptionsAction?.Invoke(keyOptions); for (int element1Index = 0; element1Index < array1.Count(); element1Index++) diff --git a/ObjectsComparer/ObjectsComparer/Exceptions/ElementKeyNotFoundException.cs b/ObjectsComparer/ObjectsComparer/Exceptions/ElementKeyNotFoundException.cs index 9b0681e..cc33b52 100644 --- a/ObjectsComparer/ObjectsComparer/Exceptions/ElementKeyNotFoundException.cs +++ b/ObjectsComparer/ObjectsComparer/Exceptions/ElementKeyNotFoundException.cs @@ -5,7 +5,7 @@ namespace ObjectsComparer.Exceptions { /// - /// Depending on the configuration, the exception is thrown if the key provider does not supply the key for list element . For more information see and . + /// Depending on the configuration, the exception is thrown if the key provider does not supply the key for list element . For more information see and . /// public class ElementKeyNotFoundException : Exception { diff --git a/ObjectsComparer/ObjectsComparer/FormatListElementKeyArgs.cs b/ObjectsComparer/ObjectsComparer/FormatListElementKeyArgs.cs index 0647100..075e3f6 100644 --- a/ObjectsComparer/ObjectsComparer/FormatListElementKeyArgs.cs +++ b/ObjectsComparer/ObjectsComparer/FormatListElementKeyArgs.cs @@ -3,7 +3,7 @@ namespace ObjectsComparer { /// - /// Useful arguments for list element key formatter, see . + /// Useful arguments for list element key formatter, see . /// public class FormatListElementKeyArgs { diff --git a/ObjectsComparer/ObjectsComparer/ListConfigurationOptions.cs b/ObjectsComparer/ObjectsComparer/ListConfigurationOptions.cs index d224e89..238ff4c 100644 --- a/ObjectsComparer/ObjectsComparer/ListConfigurationOptions.cs +++ b/ObjectsComparer/ObjectsComparer/ListConfigurationOptions.cs @@ -30,7 +30,7 @@ public void CompareElementsByIndex() KeyOptionsAction = null; } - internal Action KeyOptionsAction { get; private set; } + internal Action KeyOptionsAction { get; private set; } /// /// Compares list elements by key. @@ -43,7 +43,7 @@ public void CompareElementsByKey() /// /// Compares list elements by key. /// - public void CompareElementsByKey(Action keyOptions) + public void CompareElementsByKey(Action keyOptions) { if (keyOptions is null) { From 2f18753f81ff415c23cd33408c7077fa94a2f263 Mon Sep 17 00:00:00 2001 From: Daniel Nemec Date: Sun, 7 Nov 2021 17:32:16 +0100 Subject: [PATCH 055/181] Replace UseKey(Func keyProvider) with UseKey(Func keyProvider) --- .../Comparer_MultidimensionalArraysTests.cs | 35 ++++++++++++++----- .../CompareListElementsByKeyOptions.cs | 8 ++--- .../EnumerablesComparerBase.cs | 10 +++--- .../Exceptions/ElementKeyNotFoundException.cs | 2 +- .../ObjectsComparer/ListComparisonSettings.cs | 5 +-- .../ListElementKeyProviderArgs.cs | 22 ++++++++++++ 6 files changed, 62 insertions(+), 20 deletions(-) create mode 100644 ObjectsComparer/ObjectsComparer/ListElementKeyProviderArgs.cs diff --git a/ObjectsComparer/ObjectsComparer.Tests/Comparer_MultidimensionalArraysTests.cs b/ObjectsComparer/ObjectsComparer.Tests/Comparer_MultidimensionalArraysTests.cs index 6a521a8..27f9075 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/Comparer_MultidimensionalArraysTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/Comparer_MultidimensionalArraysTests.cs @@ -1,4 +1,5 @@ -using System.Linq; +using System; +using System.Linq; using NUnit.Framework; using ObjectsComparer.Tests.TestClasses; @@ -13,7 +14,6 @@ public void IntOfIntInequality1() var a1 = new MultidimensionalArrays { IntOfInt = new[] { new[] { 1, 2 } } }; var a2 = new MultidimensionalArrays { IntOfInt = new[] { new[] { 1, 3 } } }; var comparer = new Comparer(); - var isEqual = comparer.Compare(a1, a2, out var differencesEnum); var differences = differencesEnum.ToList(); @@ -28,30 +28,49 @@ public void IntOfIntInequality1() [Test] public void IntOfIntInequality1_CompareByKey() { + var a = new A { ListOfB = new System.Collections.Generic.List { new B { Property1 = "p" } } }; + var test = a.ListOfB.Where(b => + { + a.ListOfB.Add(new B { }); + return true; + }).ToArray(); + //??? var a1 = new MultidimensionalArrays { IntOfInt = new[] { new[] { 1, 3 } } }; var a2 = new MultidimensionalArrays { IntOfInt = new[] { new[] { 3, 1 } } }; var settings = new ComparisonSettings(); - settings.List.Configure((ctx, listOptions) => + settings.List.Configure(listOptions => listOptions.CompareElementsByKey()); + + settings.List.Configure((listCtx, listOptions) => { listOptions.CompareElementsByKey( keyOptions => { - keyOptions.FormatElementKey(args => + keyOptions.UseKey("MyId"); + + keyOptions.FormatElementKey(formatElementKeyArgs => { - if (ctx.Ancestor == null) + if (listCtx.Ancestor == null) { - return "a"; + return $"Key={formatElementKeyArgs.ElementKey}"; } return "b"; }); - if (ctx.Member.Name == "IntOfInt") + if (listCtx.Member.Name == "IntOfInt") { - keyOptions.UseKey(element => ""); + keyOptions.UseKey(keyProviderArgs => + { + if (true) + { + //return keyProviderArgs.DefaulKeyProvider(keyProviderArgs.Element); + } + var c = listCtx; + return "1"; + }); } else { diff --git a/ObjectsComparer/ObjectsComparer/CompareListElementsByKeyOptions.cs b/ObjectsComparer/ObjectsComparer/CompareListElementsByKeyOptions.cs index 6970656..8f0a7b7 100644 --- a/ObjectsComparer/ObjectsComparer/CompareListElementsByKeyOptions.cs +++ b/ObjectsComparer/ObjectsComparer/CompareListElementsByKeyOptions.cs @@ -50,9 +50,9 @@ public class CompareListElementsByKeyOptions public bool ThrowKeyNotFound { get; set; } = true; /// - /// If null, the elements should be compared by their index, otherwise by key. Default value = null. + /// See . /// - internal Func KeyProvider { get; private set; } = null; + internal Func KeyProviderAction { get; private set; } = null; internal static CompareListElementsByKeyOptions Default() => new CompareListElementsByKeyOptions(); @@ -104,14 +104,14 @@ public void UseKey(string[] keys, bool caseSensitive = false) /// Key identification. It attempts to find the key using the parameter. /// /// First parameter: The element whose key is required. Return value: The element's key. - public void UseKey(Func keyProvider) + public void UseKey(Func keyProvider) { if (keyProvider is null) { throw new ArgumentNullException(nameof(keyProvider)); } - KeyProvider = keyProvider; + KeyProviderAction = keyProvider; } /// diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparerBase.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparerBase.cs index 483319d..57096e6 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparerBase.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparerBase.cs @@ -59,7 +59,7 @@ protected virtual IEnumerable CalculateDifferencesByKey(IList continue; } - var element1Key = keyOptions.KeyProvider(element1); + var element1Key = keyOptions.KeyProviderAction(new ListElementKeyProviderArgs(element1)); if (element1Key == null) { @@ -73,9 +73,9 @@ protected virtual IEnumerable CalculateDifferencesByKey(IList var formattedElement1Key = keyOptions.GetFormattedElementKey(new FormatListElementKeyArgs(element1Index, element1Key, element1)); - if (array2.Any(elm2 => object.Equals(element1Key, keyOptions.KeyProvider(elm2)))) + if (array2.Any(elm2 => object.Equals(element1Key, keyOptions.KeyProviderAction(new ListElementKeyProviderArgs(elm2))))) { - var element2 = array2.First(elm2 => object.Equals(element1Key, keyOptions.KeyProvider(elm2))); + var element2 = array2.First(elm2 => object.Equals(element1Key, keyOptions.KeyProviderAction(new ListElementKeyProviderArgs(elm2)))); var comparer = Factory.GetObjectsComparer(element1.GetType(), Settings, this); foreach (var failure in comparer.CalculateDifferences(element1.GetType(), element1, element2, elementComparisonContext)) @@ -108,7 +108,7 @@ protected virtual IEnumerable CalculateDifferencesByKey(IList continue; } - var element2Key = keyOptions.KeyProvider(element2); + var element2Key = keyOptions.KeyProviderAction(new ListElementKeyProviderArgs(element2)); if (element2Key == null) { @@ -120,7 +120,7 @@ protected virtual IEnumerable CalculateDifferencesByKey(IList continue; } - if (array1.Any(elm1 => object.Equals(element2Key, keyOptions.KeyProvider(elm1))) == false) + if (array1.Any(elm1 => object.Equals(element2Key, keyOptions.KeyProviderAction(new ListElementKeyProviderArgs(elm1)))) == false) { var formattedElement2Key = keyOptions.GetFormattedElementKey(new FormatListElementKeyArgs(element2Index, element2Key, element2)); var valueComparer2 = OverridesCollection.GetComparer(element2.GetType()) ?? DefaultValueComparer; diff --git a/ObjectsComparer/ObjectsComparer/Exceptions/ElementKeyNotFoundException.cs b/ObjectsComparer/ObjectsComparer/Exceptions/ElementKeyNotFoundException.cs index cc33b52..a246e0e 100644 --- a/ObjectsComparer/ObjectsComparer/Exceptions/ElementKeyNotFoundException.cs +++ b/ObjectsComparer/ObjectsComparer/Exceptions/ElementKeyNotFoundException.cs @@ -5,7 +5,7 @@ namespace ObjectsComparer.Exceptions { /// - /// Depending on the configuration, the exception is thrown if the key provider does not supply the key for list element . For more information see and . + /// Depending on the configuration, the exception is thrown if the key provider does not supply the key for list element . For more information see and . /// public class ElementKeyNotFoundException : Exception { diff --git a/ObjectsComparer/ObjectsComparer/ListComparisonSettings.cs b/ObjectsComparer/ObjectsComparer/ListComparisonSettings.cs index 6b02053..aae63d5 100644 --- a/ObjectsComparer/ObjectsComparer/ListComparisonSettings.cs +++ b/ObjectsComparer/ObjectsComparer/ListComparisonSettings.cs @@ -16,8 +16,9 @@ public class ListComparisonSettings internal static ListComparisonSettings Default() => new ListComparisonSettings(); /// - /// Configures list comparison behavior. + /// Configures list comparison behavior, see . /// + /// First parameter: Current list comparison context. public void Configure(Action configureOptions) { if (configureOptions is null) @@ -29,7 +30,7 @@ public void Configure(Action config } /// - /// Configures list comparison behavior. + /// Configures list comparison behavior, see . /// /// See . public void Configure(Action configureOptions) diff --git a/ObjectsComparer/ObjectsComparer/ListElementKeyProviderArgs.cs b/ObjectsComparer/ObjectsComparer/ListElementKeyProviderArgs.cs new file mode 100644 index 0000000..076587a --- /dev/null +++ b/ObjectsComparer/ObjectsComparer/ListElementKeyProviderArgs.cs @@ -0,0 +1,22 @@ +using System; + +namespace ObjectsComparer +{ + public class ListElementKeyProviderArgs + { + /// + /// + /// + /// The element whose key is required. + public ListElementKeyProviderArgs(object element) + { + Element = element ?? throw new ArgumentNullException(nameof(element)); + } + + /// + /// The element whose key is required. + /// + public object Element { get; } + } + +} From fbb5449a9c6707542b04fd73cb3c94333424881a Mon Sep 17 00:00:00 2001 From: Daniel Nemec Date: Sun, 7 Nov 2021 18:39:12 +0100 Subject: [PATCH 056/181] Edit IntOfIntInequality1_CompareByKey. --- .../Comparer_MultidimensionalArraysTests.cs | 7 +++++++ .../ObjectsComparer/ListConfigurationOptions.cs | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/ObjectsComparer/ObjectsComparer.Tests/Comparer_MultidimensionalArraysTests.cs b/ObjectsComparer/ObjectsComparer.Tests/Comparer_MultidimensionalArraysTests.cs index 27f9075..adcbf79 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/Comparer_MultidimensionalArraysTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/Comparer_MultidimensionalArraysTests.cs @@ -42,9 +42,16 @@ public void IntOfIntInequality1_CompareByKey() var settings = new ComparisonSettings(); settings.List.Configure(listOptions => listOptions.CompareElementsByKey()); + /* + * settings.List.Configure(listOptions => listOptions + * .CompareUnequalLists(true) + * .CompareElementsByKey(keyOptions => keyOptions.UseKey("MyKey"))); + */ settings.List.Configure((listCtx, listOptions) => { + listOptions.CompareUnequalLists = true; + listOptions.CompareElementsByKey( keyOptions => { diff --git a/ObjectsComparer/ObjectsComparer/ListConfigurationOptions.cs b/ObjectsComparer/ObjectsComparer/ListConfigurationOptions.cs index 238ff4c..0772e48 100644 --- a/ObjectsComparer/ObjectsComparer/ListConfigurationOptions.cs +++ b/ObjectsComparer/ObjectsComparer/ListConfigurationOptions.cs @@ -16,7 +16,7 @@ public class ListConfigurationOptions } /// - /// Whether to compare elements of the lists even if their number differs. Regardless of the value, respective difference of type will always be logged. Default value = false. + /// Whether to compare elements of the lists even if their number differs. Regardless of the value, the respective difference of type will always be logged. Default value = false. /// public bool CompareUnequalLists { get; set; } = false; From 4c2d9826ccf35c731606001aa6a724c46c3846fb Mon Sep 17 00:00:00 2001 From: "ASD\\nemec" Date: Mon, 8 Nov 2021 20:01:49 +0100 Subject: [PATCH 057/181] Add fluent API into CompareListElementsByKeyOptions, ListConfigurationOptions. --- .../Comparer_MultidimensionalArraysTests.cs | 24 ++++++++++++++++--- .../CompareListElementsByKeyOptions.cs | 20 ++++++++++------ .../ListConfigurationOptions.cs | 24 +++++++++++++++---- 3 files changed, 53 insertions(+), 15 deletions(-) diff --git a/ObjectsComparer/ObjectsComparer.Tests/Comparer_MultidimensionalArraysTests.cs b/ObjectsComparer/ObjectsComparer.Tests/Comparer_MultidimensionalArraysTests.cs index adcbf79..3d1bbe3 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/Comparer_MultidimensionalArraysTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/Comparer_MultidimensionalArraysTests.cs @@ -41,7 +41,27 @@ public void IntOfIntInequality1_CompareByKey() var settings = new ComparisonSettings(); - settings.List.Configure(listOptions => listOptions.CompareElementsByKey()); + settings.List.Configure((ComparisonContext ctx, ListConfigurationOptions listOptions) => listOptions + .WithUnequalLists(true) + .CompareElementsByKey(keyOptions => + { + if (ctx.Member == null) + { + keyOptions.UseKey(args => args.Element.ToString()); + } + else + { + keyOptions.UseKey(args => $"100{args.Element}"); + } + })); + + settings.List.Configure(listOptions => + { + listOptions + .WithUnequalLists(true) + .CompareElementsByKey(); + }); + /* * settings.List.Configure(listOptions => listOptions * .CompareUnequalLists(true) @@ -50,8 +70,6 @@ public void IntOfIntInequality1_CompareByKey() settings.List.Configure((listCtx, listOptions) => { - listOptions.CompareUnequalLists = true; - listOptions.CompareElementsByKey( keyOptions => { diff --git a/ObjectsComparer/ObjectsComparer/CompareListElementsByKeyOptions.cs b/ObjectsComparer/ObjectsComparer/CompareListElementsByKeyOptions.cs index 8f0a7b7..d9e90a8 100644 --- a/ObjectsComparer/ObjectsComparer/CompareListElementsByKeyOptions.cs +++ b/ObjectsComparer/ObjectsComparer/CompareListElementsByKeyOptions.cs @@ -64,20 +64,20 @@ void Initialize() /// /// Key identification. It attempts to find the key using the property specified by the parameter. /// - public void UseKey(string key, bool caseSensitive = false) + public CompareListElementsByKeyOptions UseKey(string key, bool caseSensitive = false) { if (string.IsNullOrWhiteSpace(key)) { throw new ArgumentException($"'{nameof(key)}' cannot be null or whitespace.", nameof(key)); } - UseKey(new string[] { key }, caseSensitive); + return UseKey(new string[] { key }, caseSensitive); } /// /// Key identification. It attempts to find the key using one of the public properties specified by the parameter, in the specified order. /// - public void UseKey(string[] keys, bool caseSensitive = false) + public CompareListElementsByKeyOptions UseKey(string[] keys, bool caseSensitive = false) { if (keys is null) { @@ -94,7 +94,7 @@ public void UseKey(string[] keys, bool caseSensitive = false) throw new ArgumentException($"'{nameof(keys)}' cannot contain null or whitespace.", nameof(keys)); } - UseKey(element => + return UseKey(element => { return GetKeyValue(element, caseSensitive, keys); }); @@ -104,7 +104,7 @@ public void UseKey(string[] keys, bool caseSensitive = false) /// Key identification. It attempts to find the key using the parameter. /// /// First parameter: The element whose key is required. Return value: The element's key. - public void UseKey(Func keyProvider) + public CompareListElementsByKeyOptions UseKey(Func keyProvider) { if (keyProvider is null) { @@ -112,6 +112,8 @@ public void UseKey(Func keyProvider) } KeyProviderAction = keyProvider; + + return this; } /// @@ -183,7 +185,7 @@ internal string GetNullElementIdentifier(int elementIndex) /// The formatted element key is then used as part of the property, e.g. "Addresses[Id=1]" instead of "Addresses[1]".
/// By default the element key is not formatted. ///
- public void FormatElementKey(Func formatter) + public CompareListElementsByKeyOptions FormatElementKey(Func formatter) { if (formatter is null) { @@ -191,6 +193,8 @@ public void FormatElementKey(Func formatter) } ElementKeyFormatter = formatter; + + return this; } /// @@ -198,7 +202,7 @@ public void FormatElementKey(Func formatter) /// By default, template will be used to format the identifier. /// /// First parameter: Element index. Return value: Formatted identifier. - public void FormatNullElementIdentifier(Func formatter) + public CompareListElementsByKeyOptions FormatNullElementIdentifier(Func formatter) { if (formatter is null) { @@ -206,6 +210,8 @@ public void FormatNullElementIdentifier(Func formatter) } NullElementIdentifierFormatter = formatter; + + return this; } } } diff --git a/ObjectsComparer/ObjectsComparer/ListConfigurationOptions.cs b/ObjectsComparer/ObjectsComparer/ListConfigurationOptions.cs index 0772e48..c68f3fc 100644 --- a/ObjectsComparer/ObjectsComparer/ListConfigurationOptions.cs +++ b/ObjectsComparer/ObjectsComparer/ListConfigurationOptions.cs @@ -18,16 +18,28 @@ public class ListConfigurationOptions /// /// Whether to compare elements of the lists even if their number differs. Regardless of the value, the respective difference of type will always be logged. Default value = false. /// - public bool CompareUnequalLists { get; set; } = false; + internal bool CompareUnequalLists { get; private set; } = false; + + /// + /// Whether to compare elements of the lists even if their number differs. Regardless of the value, the respective difference of type will always be logged. Default value = false. + /// + public ListConfigurationOptions WithUnequalLists(bool value) + { + CompareUnequalLists = value; + + return this; + } internal static ListConfigurationOptions Default() => new ListConfigurationOptions(); /// /// Compares list elements by index. Default behavior. /// - public void CompareElementsByIndex() + public ListConfigurationOptions CompareElementsByIndex() { KeyOptionsAction = null; + + return this; } internal Action KeyOptionsAction { get; private set; } @@ -35,15 +47,15 @@ public void CompareElementsByIndex() /// /// Compares list elements by key. /// - public void CompareElementsByKey() + public ListConfigurationOptions CompareElementsByKey() { - CompareElementsByKey(options => { }); + return CompareElementsByKey(options => { }); } /// /// Compares list elements by key. /// - public void CompareElementsByKey(Action keyOptions) + public ListConfigurationOptions CompareElementsByKey(Action keyOptions) { if (keyOptions is null) { @@ -51,6 +63,8 @@ public void CompareElementsByKey(Action keyOpti } KeyOptionsAction = keyOptions; + + return this; } ///
From 76a3cb654e3de7a3ceb6ce951b162a7fd62400ca Mon Sep 17 00:00:00 2001 From: nemec Date: Mon, 8 Nov 2021 23:09:30 +0100 Subject: [PATCH 058/181] Rename operation WithUnequalLists. Rename operation WithUnequalLists with CompareUnequalLists. Rename property CompareUnequalLists with UnequalListsComparisonEnabled. --- .../Comparer_GenericEnumerableTests.cs | 57 ++++--------------- .../Comparer_MultidimensionalArraysTests.cs | 10 +--- .../Comparer_NonGenericEnumerableTests.cs | 22 +++---- .../ComparisonSettingsTests.cs | 6 +- .../CustomComparers/EnumerablesComparer.cs | 2 +- .../CustomComparers/EnumerablesComparer~1.cs | 2 +- .../ListConfigurationOptions.cs | 10 ++-- 7 files changed, 33 insertions(+), 76 deletions(-) diff --git a/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs b/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs index dcb3b25..a70f3bc 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs @@ -65,10 +65,7 @@ public void PrimitiveTypeArrayInequalityCount_CompareUnequalLists() var a2 = new A { IntArray = new[] { 1, 2, 3 } }; var settings = new ComparisonSettings(); - settings.List.Configure(listOptions => - { - listOptions.CompareUnequalLists = true; - }); + settings.List.Configure(listOptions => listOptions.CompareUnequalLists(true)); var comparer = new Comparer(settings); var rootCtx = ComparisonContext.CreateRoot(); @@ -307,11 +304,7 @@ public void ClassArrayInequalityCount_CompareByKey_DoesNotThrow_ElementKeyNotFou var a2 = new A { ArrayOfB = new[] { new B { Property1 = "Str1" }, new B { Property1 = "Str2" } } }; var settings = new ComparisonSettings(); - settings.List.Configure(listOptions => - { - listOptions.CompareUnequalLists = true; - listOptions.CompareElementsByKey(keyOptions => keyOptions.ThrowKeyNotFound = false); - }); + settings.List.Configure(listOptions => listOptions.CompareUnequalLists(true).CompareElementsByKey(keyOptions => keyOptions.ThrowKeyNotFound = false)); var comparer = new Comparer(settings); @@ -333,10 +326,7 @@ public void ClassArrayInequalityCount_CompareUnequalLists() var a2 = new A { ArrayOfB = new[] { new B { Property1 = "Str1" }, new B { Property1 = "Str2" } } }; var settings = new ComparisonSettings(); - settings.List.Configure(listOptions => - { - listOptions.CompareUnequalLists = true; - }); + settings.List.Configure(listOptions => listOptions.CompareUnequalLists(true)); var comparer = new Comparer(settings); @@ -460,10 +450,7 @@ public void CollectionInequalityCount_CompareUnequalLists() var a2 = new A { CollectionOfB = new Collection { new B { Property1 = "Str1" } } }; var settings = new ComparisonSettings(); - settings.List.Configure(listOptions => - { - listOptions.CompareUnequalLists = true; - }); + settings.List.Configure(listOptions => listOptions.CompareUnequalLists(true)); var comparer = new Comparer(settings); @@ -647,7 +634,7 @@ public void ClassImplementsCollectionInequalityCount_CompareUnequalLists() var a2 = new A { ClassImplementsCollectionOfB = new CollectionOfB { new B { Property1 = "Str1" } } }; var settings = new ComparisonSettings(); - settings.List.Configure(listOptions => listOptions.CompareUnequalLists = true); + settings.List.Configure(listOptions => listOptions.CompareUnequalLists(true)); var comparer = new Comparer(settings); @@ -674,11 +661,7 @@ public void ClassImplementsCollectionInequalityCount_CompareUnequalLists_Compare var a2 = new A { ClassImplementsCollectionOfB = new CollectionOfB { new B { Property1 = "Str1", Id = 1 } } }; var settings = new ComparisonSettings(); - settings.List.Configure(listOptions => - { - listOptions.CompareUnequalLists = true; - listOptions.CompareElementsByKey(); - }); + settings.List.Configure(listOptions => listOptions.CompareUnequalLists(true).CompareElementsByKey()); var comparer = new Comparer(settings); @@ -720,11 +703,7 @@ public void ClassImplementsCollectionInequalityProperty_CompareByKey() var a2 = new A { ClassImplementsCollectionOfB = new CollectionOfB { new B { Property1 = "Str1", Id = 1 }, new B { Property1 = "Str3", Id = 2 } } }; var settings = new ComparisonSettings(); - settings.List.Configure(listOptions => - { - listOptions.CompareUnequalLists = true; - listOptions.CompareElementsByKey(); - }); + settings.List.Configure(listOptions => listOptions.CompareUnequalLists(true).CompareElementsByKey()); var comparer = new Comparer(settings); @@ -866,11 +845,7 @@ public void CollectionOfBCountInequality1_CompareElementsByKey_CompareUnequalLis }; var settings = new ComparisonSettings(); - settings.List.Configure(listOptions => - { - listOptions.CompareUnequalLists = true; - listOptions.CompareElementsByKey(); - }); + settings.List.Configure(listOptions => listOptions.CompareUnequalLists(true).CompareElementsByKey()); var comparer = new Comparer(settings); @@ -930,11 +905,7 @@ public void CollectionOfBCountInequality2_CompareByKey() }; var settings = new ComparisonSettings(); - settings.List.Configure(listOptions => - { - listOptions.CompareUnequalLists = true; - listOptions.CompareElementsByKey(); - }); + settings.List.Configure(listOptions => listOptions.CompareUnequalLists(true).CompareElementsByKey()); var comparer = new Comparer(settings); var isEqual = comparer.Compare(a1, a2, out var differencesEnum); @@ -1076,7 +1047,7 @@ public void CompareAsIList_CompareUnequalLists() var list2 = new List { 1 }; var settings = new ComparisonSettings(); - settings.List.Configure(listOptions => listOptions.CompareUnequalLists = true); + settings.List.Configure(listOptions => listOptions.CompareUnequalLists(true)); var comparer = new Comparer>(settings); @@ -1101,11 +1072,7 @@ public void CompareAsIList_CompareUnequalLists_CompareElementsByKey() var list2 = new List { 1 }; var settings = new ComparisonSettings(); - settings.List.Configure(listOptions => - { - listOptions.CompareUnequalLists = true; - listOptions.CompareElementsByKey(); - }); + settings.List.Configure(listOptions => listOptions.CompareUnequalLists(true).CompareElementsByKey()); var comparer = new Comparer>(settings); @@ -1141,7 +1108,7 @@ public void CompareAsIList_CompareUnequalLists_CompareElementsByKey_FormatKey() * .CompareElementsByKey(keyOptions => keyOptions.FormatElementKey(elementKey => $"Key={elementKey}")); */ - listOptions.CompareUnequalLists = true; + listOptions.CompareUnequalLists(true); listOptions.CompareElementsByKey(keyOptions => { diff --git a/ObjectsComparer/ObjectsComparer.Tests/Comparer_MultidimensionalArraysTests.cs b/ObjectsComparer/ObjectsComparer.Tests/Comparer_MultidimensionalArraysTests.cs index 3d1bbe3..af09078 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/Comparer_MultidimensionalArraysTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/Comparer_MultidimensionalArraysTests.cs @@ -42,7 +42,7 @@ public void IntOfIntInequality1_CompareByKey() var settings = new ComparisonSettings(); settings.List.Configure((ComparisonContext ctx, ListConfigurationOptions listOptions) => listOptions - .WithUnequalLists(true) + .CompareUnequalLists(true) .CompareElementsByKey(keyOptions => { if (ctx.Member == null) @@ -58,16 +58,10 @@ public void IntOfIntInequality1_CompareByKey() settings.List.Configure(listOptions => { listOptions - .WithUnequalLists(true) + .CompareUnequalLists(true) .CompareElementsByKey(); }); - /* - * settings.List.Configure(listOptions => listOptions - * .CompareUnequalLists(true) - * .CompareElementsByKey(keyOptions => keyOptions.UseKey("MyKey"))); - */ - settings.List.Configure((listCtx, listOptions) => { listOptions.CompareElementsByKey( diff --git a/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs b/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs index 797ffe2..20eaffe 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs @@ -33,6 +33,7 @@ public void Equality_CompareByKey() { var a1 = new A { NonGenericEnumerable = new ArrayList { new B { Property1 = "Str2" }, new B { Property1 = "Str1" } } }; var a2 = new A { NonGenericEnumerable = new ArrayList { new B { Property1 = "Str1" }, new B { Property1 = "Str2" } } }; + var settings = new ComparisonSettings(); settings.List.Configure(listOptions => listOptions.CompareElementsByKey(keyOptions => keyOptions.UseKey("Property1"))); var comparer = new Comparer(settings); @@ -63,8 +64,9 @@ public void InequalityCount_CompareUnequalLists() { var a1 = new A { NonGenericEnumerable = new ArrayList { new B { Property1 = "Str1" }, new B { Property1 = "Str2" } } }; var a2 = new A { NonGenericEnumerable = new ArrayList { new B { Property1 = "Str1" } } }; + var settings = new ComparisonSettings(); - settings.List.Configure(listOptions => listOptions.CompareUnequalLists = true); + settings.List.Configure(listOptions => listOptions.CompareUnequalLists(true)); var comparer = new Comparer(settings); var differences = comparer.CalculateDifferences(a1, a2).ToList(); @@ -87,10 +89,11 @@ public void InequalityCount_CompareUnequalLists_CompareByKey() { var a1 = new A { NonGenericEnumerable = new ArrayList { new B { Property1 = "Str1" }, new B { Property1 = "Str2" } } }; var a2 = new A { NonGenericEnumerable = new ArrayList { new B { Property1 = "Str1" } } }; + var settings = new ComparisonSettings(); settings.List.Configure(listOptions => { - listOptions.CompareUnequalLists = true; + listOptions.CompareUnequalLists(true); listOptions.CompareElementsByKey(keyOptions => { keyOptions.UseKey("Property1"); @@ -119,12 +122,9 @@ public void InequalityCount_CompareUnequalLists_CompareByKey_DontFormatKey() { var a1 = new A { NonGenericEnumerable = new ArrayList { new B { Property1 = "Str1" }, new B { Property1 = "Str2" } } }; var a2 = new A { NonGenericEnumerable = new ArrayList { new B { Property1 = "Str1" } } }; + var settings = new ComparisonSettings(); - settings.List.Configure(listOptions => - { - listOptions.CompareUnequalLists = true; - listOptions.CompareElementsByKey(keyOptions => keyOptions.UseKey("Property1")); - }); + settings.List.Configure(listOptions => listOptions.CompareUnequalLists(true).CompareElementsByKey(keyOptions => keyOptions.UseKey("Property1"))); var comparer = new Comparer(settings); @@ -202,7 +202,7 @@ public void NullElementsEquality_CompareUnequalLists() var a2 = new A { NonGenericEnumerable = new ArrayList { null, null } }; var settings = new ComparisonSettings(); - settings.List.Configure(listOptions => listOptions.CompareUnequalLists = true); + settings.List.Configure(listOptions => listOptions.CompareUnequalLists(true)); var comparer = new Comparer(settings); var isEqual = comparer.Compare(a1, a2, out var diffs); @@ -225,11 +225,7 @@ public void NullElementsEquality_CompareUnequalLists_CompareByKey() var a2 = new A { NonGenericEnumerable = new ArrayList { null, null } }; var settings = new ComparisonSettings(); - settings.List.Configure(listOptions => - { - listOptions.CompareUnequalLists = true; - listOptions.CompareElementsByKey(); //Because all elements are null, no key definition is required for this test method. - }); + settings.List.Configure(listOptions => listOptions.CompareUnequalLists(true).CompareElementsByKey()); var comparer = new Comparer(settings); var isEqual = comparer.Compare(a1, a2, out var diffs); diff --git a/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs b/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs index 5d96663..60a6b77 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs @@ -63,7 +63,7 @@ public void CompareListElementsByKeyIsCorrectlySet() settings.List.Configure((comparisonContext, listOptions) => { - listOptions.CompareUnequalLists = true; + listOptions.CompareUnequalLists(true); listOptions.CompareElementsByKey(keyOptions => { @@ -79,7 +79,7 @@ public void CompareListElementsByKeyIsCorrectlySet() var compareElementsByKeyOptions = CompareListElementsByKeyOptions.Default(); listConfigurationOptions.KeyOptionsAction(compareElementsByKeyOptions); - Assert.AreEqual(true, listConfigurationOptions.CompareUnequalLists); + Assert.AreEqual(true, listConfigurationOptions.UnequalListsComparisonEnabled); Assert.AreEqual(true, listConfigurationOptions.ElementSearchMode == ListElementSearchMode.Key); Assert.AreEqual(false, compareElementsByKeyOptions.ThrowKeyNotFound); } @@ -92,7 +92,7 @@ public void ListComparisonConfigurationBackwardCompatibilityEnsured() { var options = ListConfigurationOptions.Default(); - Assert.AreEqual(false, options.CompareUnequalLists); + Assert.AreEqual(false, options.UnequalListsComparisonEnabled); Assert.AreEqual(true, options.ElementSearchMode == ListElementSearchMode.Index); } diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs index ebcfb72..ebfdfd9 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs @@ -64,7 +64,7 @@ public IEnumerable CalculateDifferences(Type type, object obj1, obje { yield return AddDifferenceToComparisonContext(new Difference("", array1.Length.ToString(), array2.Length.ToString(), DifferenceTypes.NumberOfElementsMismatch), listComparisonContext); - if (listConfigurationOptions.CompareUnequalLists == false) + if (listConfigurationOptions.UnequalListsComparisonEnabled == false) { yield break; } diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer~1.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer~1.cs index 7e6944c..c88f356 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer~1.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer~1.cs @@ -67,7 +67,7 @@ public IEnumerable CalculateDifferences(Type type, object obj1, obje yield return AddDifferenceToComparisonContext(new Difference("", list1.Count().ToString(), list2.Count().ToString(), DifferenceTypes.NumberOfElementsMismatch), listComparisonContext); } - if (listConfigurationOptions.CompareUnequalLists == false) + if (listConfigurationOptions.UnequalListsComparisonEnabled == false) { yield break; } diff --git a/ObjectsComparer/ObjectsComparer/ListConfigurationOptions.cs b/ObjectsComparer/ObjectsComparer/ListConfigurationOptions.cs index c68f3fc..7ed4596 100644 --- a/ObjectsComparer/ObjectsComparer/ListConfigurationOptions.cs +++ b/ObjectsComparer/ObjectsComparer/ListConfigurationOptions.cs @@ -16,16 +16,16 @@ public class ListConfigurationOptions } /// - /// Whether to compare elements of the lists even if their number differs. Regardless of the value, the respective difference of type will always be logged. Default value = false. + /// See . /// - internal bool CompareUnequalLists { get; private set; } = false; + internal bool UnequalListsComparisonEnabled { get; private set; } = false; /// - /// Whether to compare elements of the lists even if their number differs. Regardless of the value, the respective difference of type will always be logged. Default value = false. + /// Whether to compare elements of the lists even if their number differs. Regardless of the , the respective difference of type will always be logged. Default value = false. /// - public ListConfigurationOptions WithUnequalLists(bool value) + public ListConfigurationOptions CompareUnequalLists(bool value) { - CompareUnequalLists = value; + UnequalListsComparisonEnabled = value; return this; } From 0f4243e7179b53b95fd0219774903d72c1ba2364 Mon Sep 17 00:00:00 2001 From: "ASD\\nemec" Date: Tue, 9 Nov 2021 07:18:24 +0100 Subject: [PATCH 059/181] CompareListElementsByKeyOptions: Add fluent API. --- .../Comparer_GenericEnumerableTests.cs | 26 +++++++++---------- .../Comparer_MultidimensionalArraysTests.cs | 4 +-- .../Comparer_NonGenericEnumerableTests.cs | 10 +++---- .../ComparisonSettingsTests.cs | 25 +++++++++++++++--- .../CompareListElementsByKeyOptions.cs | 18 ++++++++++--- .../EnumerablesComparerBase.cs | 4 +-- .../Exceptions/ElementKeyNotFoundException.cs | 2 +- .../ListConfigurationOptions.cs | 4 +-- 8 files changed, 62 insertions(+), 31 deletions(-) diff --git a/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs b/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs index a70f3bc..e5ada64 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs @@ -65,7 +65,7 @@ public void PrimitiveTypeArrayInequalityCount_CompareUnequalLists() var a2 = new A { IntArray = new[] { 1, 2, 3 } }; var settings = new ComparisonSettings(); - settings.List.Configure(listOptions => listOptions.CompareUnequalLists(true)); + settings.List.Configure(listOptions => listOptions.WithUnequalLists(true)); var comparer = new Comparer(settings); var rootCtx = ComparisonContext.CreateRoot(); @@ -268,7 +268,7 @@ public void ClassArrayEquality_ComareByKey_DoesNotThrow_ElementKeyNotFoundExcept var a2 = new A { ArrayOfB = new[] { new B { Property1 = "Str1" }, new B { Property1 = "Str2" } } }; var settings = new ComparisonSettings(); - settings.List.Configure(listOptions => listOptions.CompareElementsByKey(keyOptions => keyOptions.ThrowKeyNotFound = false)); + settings.List.Configure(listOptions => listOptions.CompareElementsByKey(keyOptions => keyOptions.ThrowKeyNotFoundEnabled = false)); var comparer = new Comparer(settings); bool isEqual = false; @@ -304,7 +304,7 @@ public void ClassArrayInequalityCount_CompareByKey_DoesNotThrow_ElementKeyNotFou var a2 = new A { ArrayOfB = new[] { new B { Property1 = "Str1" }, new B { Property1 = "Str2" } } }; var settings = new ComparisonSettings(); - settings.List.Configure(listOptions => listOptions.CompareUnequalLists(true).CompareElementsByKey(keyOptions => keyOptions.ThrowKeyNotFound = false)); + settings.List.Configure(listOptions => listOptions.WithUnequalLists(true).CompareElementsByKey(keyOptions => keyOptions.ThrowKeyNotFoundEnabled = false)); var comparer = new Comparer(settings); @@ -326,7 +326,7 @@ public void ClassArrayInequalityCount_CompareUnequalLists() var a2 = new A { ArrayOfB = new[] { new B { Property1 = "Str1" }, new B { Property1 = "Str2" } } }; var settings = new ComparisonSettings(); - settings.List.Configure(listOptions => listOptions.CompareUnequalLists(true)); + settings.List.Configure(listOptions => listOptions.WithUnequalLists(true)); var comparer = new Comparer(settings); @@ -450,7 +450,7 @@ public void CollectionInequalityCount_CompareUnequalLists() var a2 = new A { CollectionOfB = new Collection { new B { Property1 = "Str1" } } }; var settings = new ComparisonSettings(); - settings.List.Configure(listOptions => listOptions.CompareUnequalLists(true)); + settings.List.Configure(listOptions => listOptions.WithUnequalLists(true)); var comparer = new Comparer(settings); @@ -634,7 +634,7 @@ public void ClassImplementsCollectionInequalityCount_CompareUnequalLists() var a2 = new A { ClassImplementsCollectionOfB = new CollectionOfB { new B { Property1 = "Str1" } } }; var settings = new ComparisonSettings(); - settings.List.Configure(listOptions => listOptions.CompareUnequalLists(true)); + settings.List.Configure(listOptions => listOptions.WithUnequalLists(true)); var comparer = new Comparer(settings); @@ -661,7 +661,7 @@ public void ClassImplementsCollectionInequalityCount_CompareUnequalLists_Compare var a2 = new A { ClassImplementsCollectionOfB = new CollectionOfB { new B { Property1 = "Str1", Id = 1 } } }; var settings = new ComparisonSettings(); - settings.List.Configure(listOptions => listOptions.CompareUnequalLists(true).CompareElementsByKey()); + settings.List.Configure(listOptions => listOptions.WithUnequalLists(true).CompareElementsByKey()); var comparer = new Comparer(settings); @@ -703,7 +703,7 @@ public void ClassImplementsCollectionInequalityProperty_CompareByKey() var a2 = new A { ClassImplementsCollectionOfB = new CollectionOfB { new B { Property1 = "Str1", Id = 1 }, new B { Property1 = "Str3", Id = 2 } } }; var settings = new ComparisonSettings(); - settings.List.Configure(listOptions => listOptions.CompareUnequalLists(true).CompareElementsByKey()); + settings.List.Configure(listOptions => listOptions.WithUnequalLists(true).CompareElementsByKey()); var comparer = new Comparer(settings); @@ -845,7 +845,7 @@ public void CollectionOfBCountInequality1_CompareElementsByKey_CompareUnequalLis }; var settings = new ComparisonSettings(); - settings.List.Configure(listOptions => listOptions.CompareUnequalLists(true).CompareElementsByKey()); + settings.List.Configure(listOptions => listOptions.WithUnequalLists(true).CompareElementsByKey()); var comparer = new Comparer(settings); @@ -905,7 +905,7 @@ public void CollectionOfBCountInequality2_CompareByKey() }; var settings = new ComparisonSettings(); - settings.List.Configure(listOptions => listOptions.CompareUnequalLists(true).CompareElementsByKey()); + settings.List.Configure(listOptions => listOptions.WithUnequalLists(true).CompareElementsByKey()); var comparer = new Comparer(settings); var isEqual = comparer.Compare(a1, a2, out var differencesEnum); @@ -1047,7 +1047,7 @@ public void CompareAsIList_CompareUnequalLists() var list2 = new List { 1 }; var settings = new ComparisonSettings(); - settings.List.Configure(listOptions => listOptions.CompareUnequalLists(true)); + settings.List.Configure(listOptions => listOptions.WithUnequalLists(true)); var comparer = new Comparer>(settings); @@ -1072,7 +1072,7 @@ public void CompareAsIList_CompareUnequalLists_CompareElementsByKey() var list2 = new List { 1 }; var settings = new ComparisonSettings(); - settings.List.Configure(listOptions => listOptions.CompareUnequalLists(true).CompareElementsByKey()); + settings.List.Configure(listOptions => listOptions.WithUnequalLists(true).CompareElementsByKey()); var comparer = new Comparer>(settings); @@ -1108,7 +1108,7 @@ public void CompareAsIList_CompareUnequalLists_CompareElementsByKey_FormatKey() * .CompareElementsByKey(keyOptions => keyOptions.FormatElementKey(elementKey => $"Key={elementKey}")); */ - listOptions.CompareUnequalLists(true); + listOptions.WithUnequalLists(true); listOptions.CompareElementsByKey(keyOptions => { diff --git a/ObjectsComparer/ObjectsComparer.Tests/Comparer_MultidimensionalArraysTests.cs b/ObjectsComparer/ObjectsComparer.Tests/Comparer_MultidimensionalArraysTests.cs index af09078..5782600 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/Comparer_MultidimensionalArraysTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/Comparer_MultidimensionalArraysTests.cs @@ -42,7 +42,7 @@ public void IntOfIntInequality1_CompareByKey() var settings = new ComparisonSettings(); settings.List.Configure((ComparisonContext ctx, ListConfigurationOptions listOptions) => listOptions - .CompareUnequalLists(true) + .WithUnequalLists(true) .CompareElementsByKey(keyOptions => { if (ctx.Member == null) @@ -58,7 +58,7 @@ public void IntOfIntInequality1_CompareByKey() settings.List.Configure(listOptions => { listOptions - .CompareUnequalLists(true) + .WithUnequalLists(true) .CompareElementsByKey(); }); diff --git a/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs b/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs index 20eaffe..0ce7b34 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs @@ -66,7 +66,7 @@ public void InequalityCount_CompareUnequalLists() var a2 = new A { NonGenericEnumerable = new ArrayList { new B { Property1 = "Str1" } } }; var settings = new ComparisonSettings(); - settings.List.Configure(listOptions => listOptions.CompareUnequalLists(true)); + settings.List.Configure(listOptions => listOptions.WithUnequalLists(true)); var comparer = new Comparer(settings); var differences = comparer.CalculateDifferences(a1, a2).ToList(); @@ -93,7 +93,7 @@ public void InequalityCount_CompareUnequalLists_CompareByKey() var settings = new ComparisonSettings(); settings.List.Configure(listOptions => { - listOptions.CompareUnequalLists(true); + listOptions.WithUnequalLists(true); listOptions.CompareElementsByKey(keyOptions => { keyOptions.UseKey("Property1"); @@ -124,7 +124,7 @@ public void InequalityCount_CompareUnequalLists_CompareByKey_DontFormatKey() var a2 = new A { NonGenericEnumerable = new ArrayList { new B { Property1 = "Str1" } } }; var settings = new ComparisonSettings(); - settings.List.Configure(listOptions => listOptions.CompareUnequalLists(true).CompareElementsByKey(keyOptions => keyOptions.UseKey("Property1"))); + settings.List.Configure(listOptions => listOptions.WithUnequalLists(true).CompareElementsByKey(keyOptions => keyOptions.UseKey("Property1"))); var comparer = new Comparer(settings); @@ -202,7 +202,7 @@ public void NullElementsEquality_CompareUnequalLists() var a2 = new A { NonGenericEnumerable = new ArrayList { null, null } }; var settings = new ComparisonSettings(); - settings.List.Configure(listOptions => listOptions.CompareUnequalLists(true)); + settings.List.Configure(listOptions => listOptions.WithUnequalLists(true)); var comparer = new Comparer(settings); var isEqual = comparer.Compare(a1, a2, out var diffs); @@ -225,7 +225,7 @@ public void NullElementsEquality_CompareUnequalLists_CompareByKey() var a2 = new A { NonGenericEnumerable = new ArrayList { null, null } }; var settings = new ComparisonSettings(); - settings.List.Configure(listOptions => listOptions.CompareUnequalLists(true).CompareElementsByKey()); + settings.List.Configure(listOptions => listOptions.WithUnequalLists(true).CompareElementsByKey()); var comparer = new Comparer(settings); var isEqual = comparer.Compare(a1, a2, out var diffs); diff --git a/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs b/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs index 60a6b77..33bea19 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs @@ -63,12 +63,12 @@ public void CompareListElementsByKeyIsCorrectlySet() settings.List.Configure((comparisonContext, listOptions) => { - listOptions.CompareUnequalLists(true); + listOptions.WithUnequalLists(true); listOptions.CompareElementsByKey(keyOptions => { keyOptions.UseKey("Key"); - keyOptions.ThrowKeyNotFound = false; + keyOptions.ThrowKeyNotFoundEnabled = false; }); }); @@ -81,7 +81,7 @@ public void CompareListElementsByKeyIsCorrectlySet() Assert.AreEqual(true, listConfigurationOptions.UnequalListsComparisonEnabled); Assert.AreEqual(true, listConfigurationOptions.ElementSearchMode == ListElementSearchMode.Key); - Assert.AreEqual(false, compareElementsByKeyOptions.ThrowKeyNotFound); + Assert.AreEqual(false, compareElementsByKeyOptions.ThrowKeyNotFoundEnabled); } /// @@ -105,5 +105,24 @@ public void PrubeznyTest() var result = comparer.CalculateDifferences(a1, a2).ToArray(); } + + [Test] + public void FluentTest() + { + var a1 = new ArrayList() { 3, 2, 1 }; + var a2 = new ArrayList() { 1, 2, 3, 4 }; + + var settings = new ComparisonSettings(); + settings.List.Configure(listOptions => listOptions.WithUnequalLists(true).CompareElementsByKey()); + + var comparer = new Comparer(settings); + var differences = comparer.CalculateDifferences(a1, a2).ToList(); + + Assert.AreEqual(2, differences.Count); + Assert.AreEqual(DifferenceTypes.MissedElementInFirstObject, differences[1].DifferenceType); + Assert.AreEqual("[1]", differences[0].MemberPath); + Assert.AreEqual("", differences[1].Value1); + Assert.AreEqual("4", differences[1].Value2); + } } } diff --git a/ObjectsComparer/ObjectsComparer/CompareListElementsByKeyOptions.cs b/ObjectsComparer/ObjectsComparer/CompareListElementsByKeyOptions.cs index d9e90a8..ad97bb5 100644 --- a/ObjectsComparer/ObjectsComparer/CompareListElementsByKeyOptions.cs +++ b/ObjectsComparer/ObjectsComparer/CompareListElementsByKeyOptions.cs @@ -42,12 +42,24 @@ public class CompareListElementsByKeyOptions /// Func NullElementIdentifierFormatter { get; set; } + /// + /// See . + /// + internal bool ThrowKeyNotFoundEnabled { get; set; } = true; + /// /// If value = false and element key will not be found, the element will be excluded from comparison and no difference will be added except for possible difference. /// If value = true and element key will not be found, an exception of type will be thrown. /// Default value = true. /// - public bool ThrowKeyNotFound { get; set; } = true; + /// + /// + public CompareListElementsByKeyOptions ThrowKeyNotFound(bool value) + { + ThrowKeyNotFoundEnabled = value; + + return this; + } /// /// See . @@ -94,9 +106,9 @@ public CompareListElementsByKeyOptions UseKey(string[] keys, bool caseSensitive throw new ArgumentException($"'{nameof(keys)}' cannot contain null or whitespace.", nameof(keys)); } - return UseKey(element => + return UseKey(args => { - return GetKeyValue(element, caseSensitive, keys); + return GetKeyValue(args.Element, caseSensitive, keys); }); } diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparerBase.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparerBase.cs index 57096e6..0a364bc 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparerBase.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparerBase.cs @@ -63,7 +63,7 @@ protected virtual IEnumerable CalculateDifferencesByKey(IList if (element1Key == null) { - if (keyOptions.ThrowKeyNotFound) + if (keyOptions.ThrowKeyNotFoundEnabled) { throw new ElementKeyNotFoundException(element1, elementComparisonContext); } @@ -112,7 +112,7 @@ protected virtual IEnumerable CalculateDifferencesByKey(IList if (element2Key == null) { - if (keyOptions.ThrowKeyNotFound) + if (keyOptions.ThrowKeyNotFoundEnabled) { throw new ElementKeyNotFoundException(element2, elementComparisonContext); } diff --git a/ObjectsComparer/ObjectsComparer/Exceptions/ElementKeyNotFoundException.cs b/ObjectsComparer/ObjectsComparer/Exceptions/ElementKeyNotFoundException.cs index a246e0e..816b188 100644 --- a/ObjectsComparer/ObjectsComparer/Exceptions/ElementKeyNotFoundException.cs +++ b/ObjectsComparer/ObjectsComparer/Exceptions/ElementKeyNotFoundException.cs @@ -5,7 +5,7 @@ namespace ObjectsComparer.Exceptions { /// - /// Depending on the configuration, the exception is thrown if the key provider does not supply the key for list element . For more information see and . + /// Depending on the configuration, the exception is thrown if the key provider does not supply the key for list element . For more information see and . /// public class ElementKeyNotFoundException : Exception { diff --git a/ObjectsComparer/ObjectsComparer/ListConfigurationOptions.cs b/ObjectsComparer/ObjectsComparer/ListConfigurationOptions.cs index 7ed4596..fb431a6 100644 --- a/ObjectsComparer/ObjectsComparer/ListConfigurationOptions.cs +++ b/ObjectsComparer/ObjectsComparer/ListConfigurationOptions.cs @@ -16,14 +16,14 @@ public class ListConfigurationOptions } /// - /// See . + /// See . /// internal bool UnequalListsComparisonEnabled { get; private set; } = false; /// /// Whether to compare elements of the lists even if their number differs. Regardless of the , the respective difference of type will always be logged. Default value = false. /// - public ListConfigurationOptions CompareUnequalLists(bool value) + public ListConfigurationOptions WithUnequalLists(bool value) { UnequalListsComparisonEnabled = value; From 1aa67033402263ff47c864c4e89944a67ce4fc1c Mon Sep 17 00:00:00 2001 From: "ASD\\nemec" Date: Tue, 9 Nov 2021 10:48:21 +0100 Subject: [PATCH 060/181] Test fluent methods. --- .../ComparisonSettingsTests.cs | 204 +++++++++++++++++- 1 file changed, 195 insertions(+), 9 deletions(-) diff --git a/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs b/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs index 33bea19..5997587 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs @@ -3,6 +3,7 @@ using System.Linq; using System.Collections.Generic; using NUnit.Framework; +using ObjectsComparer.Tests.TestClasses; namespace ObjectsComparer.Tests { @@ -97,20 +98,45 @@ public void ListComparisonConfigurationBackwardCompatibilityEnsured() } [Test] - public void PrubeznyTest() + public void FluentTest_WithUnequalLists() { - var a1 = new ArrayList() { 1, 2, 3 }; - var a2 = new ArrayList() { 1, 2, 3, 4 }; - var comparer = new Comparer(); + var a1 = new int[] { 3, 2, 1 }; + var a2 = new int[] { 1, 2, 3, 4 }; - var result = comparer.CalculateDifferences(a1, a2).ToArray(); + var settings = new ComparisonSettings(); + settings.List.Configure(listOptions => listOptions.WithUnequalLists(true)); + + var comparer = new Comparer(settings); + var differences = comparer.CalculateDifferences(a1, a2).ToList(); + + Assert.AreEqual(4, differences.Count); + + Assert.AreEqual(DifferenceTypes.ValueMismatch, differences[0].DifferenceType); + Assert.AreEqual("[0]", differences[0].MemberPath); + Assert.AreEqual("3", differences[0].Value1); + Assert.AreEqual("1", differences[0].Value2); + + Assert.AreEqual(DifferenceTypes.ValueMismatch, differences[1].DifferenceType); + Assert.AreEqual("[2]", differences[1].MemberPath); + Assert.AreEqual("1", differences[1].Value1); + Assert.AreEqual("3", differences[1].Value2); + + Assert.AreEqual(DifferenceTypes.MissedElementInFirstObject, differences[2].DifferenceType); + Assert.AreEqual("[3]", differences[2].MemberPath); + Assert.AreEqual("", differences[2].Value1); + Assert.AreEqual("4", differences[2].Value2); + + Assert.AreEqual(DifferenceTypes.ValueMismatch, differences[3].DifferenceType); + Assert.AreEqual("Length", differences[3].MemberPath); + Assert.AreEqual("3", differences[3].Value1); + Assert.AreEqual("4", differences[3].Value2); } [Test] - public void FluentTest() + public void FluentTest_WithUnequalLists_CompareElementsByKey() { - var a1 = new ArrayList() { 3, 2, 1 }; - var a2 = new ArrayList() { 1, 2, 3, 4 }; + var a1 = new int[] { 3, 2, 1 }; + var a2 = new int[] { 1, 2, 3, 4 }; var settings = new ComparisonSettings(); settings.List.Configure(listOptions => listOptions.WithUnequalLists(true).CompareElementsByKey()); @@ -119,9 +145,169 @@ public void FluentTest() var differences = comparer.CalculateDifferences(a1, a2).ToList(); Assert.AreEqual(2, differences.Count); + + Assert.AreEqual(DifferenceTypes.MissedElementInFirstObject, differences[0].DifferenceType); + Assert.AreEqual("[4]", differences[0].MemberPath); + Assert.AreEqual("", differences[0].Value1); + Assert.AreEqual("4", differences[0].Value2); + + Assert.AreEqual(DifferenceTypes.ValueMismatch, differences[1].DifferenceType); + Assert.AreEqual("Length", differences[1].MemberPath); + Assert.AreEqual("3", differences[1].Value1); + Assert.AreEqual("4", differences[1].Value2); + } + + [Test] + public void FluentTest_WithUnequalLists_CompareElementsByKey_FormatKey() + { + var a1 = new int[] { 3, 2, 1 }; + var a2 = new int[] { 1, 2, 3, 4 }; + + var settings = new ComparisonSettings(); + settings.List.Configure(listOptions => listOptions + .WithUnequalLists(true) + .CompareElementsByKey(keyOptions => keyOptions.FormatElementKey(args => $"Key={args.ElementKey}"))); + + var comparer = new Comparer(settings); + var differences = comparer.CalculateDifferences(a1, a2).ToList(); + + Assert.AreEqual(2, differences.Count); + + Assert.AreEqual(DifferenceTypes.MissedElementInFirstObject, differences[0].DifferenceType); + Assert.AreEqual("[Key=4]", differences[0].MemberPath); + Assert.AreEqual("", differences[0].Value1); + Assert.AreEqual("4", differences[0].Value2); + + Assert.AreEqual(DifferenceTypes.ValueMismatch, differences[1].DifferenceType); + Assert.AreEqual("Length", differences[1].MemberPath); + Assert.AreEqual("3", differences[1].Value1); + Assert.AreEqual("4", differences[1].Value2); + } + + [Test] + public void FluentTest_WithUnequalLists_CompareElementsByKey_FormatKey_DefaultNullElementIdentifier() + { + var a1 = new int?[] { 3, 2, 1 }; + var a2 = new int?[] { 1, 2, 3, 4, null }; + + var settings = new ComparisonSettings(); + settings.List.Configure(listOptions => listOptions + .WithUnequalLists(true) + .CompareElementsByKey(keyOptions => keyOptions.FormatElementKey(args => $"Key={args.ElementKey}"))); + + var comparer = new Comparer(settings); + var differences = comparer.CalculateDifferences(a1, a2).ToList(); + + Assert.AreEqual(3, differences.Count); + + Assert.AreEqual(DifferenceTypes.MissedElementInFirstObject, differences[0].DifferenceType); + Assert.AreEqual("[Key=4]", differences[0].MemberPath); + Assert.AreEqual("", differences[0].Value1); + Assert.AreEqual("4", differences[0].Value2); + Assert.AreEqual(DifferenceTypes.MissedElementInFirstObject, differences[1].DifferenceType); - Assert.AreEqual("[1]", differences[0].MemberPath); + Assert.AreEqual("[NullAtIdx=4]", differences[1].MemberPath); Assert.AreEqual("", differences[1].Value1); + Assert.AreEqual("", differences[1].Value2); + + Assert.AreEqual(DifferenceTypes.ValueMismatch, differences[2].DifferenceType); + Assert.AreEqual("Length", differences[2].MemberPath); + Assert.AreEqual("3", differences[2].Value1); + Assert.AreEqual("5", differences[2].Value2); + } + + [Test] + public void FluentTest_WithUnequalLists_CompareElementsByKey_FormatKey_FormatNullElementIdntf() + { + var a1 = new int?[] { 3, 2, 1 }; + var a2 = new int?[] { 1, 2, 3, 4, null }; + + var settings = new ComparisonSettings(); + settings.List.Configure(listOptions => listOptions + .WithUnequalLists(true) + .CompareElementsByKey(keyOptions => keyOptions + .FormatElementKey(args => $"Key={args.ElementKey}") + .FormatNullElementIdentifier(idx => $"Null at {idx}"))); + + settings.List.Configure(listOptions => + { + listOptions.WithUnequalLists(true); + + listOptions.CompareElementsByKey(keyOptions => + { + keyOptions.FormatElementKey(args => $"Key={args.ElementKey}"); + keyOptions.FormatNullElementIdentifier(idx => $"Null at {idx}"); + }); + }); + + settings.List.Configure((ctx, listOptions) => + { + bool unequalEnabled = ctx.Member.Name == "List1"; + listOptions.WithUnequalLists(unequalEnabled); + + listOptions.CompareElementsByKey(keyOptions => + { + keyOptions.FormatElementKey(args => $"Key={args.ElementKey}"); + keyOptions.FormatNullElementIdentifier(idx => $"Null at {idx}"); + + if (ctx.Member.Name == nameof(A.ListOfB)) + { + keyOptions.UseKey(args => + { + if (args.Element is B element) + { + return element.Property1; + } + + return args.Element; + }); + } + }); + }); + + var comparer = new Comparer(settings); + var differences = comparer.CalculateDifferences(a1, a2).ToList(); + + Assert.AreEqual(3, differences.Count); + + Assert.AreEqual(DifferenceTypes.MissedElementInFirstObject, differences[0].DifferenceType); + Assert.AreEqual("[Key=4]", differences[0].MemberPath); + Assert.AreEqual("", differences[0].Value1); + Assert.AreEqual("4", differences[0].Value2); + + Assert.AreEqual(DifferenceTypes.MissedElementInFirstObject, differences[1].DifferenceType); + Assert.AreEqual("[Null at 4]", differences[1].MemberPath); + Assert.AreEqual("", differences[1].Value1); + Assert.AreEqual("", differences[1].Value2); + + Assert.AreEqual(DifferenceTypes.ValueMismatch, differences[2].DifferenceType); + Assert.AreEqual("Length", differences[2].MemberPath); + Assert.AreEqual("3", differences[2].Value1); + Assert.AreEqual("5", differences[2].Value2); + } + + [Test] + public void FluentTest_List() + { + var a1 = new List { 3, 2, 1 }; + var a2 = new List { 1, 2, 3, 4 }; + + var settings = new ComparisonSettings(); + settings.List.Configure(listOptions => listOptions.WithUnequalLists(true).CompareElementsByKey()); + + var comparer = new Comparer(settings); + var differences = comparer.CalculateDifferences(a1, a2).ToList(); + + Assert.AreEqual(2, differences.Count); + + Assert.AreEqual(DifferenceTypes.MissedElementInFirstObject, differences[0].DifferenceType); + Assert.AreEqual("[4]", differences[0].MemberPath); + Assert.AreEqual("", differences[0].Value1); + Assert.AreEqual("4", differences[0].Value2); + + Assert.AreEqual(DifferenceTypes.ValueMismatch, differences[1].DifferenceType); + Assert.AreEqual("Length", differences[1].MemberPath); + Assert.AreEqual("3", differences[1].Value1); Assert.AreEqual("4", differences[1].Value2); } } From 3ce6c62c19675b7b6fafe0c23ff944b86172300f Mon Sep 17 00:00:00 2001 From: "ASD\\nemec" Date: Tue, 9 Nov 2021 12:19:42 +0100 Subject: [PATCH 061/181] Add FormatNullElementIdentifierArgs. Replace CompareListElementsByKeyOptions.FormatNullElementIdentifier operation argument type with FormatNullElementIdentifierArgs. --- .../ComparisonSettingsTests.cs | 81 ++++++++++--------- .../CompareListElementsByKeyOptions.cs | 17 ++-- .../EnumerablesComparerBase.cs | 4 +- .../FormatListElementKeyArgs.cs | 2 +- .../FormatNullElementIdentifierArgs.cs | 17 ++++ .../ObjectsComparer/ListComparisonSettings.cs | 4 +- 6 files changed, 75 insertions(+), 50 deletions(-) create mode 100644 ObjectsComparer/ObjectsComparer/FormatNullElementIdentifierArgs.cs diff --git a/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs b/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs index 5997587..3e2bc93 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs @@ -217,7 +217,7 @@ public void FluentTest_WithUnequalLists_CompareElementsByKey_FormatKey_DefaultNu } [Test] - public void FluentTest_WithUnequalLists_CompareElementsByKey_FormatKey_FormatNullElementIdntf() + public void FluentTest_WithUnequalLists_CompareElementsByKey_FormatKey_FormatNullElementIdentifier() { var a1 = new int?[] { 3, 2, 1 }; var a2 = new int?[] { 1, 2, 3, 4, null }; @@ -226,46 +226,49 @@ public void FluentTest_WithUnequalLists_CompareElementsByKey_FormatKey_FormatNul settings.List.Configure(listOptions => listOptions .WithUnequalLists(true) .CompareElementsByKey(keyOptions => keyOptions - .FormatElementKey(args => $"Key={args.ElementKey}") - .FormatNullElementIdentifier(idx => $"Null at {idx}"))); - - settings.List.Configure(listOptions => - { - listOptions.WithUnequalLists(true); - - listOptions.CompareElementsByKey(keyOptions => - { - keyOptions.FormatElementKey(args => $"Key={args.ElementKey}"); - keyOptions.FormatNullElementIdentifier(idx => $"Null at {idx}"); - }); - }); - - settings.List.Configure((ctx, listOptions) => - { - bool unequalEnabled = ctx.Member.Name == "List1"; - listOptions.WithUnequalLists(unequalEnabled); - - listOptions.CompareElementsByKey(keyOptions => - { - keyOptions.FormatElementKey(args => $"Key={args.ElementKey}"); - keyOptions.FormatNullElementIdentifier(idx => $"Null at {idx}"); - - if (ctx.Member.Name == nameof(A.ListOfB)) - { - keyOptions.UseKey(args => - { - if (args.Element is B element) - { - return element.Property1; - } - - return args.Element; - }); - } - }); - }); + .FormatElementKey(formatArgs => $"Key={formatArgs.ElementKey}") + .FormatNullElementIdentifier(formatArgs => $"Null at {formatArgs.ElementIndex}"))); var comparer = new Comparer(settings); + + //settings = new ComparisonSettings(); + //settings.List.Configure(listOptions => + //{ + // listOptions.WithUnequalLists(true); + + // listOptions.CompareElementsByKey(keyOptions => + // { + // keyOptions.FormatElementKey(args => $"Key={args.ElementKey}"); + // keyOptions.FormatNullElementIdentifier(idx => $"Null at {idx}"); + // }); + //}); + + //settings = new ComparisonSettings(); + //settings.List.Configure((ctx, listOptions) => + //{ + // bool unequalEnabled = ctx.Member.Name == "List1"; + // listOptions.WithUnequalLists(unequalEnabled); + + // listOptions.CompareElementsByKey(keyOptions => + // { + // keyOptions.FormatElementKey(args => $"Key={args.ElementKey}"); + // keyOptions.FormatNullElementIdentifier(args => $"Null at {args.ElementIndex}"); + + // if (ctx.Member.Name == nameof(A.ListOfB)) + // { + // keyOptions.UseKey(args => + // { + // if (args.Element is B element) + // { + // return element.Property1; + // } + + // return args.Element; + // }); + // } + // }); + //}); + var differences = comparer.CalculateDifferences(a1, a2).ToList(); Assert.AreEqual(3, differences.Count); diff --git a/ObjectsComparer/ObjectsComparer/CompareListElementsByKeyOptions.cs b/ObjectsComparer/ObjectsComparer/CompareListElementsByKeyOptions.cs index ad97bb5..37daa98 100644 --- a/ObjectsComparer/ObjectsComparer/CompareListElementsByKeyOptions.cs +++ b/ObjectsComparer/ObjectsComparer/CompareListElementsByKeyOptions.cs @@ -40,7 +40,7 @@ public class CompareListElementsByKeyOptions /// /// See . /// - Func NullElementIdentifierFormatter { get; set; } + Func NullElementIdentifierFormatter { get; set; } /// /// See . @@ -178,14 +178,19 @@ internal string GetFormattedElementKey(FormatListElementKeyArgs formatElementKey /// /// Returns element identifier for element that referes to null. See . /// - /// Element index. - internal string GetNullElementIdentifier(int elementIndex) + /// Element index. + internal string GetNullElementIdentifier(FormatNullElementIdentifierArgs args) { - var elementIdentifier = NullElementIdentifierFormatter?.Invoke(elementIndex); + if (args is null) + { + throw new ArgumentNullException(nameof(args)); + } + + var elementIdentifier = NullElementIdentifierFormatter?.Invoke(args); if (string.IsNullOrWhiteSpace(elementIdentifier)) { - elementIdentifier = string.Format(DefaultNullElementIdentifierTemplate, elementIndex); + elementIdentifier = string.Format(DefaultNullElementIdentifierTemplate, args); } return elementIdentifier.Left(NullElementIdentifierMaxLength); @@ -214,7 +219,7 @@ public CompareListElementsByKeyOptions FormatElementKey(Func template will be used to format the identifier. /// /// First parameter: Element index. Return value: Formatted identifier. - public CompareListElementsByKeyOptions FormatNullElementIdentifier(Func formatter) + public CompareListElementsByKeyOptions FormatNullElementIdentifier(Func formatter) { if (formatter is null) { diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparerBase.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparerBase.cs index 0a364bc..f73e2e8 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparerBase.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparerBase.cs @@ -53,7 +53,7 @@ protected virtual IEnumerable CalculateDifferencesByKey(IList continue; } - var nullElementIdentifier = keyOptions.GetNullElementIdentifier(element1Index); + var nullElementIdentifier = keyOptions.GetNullElementIdentifier(new FormatNullElementIdentifierArgs(element1Index)); yield return AddDifferenceToComparisonContext(new Difference($"[{nullElementIdentifier}]", string.Empty, string.Empty, DifferenceTypes.MissedElementInSecondObject), elementComparisonContext); continue; @@ -102,7 +102,7 @@ protected virtual IEnumerable CalculateDifferencesByKey(IList continue; } - var nullElementIdentifier = keyOptions.GetNullElementIdentifier(element2Index); + var nullElementIdentifier = keyOptions.GetNullElementIdentifier(new FormatNullElementIdentifierArgs(element2Index)); yield return AddDifferenceToComparisonContext(new Difference($"[{nullElementIdentifier}]", string.Empty, string.Empty, DifferenceTypes.MissedElementInFirstObject), elementComparisonContext); continue; diff --git a/ObjectsComparer/ObjectsComparer/FormatListElementKeyArgs.cs b/ObjectsComparer/ObjectsComparer/FormatListElementKeyArgs.cs index 075e3f6..cbe4860 100644 --- a/ObjectsComparer/ObjectsComparer/FormatListElementKeyArgs.cs +++ b/ObjectsComparer/ObjectsComparer/FormatListElementKeyArgs.cs @@ -3,7 +3,7 @@ namespace ObjectsComparer { /// - /// Useful arguments for list element key formatter, see . + /// Useful arguments for list element key formatter. See . /// public class FormatListElementKeyArgs { diff --git a/ObjectsComparer/ObjectsComparer/FormatNullElementIdentifierArgs.cs b/ObjectsComparer/ObjectsComparer/FormatNullElementIdentifierArgs.cs new file mode 100644 index 0000000..756aca1 --- /dev/null +++ b/ObjectsComparer/ObjectsComparer/FormatNullElementIdentifierArgs.cs @@ -0,0 +1,17 @@ +using System; + +namespace ObjectsComparer +{ + /// + /// Useful arguments for null element identifier formatter. See . + /// + public class FormatNullElementIdentifierArgs + { + internal FormatNullElementIdentifierArgs(int elementIndex) + { + ElementIndex = elementIndex; + } + + public int ElementIndex { get; } + } +} diff --git a/ObjectsComparer/ObjectsComparer/ListComparisonSettings.cs b/ObjectsComparer/ObjectsComparer/ListComparisonSettings.cs index aae63d5..4665b61 100644 --- a/ObjectsComparer/ObjectsComparer/ListComparisonSettings.cs +++ b/ObjectsComparer/ObjectsComparer/ListComparisonSettings.cs @@ -16,7 +16,7 @@ public class ListComparisonSettings internal static ListComparisonSettings Default() => new ListComparisonSettings(); /// - /// Configures list comparison behavior, see . + /// Configures list comparison behavior. See . /// /// First parameter: Current list comparison context. public void Configure(Action configureOptions) @@ -30,7 +30,7 @@ public void Configure(Action config } /// - /// Configures list comparison behavior, see . + /// Configures list comparison behavior. See . /// /// See . public void Configure(Action configureOptions) From bd36eb6cb91693d07a814728e2e7302963806ec9 Mon Sep 17 00:00:00 2001 From: "ASD\\nemec" Date: Tue, 9 Nov 2021 13:51:40 +0100 Subject: [PATCH 062/181] Replace ComparisonSettings.List property. Replace ComparisonSettings.List property with ConfigureList operation. Delete List property. --- .../Comparer_GenericEnumerableTests.cs | 60 +++++++------ .../Comparer_MultidimensionalArraysTests.cs | 84 +------------------ .../Comparer_NonGenericEnumerableTests.cs | 16 ++-- .../ComparisonSettingsTests.cs | 32 +++---- .../CompareListElementsByKeyOptions.cs | 2 +- .../ObjectsComparer/ComparisonSettings.cs | 32 +++++-- .../CustomComparers/EnumerablesComparer.cs | 2 +- .../EnumerablesComparerBase.cs | 6 +- .../CustomComparers/EnumerablesComparer~1.cs | 2 +- 9 files changed, 87 insertions(+), 149 deletions(-) diff --git a/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs b/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs index e5ada64..dc7b4b8 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs @@ -30,10 +30,8 @@ public void ValueTypeArrayEquality_CompareByKey() var a2 = new A { IntArray = new[] { 1, 2 } }; var settings = new ComparisonSettings(); - settings.List.Configure(listOptions => - { - listOptions.CompareElementsByKey(opt => opt.UseKey("MyKey")); - }); + + settings.ConfigureList(listOptions => listOptions.CompareElementsByKey(opt => opt.UseKey("MyKey"))); var comparer = new Comparer(settings); @@ -65,7 +63,7 @@ public void PrimitiveTypeArrayInequalityCount_CompareUnequalLists() var a2 = new A { IntArray = new[] { 1, 2, 3 } }; var settings = new ComparisonSettings(); - settings.List.Configure(listOptions => listOptions.WithUnequalLists(true)); + settings.ConfigureList(listOptions => listOptions.WithUnequalLists(true)); var comparer = new Comparer(settings); var rootCtx = ComparisonContext.CreateRoot(); @@ -111,7 +109,7 @@ public void PrimitiveTypeArrayInequalityMember_CompareByKey() var a2 = new A { IntArray = new[] { 1, 3 } }; var settings = new ComparisonSettings(); - settings.List.Configure(listOptions => listOptions.CompareElementsByKey()); + settings.ConfigureList(listOptions => listOptions.CompareElementsByKey()); var comparer = new Comparer(settings); @@ -139,7 +137,7 @@ public void PrimitiveTypeArrayInequalityMember_CompareByKey_FormatKey() var a2 = new A { IntArray = new[] { 1, 3 } }; var settings = new ComparisonSettings(); - settings.List.Configure(listOptions => + settings.ConfigureList(listOptions => { listOptions.CompareElementsByKey(keyOptions => keyOptions.FormatElementKey(args => $"Key={args.ElementKey}")); }); @@ -185,7 +183,7 @@ public void PrimitiveTypeArrayInequalityFirstNull_CompareBykey() var a1 = new A(); var a2 = new A { IntArray = new int[0] }; var settings = new ComparisonSettings(); - settings.List.Configure(listOptions => listOptions.CompareElementsByKey()); + settings.ConfigureList(listOptions => listOptions.CompareElementsByKey()); var comparer = new Comparer(settings); @@ -220,7 +218,7 @@ public void PrimitiveTypeArrayInequalitySecondNull_CompareByKey() var a2 = new A(); var settings = new ComparisonSettings(); - settings.List.Configure(listOptions => listOptions.CompareElementsByKey()); + settings.ConfigureList(listOptions => listOptions.CompareElementsByKey()); var comparer = new Comparer(settings); @@ -251,7 +249,7 @@ public void ClassArrayEquality_ComareByKey_Throw_ElementKeyNotFoundException() var a2 = new A { ArrayOfB = new[] { new B { Property1 = "Str1" }, new B { Property1 = "Str2" } } }; var settings = new ComparisonSettings(); - settings.List.Configure(listOptions => listOptions.CompareElementsByKey()); + settings.ConfigureList(listOptions => listOptions.CompareElementsByKey()); var comparer = new Comparer(settings); @@ -268,7 +266,7 @@ public void ClassArrayEquality_ComareByKey_DoesNotThrow_ElementKeyNotFoundExcept var a2 = new A { ArrayOfB = new[] { new B { Property1 = "Str1" }, new B { Property1 = "Str2" } } }; var settings = new ComparisonSettings(); - settings.List.Configure(listOptions => listOptions.CompareElementsByKey(keyOptions => keyOptions.ThrowKeyNotFoundEnabled = false)); + settings.ConfigureList(listOptions => listOptions.CompareElementsByKey(keyOptions => keyOptions.ThrowKeyNotFoundEnabled = false)); var comparer = new Comparer(settings); bool isEqual = false; @@ -304,7 +302,7 @@ public void ClassArrayInequalityCount_CompareByKey_DoesNotThrow_ElementKeyNotFou var a2 = new A { ArrayOfB = new[] { new B { Property1 = "Str1" }, new B { Property1 = "Str2" } } }; var settings = new ComparisonSettings(); - settings.List.Configure(listOptions => listOptions.WithUnequalLists(true).CompareElementsByKey(keyOptions => keyOptions.ThrowKeyNotFoundEnabled = false)); + settings.ConfigureList(listOptions => listOptions.WithUnequalLists(true).CompareElementsByKey(keyOptions => keyOptions.ThrowKeyNotFoundEnabled = false)); var comparer = new Comparer(settings); @@ -326,7 +324,7 @@ public void ClassArrayInequalityCount_CompareUnequalLists() var a2 = new A { ArrayOfB = new[] { new B { Property1 = "Str1" }, new B { Property1 = "Str2" } } }; var settings = new ComparisonSettings(); - settings.List.Configure(listOptions => listOptions.WithUnequalLists(true)); + settings.ConfigureList(listOptions => listOptions.WithUnequalLists(true)); var comparer = new Comparer(settings); @@ -367,7 +365,7 @@ public void ClassArrayInequalityProperty_CompareByKey() var a2 = new A { ArrayOfB = new[] { new B { Property1 = "Str1", Id = 2 }, new B { Property1 = "Str3", Id = 1 } } }; var settings = new ComparisonSettings(); - settings.List.Configure(listOptions => listOptions.CompareElementsByKey()); + settings.ConfigureList(listOptions => listOptions.CompareElementsByKey()); var comparer = new Comparer(settings); @@ -386,7 +384,7 @@ public void ClassArrayInequalityProperty_CompareByKey_FormatKey() var a2 = new A { ArrayOfB = new[] { new B { Property1 = "Str1", Id = 1 }, new B { Property1 = "Str3", Id = 2 } } }; var settings = new ComparisonSettings(); - settings.List.Configure(listOptions => listOptions.CompareElementsByKey(keyOptions => keyOptions.FormatElementKey(args => $"Id={args.ElementKey}"))); + settings.ConfigureList(listOptions => listOptions.CompareElementsByKey(keyOptions => keyOptions.FormatElementKey(args => $"Id={args.ElementKey}"))); var comparer = new Comparer(settings); @@ -417,7 +415,7 @@ public void CollectionEquality_CompareByKey() var a2 = new A { CollectionOfB = new Collection { new B { Property1 = "Str1", Id = 2 }, new B { Property1 = "Str2", Id = 1 } } }; var settings = new ComparisonSettings(); - settings.List.Configure(listOptions => listOptions.CompareElementsByKey()); + settings.ConfigureList(listOptions => listOptions.CompareElementsByKey()); var comparer = new Comparer(settings); @@ -450,7 +448,7 @@ public void CollectionInequalityCount_CompareUnequalLists() var a2 = new A { CollectionOfB = new Collection { new B { Property1 = "Str1" } } }; var settings = new ComparisonSettings(); - settings.List.Configure(listOptions => listOptions.WithUnequalLists(true)); + settings.ConfigureList(listOptions => listOptions.WithUnequalLists(true)); var comparer = new Comparer(settings); @@ -493,7 +491,7 @@ public void CollectionAndNullInequality_CompareByKey() var a2 = new A(); var settings = new ComparisonSettings(); - settings.List.Configure(listOptions => + settings.ConfigureList(listOptions => { listOptions.CompareElementsByKey(); }); @@ -532,7 +530,7 @@ public void NullAndCollectionInequality_CompareByKey() var a2 = new A { CollectionOfB = new Collection { new B { Property1 = "Str1" }, new B { Property1 = "Str2" } } }; var settings = new ComparisonSettings(); - settings.List.Configure(listOptions => + settings.ConfigureList(listOptions => { listOptions.CompareElementsByKey(); }); @@ -570,7 +568,7 @@ public void CollectionInequalityProperty_CompareByKey() var a2 = new A { CollectionOfB = new Collection { new B { Property1 = "Str1", Id = 2 }, new B { Property1 = "Str3", Id = 1 } } }; var settings = new ComparisonSettings(); - settings.List.Configure(listOptions => listOptions.CompareElementsByKey()); + settings.ConfigureList(listOptions => listOptions.CompareElementsByKey()); var comparer = new Comparer(settings); @@ -601,7 +599,7 @@ public void ClassImplementsCollectionEquality_CompareByKey() var a2 = new A { ClassImplementsCollectionOfB = new CollectionOfB { new B { Property1 = "Str1", Id = 1 }, new B { Property1 = "Str2", Id = 2 } } }; var settings = new ComparisonSettings(); - settings.List.Configure(listOptions => listOptions.CompareElementsByKey()); + settings.ConfigureList(listOptions => listOptions.CompareElementsByKey()); var comparer = new Comparer(settings); @@ -634,7 +632,7 @@ public void ClassImplementsCollectionInequalityCount_CompareUnequalLists() var a2 = new A { ClassImplementsCollectionOfB = new CollectionOfB { new B { Property1 = "Str1" } } }; var settings = new ComparisonSettings(); - settings.List.Configure(listOptions => listOptions.WithUnequalLists(true)); + settings.ConfigureList(listOptions => listOptions.WithUnequalLists(true)); var comparer = new Comparer(settings); @@ -661,7 +659,7 @@ public void ClassImplementsCollectionInequalityCount_CompareUnequalLists_Compare var a2 = new A { ClassImplementsCollectionOfB = new CollectionOfB { new B { Property1 = "Str1", Id = 1 } } }; var settings = new ComparisonSettings(); - settings.List.Configure(listOptions => listOptions.WithUnequalLists(true).CompareElementsByKey()); + settings.ConfigureList(listOptions => listOptions.WithUnequalLists(true).CompareElementsByKey()); var comparer = new Comparer(settings); @@ -703,7 +701,7 @@ public void ClassImplementsCollectionInequalityProperty_CompareByKey() var a2 = new A { ClassImplementsCollectionOfB = new CollectionOfB { new B { Property1 = "Str1", Id = 1 }, new B { Property1 = "Str3", Id = 2 } } }; var settings = new ComparisonSettings(); - settings.List.Configure(listOptions => listOptions.WithUnequalLists(true).CompareElementsByKey()); + settings.ConfigureList(listOptions => listOptions.WithUnequalLists(true).CompareElementsByKey()); var comparer = new Comparer(settings); @@ -816,7 +814,7 @@ public void CollectionOfBCountInequality1_CompareElementsByKey() }; var settings = new ComparisonSettings(); - settings.List.Configure(listOptions => listOptions.CompareElementsByKey()); + settings.ConfigureList(listOptions => listOptions.CompareElementsByKey()); var comparer = new Comparer(settings); @@ -845,7 +843,7 @@ public void CollectionOfBCountInequality1_CompareElementsByKey_CompareUnequalLis }; var settings = new ComparisonSettings(); - settings.List.Configure(listOptions => listOptions.WithUnequalLists(true).CompareElementsByKey()); + settings.ConfigureList(listOptions => listOptions.WithUnequalLists(true).CompareElementsByKey()); var comparer = new Comparer(settings); @@ -905,7 +903,7 @@ public void CollectionOfBCountInequality2_CompareByKey() }; var settings = new ComparisonSettings(); - settings.List.Configure(listOptions => listOptions.WithUnequalLists(true).CompareElementsByKey()); + settings.ConfigureList(listOptions => listOptions.WithUnequalLists(true).CompareElementsByKey()); var comparer = new Comparer(settings); var isEqual = comparer.Compare(a1, a2, out var differencesEnum); @@ -1047,7 +1045,7 @@ public void CompareAsIList_CompareUnequalLists() var list2 = new List { 1 }; var settings = new ComparisonSettings(); - settings.List.Configure(listOptions => listOptions.WithUnequalLists(true)); + settings.ConfigureList(listOptions => listOptions.WithUnequalLists(true)); var comparer = new Comparer>(settings); @@ -1072,7 +1070,7 @@ public void CompareAsIList_CompareUnequalLists_CompareElementsByKey() var list2 = new List { 1 }; var settings = new ComparisonSettings(); - settings.List.Configure(listOptions => listOptions.WithUnequalLists(true).CompareElementsByKey()); + settings.ConfigureList(listOptions => listOptions.WithUnequalLists(true).CompareElementsByKey()); var comparer = new Comparer>(settings); @@ -1097,7 +1095,7 @@ public void CompareAsIList_CompareUnequalLists_CompareElementsByKey_FormatKey() var list2 = new List { 1 }; var settings = new ComparisonSettings(); - settings.List.Configure(listOptions => + settings.ConfigureList(listOptions => { //DaN Fluent. //listOptions.CompareUnequalLists().CompareElementsByKey(keyOptions => keyOptions.FormatElementKey(elementKey => $"Key={elementKey}")); @@ -1154,7 +1152,7 @@ public void DictionaryEqualitySameOrder_CompareByKey() var a2 = new Dictionary { { 1, "One" }, { 2, "Two" } }; var settings = new ComparisonSettings(); - settings.List.Configure(listOptions => listOptions.CompareElementsByKey()); + settings.ConfigureList(listOptions => listOptions.CompareElementsByKey()); var comparer = new Comparer>(settings); diff --git a/ObjectsComparer/ObjectsComparer.Tests/Comparer_MultidimensionalArraysTests.cs b/ObjectsComparer/ObjectsComparer.Tests/Comparer_MultidimensionalArraysTests.cs index 5782600..3281b9c 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/Comparer_MultidimensionalArraysTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/Comparer_MultidimensionalArraysTests.cs @@ -24,89 +24,7 @@ public void IntOfIntInequality1() Assert.AreEqual("2", differences[0].Value1); Assert.AreEqual("3", differences[0].Value2); } - - [Test] - public void IntOfIntInequality1_CompareByKey() - { - var a = new A { ListOfB = new System.Collections.Generic.List { new B { Property1 = "p" } } }; - var test = a.ListOfB.Where(b => - { - a.ListOfB.Add(new B { }); - return true; - }).ToArray(); - - //??? - var a1 = new MultidimensionalArrays { IntOfInt = new[] { new[] { 1, 3 } } }; - var a2 = new MultidimensionalArrays { IntOfInt = new[] { new[] { 3, 1 } } }; - - var settings = new ComparisonSettings(); - - settings.List.Configure((ComparisonContext ctx, ListConfigurationOptions listOptions) => listOptions - .WithUnequalLists(true) - .CompareElementsByKey(keyOptions => - { - if (ctx.Member == null) - { - keyOptions.UseKey(args => args.Element.ToString()); - } - else - { - keyOptions.UseKey(args => $"100{args.Element}"); - } - })); - - settings.List.Configure(listOptions => - { - listOptions - .WithUnequalLists(true) - .CompareElementsByKey(); - }); - - settings.List.Configure((listCtx, listOptions) => - { - listOptions.CompareElementsByKey( - keyOptions => - { - keyOptions.UseKey("MyId"); - - keyOptions.FormatElementKey(formatElementKeyArgs => - { - if (listCtx.Ancestor == null) - { - return $"Key={formatElementKeyArgs.ElementKey}"; - } - - return "b"; - }); - - if (listCtx.Member.Name == "IntOfInt") - { - keyOptions.UseKey(keyProviderArgs => - { - if (true) - { - //return keyProviderArgs.DefaulKeyProvider(keyProviderArgs.Element); - } - var c = listCtx; - return "1"; - }); - } - else - { - keyOptions.UseKey("Key"); - } - }); - }); - - var comparer = new Comparer(settings); - - var isEqual = comparer.Compare(a1, a2, out var differencesEnum); - var differences = differencesEnum.ToList(); - - Assert.IsTrue(isEqual); - CollectionAssert.IsEmpty(differences); - } - + [Test] public void IntOfIntInequality2() { diff --git a/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs b/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs index 0ce7b34..a5d660c 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs @@ -35,7 +35,7 @@ public void Equality_CompareByKey() var a2 = new A { NonGenericEnumerable = new ArrayList { new B { Property1 = "Str1" }, new B { Property1 = "Str2" } } }; var settings = new ComparisonSettings(); - settings.List.Configure(listOptions => listOptions.CompareElementsByKey(keyOptions => keyOptions.UseKey("Property1"))); + settings.ConfigureList(listOptions => listOptions.CompareElementsByKey(keyOptions => keyOptions.UseKey("Property1"))); var comparer = new Comparer(settings); var isEqual = comparer.Compare(a1, a2); @@ -66,7 +66,7 @@ public void InequalityCount_CompareUnequalLists() var a2 = new A { NonGenericEnumerable = new ArrayList { new B { Property1 = "Str1" } } }; var settings = new ComparisonSettings(); - settings.List.Configure(listOptions => listOptions.WithUnequalLists(true)); + settings.ConfigureList(listOptions => listOptions.WithUnequalLists(true)); var comparer = new Comparer(settings); var differences = comparer.CalculateDifferences(a1, a2).ToList(); @@ -91,7 +91,7 @@ public void InequalityCount_CompareUnequalLists_CompareByKey() var a2 = new A { NonGenericEnumerable = new ArrayList { new B { Property1 = "Str1" } } }; var settings = new ComparisonSettings(); - settings.List.Configure(listOptions => + settings.ConfigureList(listOptions => { listOptions.WithUnequalLists(true); listOptions.CompareElementsByKey(keyOptions => @@ -124,7 +124,7 @@ public void InequalityCount_CompareUnequalLists_CompareByKey_DontFormatKey() var a2 = new A { NonGenericEnumerable = new ArrayList { new B { Property1 = "Str1" } } }; var settings = new ComparisonSettings(); - settings.List.Configure(listOptions => listOptions.WithUnequalLists(true).CompareElementsByKey(keyOptions => keyOptions.UseKey("Property1"))); + settings.ConfigureList(listOptions => listOptions.WithUnequalLists(true).CompareElementsByKey(keyOptions => keyOptions.UseKey("Property1"))); var comparer = new Comparer(settings); @@ -165,7 +165,7 @@ public void InequalityProperty_CompareByKey() var a2 = new A { NonGenericEnumerable = new ArrayList { new B { Property1 = "Str3", Id = 2 }, new B { Property1 = "Str1", Id = 1 } } }; var settings = new ComparisonSettings(); - settings.List.Configure(listOptions => listOptions.CompareElementsByKey()); + settings.ConfigureList(listOptions => listOptions.CompareElementsByKey()); var comparer = new Comparer(settings); @@ -202,7 +202,7 @@ public void NullElementsEquality_CompareUnequalLists() var a2 = new A { NonGenericEnumerable = new ArrayList { null, null } }; var settings = new ComparisonSettings(); - settings.List.Configure(listOptions => listOptions.WithUnequalLists(true)); + settings.ConfigureList(listOptions => listOptions.WithUnequalLists(true)); var comparer = new Comparer(settings); var isEqual = comparer.Compare(a1, a2, out var diffs); @@ -225,7 +225,7 @@ public void NullElementsEquality_CompareUnequalLists_CompareByKey() var a2 = new A { NonGenericEnumerable = new ArrayList { null, null } }; var settings = new ComparisonSettings(); - settings.List.Configure(listOptions => listOptions.WithUnequalLists(true).CompareElementsByKey()); + settings.ConfigureList(listOptions => listOptions.WithUnequalLists(true).CompareElementsByKey()); var comparer = new Comparer(settings); var isEqual = comparer.Compare(a1, a2, out var diffs); @@ -263,7 +263,7 @@ public void NullAndNotNullElementsInequality_CompareByKey() var a2 = new A { NonGenericEnumerable = new ArrayList { "Str2", null } }; var settings = new ComparisonSettings(); - settings.List.Configure(listOptions => + settings.ConfigureList(listOptions => { listOptions.CompareElementsByKey(); }); diff --git a/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs b/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs index 3e2bc93..fe9b066 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs @@ -62,7 +62,7 @@ public void CompareListElementsByKeyIsCorrectlySet() //Client side. var settings = new ComparisonSettings(); - settings.List.Configure((comparisonContext, listOptions) => + settings.ConfigureList((comparisonContext, listOptions) => { listOptions.WithUnequalLists(true); @@ -76,7 +76,7 @@ public void CompareListElementsByKeyIsCorrectlySet() //Component side. var listConfigurationOptions = ListConfigurationOptions.Default(); var ctx = ComparisonContext.Create(); - settings.List.ConfigureOptionsAction(ctx, listConfigurationOptions); + settings.ConfigureOptionsAction(ctx, listConfigurationOptions); var compareElementsByKeyOptions = CompareListElementsByKeyOptions.Default(); listConfigurationOptions.KeyOptionsAction(compareElementsByKeyOptions); @@ -104,7 +104,7 @@ public void FluentTest_WithUnequalLists() var a2 = new int[] { 1, 2, 3, 4 }; var settings = new ComparisonSettings(); - settings.List.Configure(listOptions => listOptions.WithUnequalLists(true)); + settings.ConfigureList(listOptions => listOptions.WithUnequalLists(true)); var comparer = new Comparer(settings); var differences = comparer.CalculateDifferences(a1, a2).ToList(); @@ -139,7 +139,7 @@ public void FluentTest_WithUnequalLists_CompareElementsByKey() var a2 = new int[] { 1, 2, 3, 4 }; var settings = new ComparisonSettings(); - settings.List.Configure(listOptions => listOptions.WithUnequalLists(true).CompareElementsByKey()); + settings.ConfigureList(listOptions => listOptions.WithUnequalLists(true).CompareElementsByKey()); var comparer = new Comparer(settings); var differences = comparer.CalculateDifferences(a1, a2).ToList(); @@ -164,7 +164,7 @@ public void FluentTest_WithUnequalLists_CompareElementsByKey_FormatKey() var a2 = new int[] { 1, 2, 3, 4 }; var settings = new ComparisonSettings(); - settings.List.Configure(listOptions => listOptions + settings.ConfigureList(listOptions => listOptions .WithUnequalLists(true) .CompareElementsByKey(keyOptions => keyOptions.FormatElementKey(args => $"Key={args.ElementKey}"))); @@ -191,7 +191,7 @@ public void FluentTest_WithUnequalLists_CompareElementsByKey_FormatKey_DefaultNu var a2 = new int?[] { 1, 2, 3, 4, null }; var settings = new ComparisonSettings(); - settings.List.Configure(listOptions => listOptions + settings.ConfigureList(listOptions => listOptions .WithUnequalLists(true) .CompareElementsByKey(keyOptions => keyOptions.FormatElementKey(args => $"Key={args.ElementKey}"))); @@ -223,7 +223,7 @@ public void FluentTest_WithUnequalLists_CompareElementsByKey_FormatKey_FormatNul var a2 = new int?[] { 1, 2, 3, 4, null }; var settings = new ComparisonSettings(); - settings.List.Configure(listOptions => listOptions + settings.ConfigureList(listOptions => listOptions .WithUnequalLists(true) .CompareElementsByKey(keyOptions => keyOptions .FormatElementKey(formatArgs => $"Key={formatArgs.ElementKey}") @@ -232,7 +232,7 @@ public void FluentTest_WithUnequalLists_CompareElementsByKey_FormatKey_FormatNul var comparer = new Comparer(settings); //settings = new ComparisonSettings(); - //settings.List.Configure(listOptions => + //settings.ConfigureList(listOptions => //{ // listOptions.WithUnequalLists(true); @@ -244,7 +244,7 @@ public void FluentTest_WithUnequalLists_CompareElementsByKey_FormatKey_FormatNul //}); //settings = new ComparisonSettings(); - //settings.List.Configure((ctx, listOptions) => + //settings.ConfigureList((ctx, listOptions) => //{ // bool unequalEnabled = ctx.Member.Name == "List1"; // listOptions.WithUnequalLists(unequalEnabled); @@ -296,21 +296,21 @@ public void FluentTest_List() var a2 = new List { 1, 2, 3, 4 }; var settings = new ComparisonSettings(); - settings.List.Configure(listOptions => listOptions.WithUnequalLists(true).CompareElementsByKey()); + settings.ConfigureList(listOptions => listOptions.WithUnequalLists(true).CompareElementsByKey()); var comparer = new Comparer(settings); var differences = comparer.CalculateDifferences(a1, a2).ToList(); Assert.AreEqual(2, differences.Count); - Assert.AreEqual(DifferenceTypes.MissedElementInFirstObject, differences[0].DifferenceType); - Assert.AreEqual("[4]", differences[0].MemberPath); - Assert.AreEqual("", differences[0].Value1); + Assert.AreEqual(DifferenceTypes.NumberOfElementsMismatch, differences[0].DifferenceType); + Assert.AreEqual("", differences[0].MemberPath); + Assert.AreEqual("3", differences[0].Value1); Assert.AreEqual("4", differences[0].Value2); - Assert.AreEqual(DifferenceTypes.ValueMismatch, differences[1].DifferenceType); - Assert.AreEqual("Length", differences[1].MemberPath); - Assert.AreEqual("3", differences[1].Value1); + Assert.AreEqual(DifferenceTypes.MissedElementInFirstObject, differences[1].DifferenceType); + Assert.AreEqual("[4]", differences[1].MemberPath); + Assert.AreEqual("", differences[1].Value1); Assert.AreEqual("4", differences[1].Value2); } } diff --git a/ObjectsComparer/ObjectsComparer/CompareListElementsByKeyOptions.cs b/ObjectsComparer/ObjectsComparer/CompareListElementsByKeyOptions.cs index 37daa98..041d87d 100644 --- a/ObjectsComparer/ObjectsComparer/CompareListElementsByKeyOptions.cs +++ b/ObjectsComparer/ObjectsComparer/CompareListElementsByKeyOptions.cs @@ -190,7 +190,7 @@ internal string GetNullElementIdentifier(FormatNullElementIdentifierArgs args) if (string.IsNullOrWhiteSpace(elementIdentifier)) { - elementIdentifier = string.Format(DefaultNullElementIdentifierTemplate, args); + elementIdentifier = string.Format(DefaultNullElementIdentifierTemplate, args.ElementIndex); } return elementIdentifier.Left(NullElementIdentifierMaxLength); diff --git a/ObjectsComparer/ObjectsComparer/ComparisonSettings.cs b/ObjectsComparer/ObjectsComparer/ComparisonSettings.cs index 9a9b159..c7a0f0c 100644 --- a/ObjectsComparer/ObjectsComparer/ComparisonSettings.cs +++ b/ObjectsComparer/ObjectsComparer/ComparisonSettings.cs @@ -27,11 +27,6 @@ public class ComparisonSettings private readonly Dictionary, object> _settings = new Dictionary, object>(); - /// - /// List comparison settings. - /// - public ListComparisonSettings List { get; } = ListComparisonSettings.Default(); - /// /// Initializes a new instance of the class. /// @@ -71,5 +66,32 @@ public T GetCustomSetting(string key = null) throw new KeyNotFoundException(); } + + internal Action ConfigureOptionsAction { get; private set; } = null; + + /// + /// Configures list comparison behavior, especially the type of comparison. See . + /// + /// First parameter: Current list comparison context. + public ComparisonSettings ConfigureList(Action configureOptions) + { + if (configureOptions is null) + { + throw new ArgumentNullException(nameof(configureOptions)); + } + + ConfigureOptionsAction = configureOptions; + + return this; + } + + /// + /// Configures list comparison behavior, especially the type of comparison.. See . + /// + /// See . + public ComparisonSettings ConfigureList(Action configureOptions) + { + return ConfigureList((_, options) => configureOptions(options)); + } } } diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs index ebfdfd9..93ac723 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs @@ -58,7 +58,7 @@ public IEnumerable CalculateDifferences(Type type, object obj1, obje var array2 = ((IEnumerable)obj2).Cast().ToArray(); var listConfigurationOptions = ListConfigurationOptions.Default(); - Settings.List.ConfigureOptionsAction?.Invoke(listComparisonContext, listConfigurationOptions); + Settings.ConfigureOptionsAction?.Invoke(listComparisonContext, listConfigurationOptions); if (array1.Length != array2.Length) { diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparerBase.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparerBase.cs index f73e2e8..6845ebe 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparerBase.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparerBase.cs @@ -73,9 +73,9 @@ protected virtual IEnumerable CalculateDifferencesByKey(IList var formattedElement1Key = keyOptions.GetFormattedElementKey(new FormatListElementKeyArgs(element1Index, element1Key, element1)); - if (array2.Any(elm2 => object.Equals(element1Key, keyOptions.KeyProviderAction(new ListElementKeyProviderArgs(elm2))))) + if (array2.Any(elm2 => elm2 != null && object.Equals(element1Key, keyOptions.KeyProviderAction(new ListElementKeyProviderArgs(elm2))))) { - var element2 = array2.First(elm2 => object.Equals(element1Key, keyOptions.KeyProviderAction(new ListElementKeyProviderArgs(elm2)))); + var element2 = array2.First(elm2 => elm2 != null && object.Equals(element1Key, keyOptions.KeyProviderAction(new ListElementKeyProviderArgs(elm2)))); var comparer = Factory.GetObjectsComparer(element1.GetType(), Settings, this); foreach (var failure in comparer.CalculateDifferences(element1.GetType(), element1, element2, elementComparisonContext)) @@ -120,7 +120,7 @@ protected virtual IEnumerable CalculateDifferencesByKey(IList continue; } - if (array1.Any(elm1 => object.Equals(element2Key, keyOptions.KeyProviderAction(new ListElementKeyProviderArgs(elm1)))) == false) + if (array1.Any(elm1 => elm1 != null && object.Equals(element2Key, keyOptions.KeyProviderAction(new ListElementKeyProviderArgs(elm1)))) == false) { var formattedElement2Key = keyOptions.GetFormattedElementKey(new FormatListElementKeyArgs(element2Index, element2Key, element2)); var valueComparer2 = OverridesCollection.GetComparer(element2.GetType()) ?? DefaultValueComparer; diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer~1.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer~1.cs index c88f356..0dfd07a 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer~1.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer~1.cs @@ -58,7 +58,7 @@ public IEnumerable CalculateDifferences(Type type, object obj1, obje var list2 = ((IEnumerable)obj2).ToList(); var listConfigurationOptions = ListConfigurationOptions.Default(); - Settings.List.ConfigureOptionsAction?.Invoke(listComparisonContext, listConfigurationOptions); + Settings.ConfigureOptionsAction?.Invoke(listComparisonContext, listConfigurationOptions); if (list1.Count != list2.Count) { From a07498d58b91e960a134bed5da96e7108be4ba6d Mon Sep 17 00:00:00 2001 From: "ASD\\nemec" Date: Tue, 9 Nov 2021 14:19:59 +0100 Subject: [PATCH 063/181] Replace ThrowKeyNotFoundEnabled with ThrowKeyNotFound. --- .../Comparer_GenericEnumerableTests.cs | 6 ++++-- .../ObjectsComparer.Tests/ComparisonSettingsTests.cs | 2 +- .../Exceptions/ElementKeyNotFoundException.cs | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs b/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs index dc7b4b8..2bc93a5 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs @@ -266,7 +266,7 @@ public void ClassArrayEquality_ComareByKey_DoesNotThrow_ElementKeyNotFoundExcept var a2 = new A { ArrayOfB = new[] { new B { Property1 = "Str1" }, new B { Property1 = "Str2" } } }; var settings = new ComparisonSettings(); - settings.ConfigureList(listOptions => listOptions.CompareElementsByKey(keyOptions => keyOptions.ThrowKeyNotFoundEnabled = false)); + settings.ConfigureList(listOptions => listOptions.CompareElementsByKey(keyOptions => keyOptions.ThrowKeyNotFound(false))); var comparer = new Comparer(settings); bool isEqual = false; @@ -302,7 +302,9 @@ public void ClassArrayInequalityCount_CompareByKey_DoesNotThrow_ElementKeyNotFou var a2 = new A { ArrayOfB = new[] { new B { Property1 = "Str1" }, new B { Property1 = "Str2" } } }; var settings = new ComparisonSettings(); - settings.ConfigureList(listOptions => listOptions.WithUnequalLists(true).CompareElementsByKey(keyOptions => keyOptions.ThrowKeyNotFoundEnabled = false)); + settings.ConfigureList(listOptions => listOptions + .WithUnequalLists(true) + .CompareElementsByKey(keyOptions => keyOptions.ThrowKeyNotFound(false))); var comparer = new Comparer(settings); diff --git a/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs b/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs index fe9b066..59bc43e 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs @@ -69,7 +69,7 @@ public void CompareListElementsByKeyIsCorrectlySet() listOptions.CompareElementsByKey(keyOptions => { keyOptions.UseKey("Key"); - keyOptions.ThrowKeyNotFoundEnabled = false; + keyOptions.ThrowKeyNotFound(false); }); }); diff --git a/ObjectsComparer/ObjectsComparer/Exceptions/ElementKeyNotFoundException.cs b/ObjectsComparer/ObjectsComparer/Exceptions/ElementKeyNotFoundException.cs index 816b188..d8f8334 100644 --- a/ObjectsComparer/ObjectsComparer/Exceptions/ElementKeyNotFoundException.cs +++ b/ObjectsComparer/ObjectsComparer/Exceptions/ElementKeyNotFoundException.cs @@ -5,7 +5,7 @@ namespace ObjectsComparer.Exceptions { /// - /// Depending on the configuration, the exception is thrown if the key provider does not supply the key for list element . For more information see and . + /// Depending on the configuration, the exception is thrown if the key provider does not supply the key for list element . For more information see and . /// public class ElementKeyNotFoundException : Exception { From f97f5cd7ba3e5c0af640be4d90faa4a95648bd39 Mon Sep 17 00:00:00 2001 From: nemec Date: Wed, 10 Nov 2021 19:49:48 +0100 Subject: [PATCH 064/181] Delete ListComparisonSettings class. --- .../ObjectsComparer/ListComparisonSettings.cs | 46 ------------------- 1 file changed, 46 deletions(-) delete mode 100644 ObjectsComparer/ObjectsComparer/ListComparisonSettings.cs diff --git a/ObjectsComparer/ObjectsComparer/ListComparisonSettings.cs b/ObjectsComparer/ObjectsComparer/ListComparisonSettings.cs deleted file mode 100644 index 4665b61..0000000 --- a/ObjectsComparer/ObjectsComparer/ListComparisonSettings.cs +++ /dev/null @@ -1,46 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace ObjectsComparer -{ - /// - /// List comparison settings. - /// - public class ListComparisonSettings - { - ListComparisonSettings() { } - - internal Action ConfigureOptionsAction { get; private set; } = null; - - internal static ListComparisonSettings Default() => new ListComparisonSettings(); - - /// - /// Configures list comparison behavior. See . - /// - /// First parameter: Current list comparison context. - public void Configure(Action configureOptions) - { - if (configureOptions is null) - { - throw new ArgumentNullException(nameof(configureOptions)); - } - - ConfigureOptionsAction = configureOptions; - } - - /// - /// Configures list comparison behavior. See . - /// - /// See . - public void Configure(Action configureOptions) - { - if (configureOptions is null) - { - throw new ArgumentNullException(nameof(configureOptions)); - } - - ConfigureOptionsAction = (_, opt) => configureOptions(opt); - } - } -} From 7161546be9d2b13801b27f02011e62a8de7b43f1 Mon Sep 17 00:00:00 2001 From: nemec Date: Thu, 11 Nov 2021 05:27:55 +0100 Subject: [PATCH 065/181] ListConfigurationOptions: Rename WithUnequalLists. --- .../Comparer_GenericEnumerableTests.cs | 24 +++++++++---------- .../Comparer_NonGenericEnumerableTests.cs | 10 ++++---- .../ComparisonSettingsTests.cs | 14 +++++------ .../ListConfigurationOptions.cs | 6 ++--- 4 files changed, 27 insertions(+), 27 deletions(-) diff --git a/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs b/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs index 2bc93a5..acf776a 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs @@ -63,7 +63,7 @@ public void PrimitiveTypeArrayInequalityCount_CompareUnequalLists() var a2 = new A { IntArray = new[] { 1, 2, 3 } }; var settings = new ComparisonSettings(); - settings.ConfigureList(listOptions => listOptions.WithUnequalLists(true)); + settings.ConfigureList(listOptions => listOptions.CompareUnequalLists(true)); var comparer = new Comparer(settings); var rootCtx = ComparisonContext.CreateRoot(); @@ -303,7 +303,7 @@ public void ClassArrayInequalityCount_CompareByKey_DoesNotThrow_ElementKeyNotFou var settings = new ComparisonSettings(); settings.ConfigureList(listOptions => listOptions - .WithUnequalLists(true) + .CompareUnequalLists(true) .CompareElementsByKey(keyOptions => keyOptions.ThrowKeyNotFound(false))); var comparer = new Comparer(settings); @@ -326,7 +326,7 @@ public void ClassArrayInequalityCount_CompareUnequalLists() var a2 = new A { ArrayOfB = new[] { new B { Property1 = "Str1" }, new B { Property1 = "Str2" } } }; var settings = new ComparisonSettings(); - settings.ConfigureList(listOptions => listOptions.WithUnequalLists(true)); + settings.ConfigureList(listOptions => listOptions.CompareUnequalLists(true)); var comparer = new Comparer(settings); @@ -450,7 +450,7 @@ public void CollectionInequalityCount_CompareUnequalLists() var a2 = new A { CollectionOfB = new Collection { new B { Property1 = "Str1" } } }; var settings = new ComparisonSettings(); - settings.ConfigureList(listOptions => listOptions.WithUnequalLists(true)); + settings.ConfigureList(listOptions => listOptions.CompareUnequalLists(true)); var comparer = new Comparer(settings); @@ -634,7 +634,7 @@ public void ClassImplementsCollectionInequalityCount_CompareUnequalLists() var a2 = new A { ClassImplementsCollectionOfB = new CollectionOfB { new B { Property1 = "Str1" } } }; var settings = new ComparisonSettings(); - settings.ConfigureList(listOptions => listOptions.WithUnequalLists(true)); + settings.ConfigureList(listOptions => listOptions.CompareUnequalLists(true)); var comparer = new Comparer(settings); @@ -661,7 +661,7 @@ public void ClassImplementsCollectionInequalityCount_CompareUnequalLists_Compare var a2 = new A { ClassImplementsCollectionOfB = new CollectionOfB { new B { Property1 = "Str1", Id = 1 } } }; var settings = new ComparisonSettings(); - settings.ConfigureList(listOptions => listOptions.WithUnequalLists(true).CompareElementsByKey()); + settings.ConfigureList(listOptions => listOptions.CompareUnequalLists(true).CompareElementsByKey()); var comparer = new Comparer(settings); @@ -703,7 +703,7 @@ public void ClassImplementsCollectionInequalityProperty_CompareByKey() var a2 = new A { ClassImplementsCollectionOfB = new CollectionOfB { new B { Property1 = "Str1", Id = 1 }, new B { Property1 = "Str3", Id = 2 } } }; var settings = new ComparisonSettings(); - settings.ConfigureList(listOptions => listOptions.WithUnequalLists(true).CompareElementsByKey()); + settings.ConfigureList(listOptions => listOptions.CompareUnequalLists(true).CompareElementsByKey()); var comparer = new Comparer(settings); @@ -845,7 +845,7 @@ public void CollectionOfBCountInequality1_CompareElementsByKey_CompareUnequalLis }; var settings = new ComparisonSettings(); - settings.ConfigureList(listOptions => listOptions.WithUnequalLists(true).CompareElementsByKey()); + settings.ConfigureList(listOptions => listOptions.CompareUnequalLists(true).CompareElementsByKey()); var comparer = new Comparer(settings); @@ -905,7 +905,7 @@ public void CollectionOfBCountInequality2_CompareByKey() }; var settings = new ComparisonSettings(); - settings.ConfigureList(listOptions => listOptions.WithUnequalLists(true).CompareElementsByKey()); + settings.ConfigureList(listOptions => listOptions.CompareUnequalLists(true).CompareElementsByKey()); var comparer = new Comparer(settings); var isEqual = comparer.Compare(a1, a2, out var differencesEnum); @@ -1047,7 +1047,7 @@ public void CompareAsIList_CompareUnequalLists() var list2 = new List { 1 }; var settings = new ComparisonSettings(); - settings.ConfigureList(listOptions => listOptions.WithUnequalLists(true)); + settings.ConfigureList(listOptions => listOptions.CompareUnequalLists(true)); var comparer = new Comparer>(settings); @@ -1072,7 +1072,7 @@ public void CompareAsIList_CompareUnequalLists_CompareElementsByKey() var list2 = new List { 1 }; var settings = new ComparisonSettings(); - settings.ConfigureList(listOptions => listOptions.WithUnequalLists(true).CompareElementsByKey()); + settings.ConfigureList(listOptions => listOptions.CompareUnequalLists(true).CompareElementsByKey()); var comparer = new Comparer>(settings); @@ -1108,7 +1108,7 @@ public void CompareAsIList_CompareUnequalLists_CompareElementsByKey_FormatKey() * .CompareElementsByKey(keyOptions => keyOptions.FormatElementKey(elementKey => $"Key={elementKey}")); */ - listOptions.WithUnequalLists(true); + listOptions.CompareUnequalLists(true); listOptions.CompareElementsByKey(keyOptions => { diff --git a/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs b/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs index a5d660c..f0a800d 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs @@ -66,7 +66,7 @@ public void InequalityCount_CompareUnequalLists() var a2 = new A { NonGenericEnumerable = new ArrayList { new B { Property1 = "Str1" } } }; var settings = new ComparisonSettings(); - settings.ConfigureList(listOptions => listOptions.WithUnequalLists(true)); + settings.ConfigureList(listOptions => listOptions.CompareUnequalLists(true)); var comparer = new Comparer(settings); var differences = comparer.CalculateDifferences(a1, a2).ToList(); @@ -93,7 +93,7 @@ public void InequalityCount_CompareUnequalLists_CompareByKey() var settings = new ComparisonSettings(); settings.ConfigureList(listOptions => { - listOptions.WithUnequalLists(true); + listOptions.CompareUnequalLists(true); listOptions.CompareElementsByKey(keyOptions => { keyOptions.UseKey("Property1"); @@ -124,7 +124,7 @@ public void InequalityCount_CompareUnequalLists_CompareByKey_DontFormatKey() var a2 = new A { NonGenericEnumerable = new ArrayList { new B { Property1 = "Str1" } } }; var settings = new ComparisonSettings(); - settings.ConfigureList(listOptions => listOptions.WithUnequalLists(true).CompareElementsByKey(keyOptions => keyOptions.UseKey("Property1"))); + settings.ConfigureList(listOptions => listOptions.CompareUnequalLists(true).CompareElementsByKey(keyOptions => keyOptions.UseKey("Property1"))); var comparer = new Comparer(settings); @@ -202,7 +202,7 @@ public void NullElementsEquality_CompareUnequalLists() var a2 = new A { NonGenericEnumerable = new ArrayList { null, null } }; var settings = new ComparisonSettings(); - settings.ConfigureList(listOptions => listOptions.WithUnequalLists(true)); + settings.ConfigureList(listOptions => listOptions.CompareUnequalLists(true)); var comparer = new Comparer(settings); var isEqual = comparer.Compare(a1, a2, out var diffs); @@ -225,7 +225,7 @@ public void NullElementsEquality_CompareUnequalLists_CompareByKey() var a2 = new A { NonGenericEnumerable = new ArrayList { null, null } }; var settings = new ComparisonSettings(); - settings.ConfigureList(listOptions => listOptions.WithUnequalLists(true).CompareElementsByKey()); + settings.ConfigureList(listOptions => listOptions.CompareUnequalLists(true).CompareElementsByKey()); var comparer = new Comparer(settings); var isEqual = comparer.Compare(a1, a2, out var diffs); diff --git a/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs b/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs index 59bc43e..3b5f99d 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs @@ -64,7 +64,7 @@ public void CompareListElementsByKeyIsCorrectlySet() settings.ConfigureList((comparisonContext, listOptions) => { - listOptions.WithUnequalLists(true); + listOptions.CompareUnequalLists(true); listOptions.CompareElementsByKey(keyOptions => { @@ -104,7 +104,7 @@ public void FluentTest_WithUnequalLists() var a2 = new int[] { 1, 2, 3, 4 }; var settings = new ComparisonSettings(); - settings.ConfigureList(listOptions => listOptions.WithUnequalLists(true)); + settings.ConfigureList(listOptions => listOptions.CompareUnequalLists(true)); var comparer = new Comparer(settings); var differences = comparer.CalculateDifferences(a1, a2).ToList(); @@ -139,7 +139,7 @@ public void FluentTest_WithUnequalLists_CompareElementsByKey() var a2 = new int[] { 1, 2, 3, 4 }; var settings = new ComparisonSettings(); - settings.ConfigureList(listOptions => listOptions.WithUnequalLists(true).CompareElementsByKey()); + settings.ConfigureList(listOptions => listOptions.CompareUnequalLists(true).CompareElementsByKey()); var comparer = new Comparer(settings); var differences = comparer.CalculateDifferences(a1, a2).ToList(); @@ -165,7 +165,7 @@ public void FluentTest_WithUnequalLists_CompareElementsByKey_FormatKey() var settings = new ComparisonSettings(); settings.ConfigureList(listOptions => listOptions - .WithUnequalLists(true) + .CompareUnequalLists(true) .CompareElementsByKey(keyOptions => keyOptions.FormatElementKey(args => $"Key={args.ElementKey}"))); var comparer = new Comparer(settings); @@ -192,7 +192,7 @@ public void FluentTest_WithUnequalLists_CompareElementsByKey_FormatKey_DefaultNu var settings = new ComparisonSettings(); settings.ConfigureList(listOptions => listOptions - .WithUnequalLists(true) + .CompareUnequalLists(true) .CompareElementsByKey(keyOptions => keyOptions.FormatElementKey(args => $"Key={args.ElementKey}"))); var comparer = new Comparer(settings); @@ -224,7 +224,7 @@ public void FluentTest_WithUnequalLists_CompareElementsByKey_FormatKey_FormatNul var settings = new ComparisonSettings(); settings.ConfigureList(listOptions => listOptions - .WithUnequalLists(true) + .CompareUnequalLists(true) .CompareElementsByKey(keyOptions => keyOptions .FormatElementKey(formatArgs => $"Key={formatArgs.ElementKey}") .FormatNullElementIdentifier(formatArgs => $"Null at {formatArgs.ElementIndex}"))); @@ -296,7 +296,7 @@ public void FluentTest_List() var a2 = new List { 1, 2, 3, 4 }; var settings = new ComparisonSettings(); - settings.ConfigureList(listOptions => listOptions.WithUnequalLists(true).CompareElementsByKey()); + settings.ConfigureList(listOptions => listOptions.CompareUnequalLists(true).CompareElementsByKey()); var comparer = new Comparer(settings); var differences = comparer.CalculateDifferences(a1, a2).ToList(); diff --git a/ObjectsComparer/ObjectsComparer/ListConfigurationOptions.cs b/ObjectsComparer/ObjectsComparer/ListConfigurationOptions.cs index fb431a6..cbfacf0 100644 --- a/ObjectsComparer/ObjectsComparer/ListConfigurationOptions.cs +++ b/ObjectsComparer/ObjectsComparer/ListConfigurationOptions.cs @@ -16,14 +16,14 @@ public class ListConfigurationOptions } /// - /// See . + /// See . /// internal bool UnequalListsComparisonEnabled { get; private set; } = false; /// - /// Whether to compare elements of the lists even if their number differs. Regardless of the , the respective difference of type will always be logged. Default value = false. + /// Whether to compare elements of the lists even if their number differs. Regardless of the , if lists are unequal, the difference of type will always be logged. Default value = false - unequal lists will not be compared. /// - public ListConfigurationOptions WithUnequalLists(bool value) + public ListConfigurationOptions CompareUnequalLists(bool value) { UnequalListsComparisonEnabled = value; From 7d7cb4b920363d9c9e5b83d07e84f55b31e5de12 Mon Sep 17 00:00:00 2001 From: nemec Date: Thu, 11 Nov 2021 05:31:10 +0100 Subject: [PATCH 066/181] Edit ComparisonSettingsTests. --- .../ComparisonSettingsTests.cs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs b/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs index 3b5f99d..a3cae13 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs @@ -98,7 +98,7 @@ public void ListComparisonConfigurationBackwardCompatibilityEnsured() } [Test] - public void FluentTest_WithUnequalLists() + public void FluentTest_CompareUnequalLists() { var a1 = new int[] { 3, 2, 1 }; var a2 = new int[] { 1, 2, 3, 4 }; @@ -133,7 +133,7 @@ public void FluentTest_WithUnequalLists() } [Test] - public void FluentTest_WithUnequalLists_CompareElementsByKey() + public void FluentTest_CompareUnequalLists_CompareElementsByKey() { var a1 = new int[] { 3, 2, 1 }; var a2 = new int[] { 1, 2, 3, 4 }; @@ -158,7 +158,7 @@ public void FluentTest_WithUnequalLists_CompareElementsByKey() } [Test] - public void FluentTest_WithUnequalLists_CompareElementsByKey_FormatKey() + public void FluentTest_CompareUnequalLists_CompareElementsByKey_FormatKey() { var a1 = new int[] { 3, 2, 1 }; var a2 = new int[] { 1, 2, 3, 4 }; @@ -185,7 +185,7 @@ public void FluentTest_WithUnequalLists_CompareElementsByKey_FormatKey() } [Test] - public void FluentTest_WithUnequalLists_CompareElementsByKey_FormatKey_DefaultNullElementIdentifier() + public void FluentTest_CompareUnequalLists_CompareElementsByKey_FormatKey_DefaultNullElementIdentifier() { var a1 = new int?[] { 3, 2, 1 }; var a2 = new int?[] { 1, 2, 3, 4, null }; @@ -217,7 +217,7 @@ public void FluentTest_WithUnequalLists_CompareElementsByKey_FormatKey_DefaultNu } [Test] - public void FluentTest_WithUnequalLists_CompareElementsByKey_FormatKey_FormatNullElementIdentifier() + public void FluentTest_CompareUnequalLists_CompareElementsByKey_FormatKey_FormatNullElementIdentifier() { var a1 = new int?[] { 3, 2, 1 }; var a2 = new int?[] { 1, 2, 3, 4, null }; @@ -234,7 +234,7 @@ public void FluentTest_WithUnequalLists_CompareElementsByKey_FormatKey_FormatNul //settings = new ComparisonSettings(); //settings.ConfigureList(listOptions => //{ - // listOptions.WithUnequalLists(true); + // listOptions.CompareUnequalLists(true); // listOptions.CompareElementsByKey(keyOptions => // { @@ -247,7 +247,7 @@ public void FluentTest_WithUnequalLists_CompareElementsByKey_FormatKey_FormatNul //settings.ConfigureList((ctx, listOptions) => //{ // bool unequalEnabled = ctx.Member.Name == "List1"; - // listOptions.WithUnequalLists(unequalEnabled); + // listOptions.CompareUnequalLists(unequalEnabled); // listOptions.CompareElementsByKey(keyOptions => // { From 783372099c5e70984f68b8b0aea52b03509695e7 Mon Sep 17 00:00:00 2001 From: "ASD\\nemec" Date: Thu, 11 Nov 2021 14:00:44 +0100 Subject: [PATCH 067/181] Edit ComparisonSettingsTests class. --- .../ComparisonSettingsTests.cs | 52 +++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs b/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs index a3cae13..6dad896 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs @@ -313,5 +313,57 @@ public void FluentTest_List() Assert.AreEqual("", differences[1].Value1); Assert.AreEqual("4", differences[1].Value2); } + + [Test] + public static void LambdaTest() + { + var game = new VariableCaptureGame(); + + int gameInput = 5; + game.Run(gameInput); + + int jTry = 10; + bool result = game.isEqualToCapturedLocalVariable(jTry); + Console.WriteLine($"Captured local variable is equal to {jTry}: {result}"); + + int anotherJ = 3; + game.updateCapturedLocalVariable(anotherJ); + + bool equalToAnother = game.isEqualToCapturedLocalVariable(anotherJ); + Console.WriteLine($"Another lambda observes a new value of captured variable: {equalToAnother}"); + } + // Output: + // Local variable before lambda invocation: 0 + // 10 is greater than 5: True + // Local variable after lambda invocation: 10 + // Captured local variable is equal to 10: True + // 3 is greater than 5: False + // Another lambda observes a new value of captured variable: True + + } + + public class VariableCaptureGame + { + internal Action updateCapturedLocalVariable; + internal Func isEqualToCapturedLocalVariable; + + + public void Run(int input) + { + int j = 0; + + updateCapturedLocalVariable = x => + { + j = x; + bool result = j > input; + Console.WriteLine($"{j} is greater than {input}: {result}"); + }; + + isEqualToCapturedLocalVariable = x => x == j; + + Console.WriteLine($"Local variable before lambda invocation: {j}"); + updateCapturedLocalVariable(10); + Console.WriteLine($"Local variable after lambda invocation: {j}"); + } } } From f81628a87e1f0796e6a0c5e0f017357611b3eab7 Mon Sep 17 00:00:00 2001 From: "ASD\\nemec" Date: Sun, 14 Nov 2021 09:25:39 +0100 Subject: [PATCH 068/181] Edit ComparerGenericEnumerableTests class. --- .../Comparer_GenericEnumerableTests.cs | 81 +++++++++++++++++++ 1 file changed, 81 insertions(+) diff --git a/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs b/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs index acf776a..6d07abe 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs @@ -1040,6 +1040,87 @@ public void CompareAsIList() Assert.AreEqual("1", differences.First().Value2); } + [Test] + public void PrimitiveTypeArray_CompareByKey_CompareUnequalLists_Ignore_Repeated_Elements() + { + var a1 = new A() { IntArray = new int[] { 1, 2 } }; + var a2 = new A() { IntArray = new int[] { 1, 2, 1, 2, 1, 2, 1, 2, 1, 2 } }; + + var settings = new ComparisonSettings(); + settings.ConfigureList(listOptions => listOptions.CompareElementsByKey().CompareUnequalLists(true)); + + var comparer = new Comparer(settings); + + var differences = comparer.CalculateDifferences(a1, a2).ToList(); + + Assert.IsTrue(differences.Count == 1); + Assert.AreEqual(DifferenceTypes.ValueMismatch, differences[0].DifferenceType); + Assert.AreEqual("IntArray.Length", differences[0].MemberPath); + Assert.AreEqual("2", differences[0].Value1); + Assert.AreEqual("10", differences[0].Value2); + } + + [Test] + public void PrimitiveTypeArray_CompareByIndex_CompareUnequalLists_Dont_Ignore_Repeated_Elements() + { + var a1 = new A() { IntArray = new int[] { 1, 2 } }; + var a2 = new A() { IntArray = new int[] { 1, 2, 1, 2, 1, 2, 1, 2, 1, 2 } }; + + var settings = new ComparisonSettings(); + settings.ConfigureList(listOptions => listOptions.CompareUnequalLists(true)); + + var comparer = new Comparer(settings); + + var differences = comparer.CalculateDifferences(a1, a2).ToList(); + + Assert.IsTrue(differences.Count == 9); + + Assert.AreEqual(DifferenceTypes.MissedElementInFirstObject, differences[0].DifferenceType); + Assert.AreEqual("IntArray[2]", differences[0].MemberPath); + Assert.AreEqual("", differences[0].Value1); + Assert.AreEqual("1", differences[0].Value2); + + Assert.AreEqual(DifferenceTypes.MissedElementInFirstObject, differences[1].DifferenceType); + Assert.AreEqual("IntArray[3]", differences[1].MemberPath); + Assert.AreEqual("", differences[1].Value1); + Assert.AreEqual("2", differences[1].Value2); + + Assert.AreEqual(DifferenceTypes.MissedElementInFirstObject, differences[2].DifferenceType); + Assert.AreEqual("IntArray[4]", differences[2].MemberPath); + Assert.AreEqual("", differences[2].Value1); + Assert.AreEqual("1", differences[2].Value2); + + Assert.AreEqual(DifferenceTypes.MissedElementInFirstObject, differences[3].DifferenceType); + Assert.AreEqual("IntArray[5]", differences[3].MemberPath); + Assert.AreEqual("", differences[3].Value1); + Assert.AreEqual("2", differences[3].Value2); + + Assert.AreEqual(DifferenceTypes.MissedElementInFirstObject, differences[4].DifferenceType); + Assert.AreEqual("IntArray[6]", differences[4].MemberPath); + Assert.AreEqual("", differences[4].Value1); + Assert.AreEqual("1", differences[4].Value2); + + Assert.AreEqual(DifferenceTypes.MissedElementInFirstObject, differences[5].DifferenceType); + Assert.AreEqual("IntArray[7]", differences[5].MemberPath); + Assert.AreEqual("", differences[5].Value1); + Assert.AreEqual("2", differences[5].Value2); + + Assert.AreEqual(DifferenceTypes.MissedElementInFirstObject, differences[6].DifferenceType); + Assert.AreEqual("IntArray[8]", differences[6].MemberPath); + Assert.AreEqual("", differences[6].Value1); + Assert.AreEqual("1", differences[6].Value2); + + Assert.AreEqual(DifferenceTypes.MissedElementInFirstObject, differences[7].DifferenceType); + Assert.AreEqual("IntArray[9]", differences[7].MemberPath); + Assert.AreEqual("", differences[7].Value1); + Assert.AreEqual("2", differences[7].Value2); + + Assert.AreEqual(DifferenceTypes.ValueMismatch, differences[8].DifferenceType); + Assert.AreEqual("IntArray.Length", differences[8].MemberPath); + Assert.AreEqual("2", differences[8].Value1); + Assert.AreEqual("10", differences[8].Value2); + } + [Test] public void CompareAsIList_CompareUnequalLists() { From 33c4ae93d979ef68fe539d64f5cee75e6ff36415 Mon Sep 17 00:00:00 2001 From: "ASD\\nemec" Date: Sun, 14 Nov 2021 18:13:07 +0100 Subject: [PATCH 069/181] Add DefaultKeyProvider. --- .../CompareListElementsByKeyOptions.cs | 29 ++++++++++++++----- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/ObjectsComparer/ObjectsComparer/CompareListElementsByKeyOptions.cs b/ObjectsComparer/ObjectsComparer/CompareListElementsByKeyOptions.cs index 041d87d..9c80b65 100644 --- a/ObjectsComparer/ObjectsComparer/CompareListElementsByKeyOptions.cs +++ b/ObjectsComparer/ObjectsComparer/CompareListElementsByKeyOptions.cs @@ -66,11 +66,23 @@ public CompareListElementsByKeyOptions ThrowKeyNotFound(bool value) /// internal Func KeyProviderAction { get; private set; } = null; + public Func DefaultKeyProvider { get; private set; } = args => + { + if (TryGetPropertyValue(args.Element, caseSensitive: false, out var keyValue, "Id", "Name")) + { + return keyValue; + } + + return args.Element; + + }; + internal static CompareListElementsByKeyOptions Default() => new CompareListElementsByKeyOptions(); void Initialize() { - UseKey(new string[] { "Id", "Name" }, caseSensitive: false); + KeyProviderAction = DefaultKeyProvider; + //UseKey(new string[] { "Id", "Name" }, caseSensitive: false); } /// @@ -108,7 +120,8 @@ public CompareListElementsByKeyOptions UseKey(string[] keys, bool caseSensitive return UseKey(args => { - return GetKeyValue(args.Element, caseSensitive, keys); + TryGetPropertyValue(args.Element, caseSensitive, out var propertyValue, keys); + return propertyValue; }); } @@ -129,10 +142,10 @@ public CompareListElementsByKeyOptions UseKey(Func - /// It will try to find one of the public properties specified by the parameter, then it returns its value. + /// It will try to find one of the public properties specified by the parameter, then it returns its value. /// /// Returns the value of the property that corresponds to the specified key. If no property matches the specified key, it returns the itself. - static object GetKeyValue(object instance, bool caseSensitive, params string[] keys) + static bool TryGetPropertyValue(object instance, bool caseSensitive, out object value, params string[] properties) { if (instance != null) { @@ -142,17 +155,19 @@ static object GetKeyValue(object instance, bool caseSensitive, params string[] k bindingAttr |= BindingFlags.IgnoreCase; } - foreach (var key in keys) + foreach (var key in properties) { var property = instance.GetType().GetTypeInfo().GetProperty(key, bindingAttr); if (property != null) { - return property.GetValue(instance); + value = property.GetValue(instance); + return true; } } } - return instance; + value = null; + return false; } /// From 636768e05fc4af2057a2d7dd3ef068499871148f Mon Sep 17 00:00:00 2001 From: "ASD\\nemec" Date: Mon, 15 Nov 2021 12:18:05 +0100 Subject: [PATCH 070/181] Implement DefaultElementKeyProviderAction key provider. --- .../Comparer_GenericEnumerableTests.cs | 23 +++++- .../Comparer_MultidimensionalArraysTests.cs | 24 +++++- .../CompareListElementsByKeyOptions.cs | 80 ++++++++++++++----- .../ListConfigurationOptions.cs | 2 +- 4 files changed, 104 insertions(+), 25 deletions(-) diff --git a/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs b/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs index 6d07abe..16a1d39 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using ObjectsComparer.Exceptions; using System; +using ObjectsComparer.Utils; namespace ObjectsComparer.Tests { @@ -31,7 +32,7 @@ public void ValueTypeArrayEquality_CompareByKey() var settings = new ComparisonSettings(); - settings.ConfigureList(listOptions => listOptions.CompareElementsByKey(opt => opt.UseKey("MyKey"))); + settings.ConfigureList(listOptions => listOptions.CompareElementsByKey()); var comparer = new Comparer(settings); @@ -1231,7 +1232,7 @@ public void DictionaryEqualitySameOrder() [Test] public void DictionaryEqualitySameOrder_CompareByKey() { - var a1 = new Dictionary { { 1, "One" }, { 2, "TwoXXX" } }; + var a1 = new Dictionary { { 1, "One" }, { 2, "Two" } }; var a2 = new Dictionary { { 1, "One" }, { 2, "Two" } }; var settings = new ComparisonSettings(); @@ -1244,7 +1245,7 @@ public void DictionaryEqualitySameOrder_CompareByKey() Assert.IsTrue(isEqual); } - + [Test] public void DictionaryInequalityDifferentOrder() { @@ -1257,6 +1258,22 @@ public void DictionaryInequalityDifferentOrder() Assert.IsFalse(isEqual); } + [Test] + public void DictionaryEqualityDifferentOrder_CompareByKey() + { + var a1 = new Dictionary { { 1, "One" }, { 2, "Two" } }; + var a2 = new Dictionary { { 2, "Two" }, { 1, "One" } }; + + var settings = new ComparisonSettings(); + settings.ConfigureList(listOptions => listOptions.CompareElementsByKey()); + + var comparer = new Comparer>(settings); + + var isEqual = comparer.Compare(a1, a2); + + Assert.IsTrue(isEqual); + } + [Test] public void DictionaryInequalityDifferentNumberOfElements() { diff --git a/ObjectsComparer/ObjectsComparer.Tests/Comparer_MultidimensionalArraysTests.cs b/ObjectsComparer/ObjectsComparer.Tests/Comparer_MultidimensionalArraysTests.cs index 3281b9c..23107d5 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/Comparer_MultidimensionalArraysTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/Comparer_MultidimensionalArraysTests.cs @@ -24,7 +24,29 @@ public void IntOfIntInequality1() Assert.AreEqual("2", differences[0].Value1); Assert.AreEqual("3", differences[0].Value2); } - + + [Test] + public void IntOfIntInequality1_CompareByKey() + { + var a1 = new MultidimensionalArrays { IntOfInt = new[] { new[] { 1, 2 } } }; + var a2 = new MultidimensionalArrays { IntOfInt = new[] { new[] { 1, 3 } } }; + + var settings = new ComparisonSettings(); + settings.ConfigureList(options => options.CompareElementsByKey()); + + var comparer = new Comparer(settings); + + var isEqual = comparer.Compare(a1, a2, out var differencesEnum); + var differences = differencesEnum.ToList(); + + Assert.IsFalse(isEqual); + CollectionAssert.IsNotEmpty(differences); + Assert.AreEqual(1, differences.Count); + Assert.AreEqual("IntOfInt[0][1]", differences[0].MemberPath); + Assert.AreEqual("2", differences[0].Value1); + Assert.AreEqual("3", differences[0].Value2); + } + [Test] public void IntOfIntInequality2() { diff --git a/ObjectsComparer/ObjectsComparer/CompareListElementsByKeyOptions.cs b/ObjectsComparer/ObjectsComparer/CompareListElementsByKeyOptions.cs index 9c80b65..c26bfb1 100644 --- a/ObjectsComparer/ObjectsComparer/CompareListElementsByKeyOptions.cs +++ b/ObjectsComparer/ObjectsComparer/CompareListElementsByKeyOptions.cs @@ -20,16 +20,42 @@ public class CompareListElementsByKeyOptions /// /// Max. length of the formatted key of the element. See . /// - const int FormattedKeyMaxLength = 50; + const int FormattedElementKeyMaxLength = 50; /// /// Max. length of the identifier of the element that refers to null value. See . /// const int NullElementIdentifierMaxLength = 20; + + /// + /// Element keys supported by . + /// + static readonly string[] DefaultElementKeys = new string[] { "Id", "Key", "Name"}; + + /// + /// + /// + const bool DefaultElementKeyCaseSensitivity = false; CompareListElementsByKeyOptions() { - Initialize(); + DefaultElementKeyProviderAction = args => + { + if (TryGetPropertyValue(args.Element, caseSensitive: DefaultElementKeyCaseSensitivity, out var keyValue, DefaultElementKeys)) + { + return keyValue; + } + + if (TryGetKeyValueFromElement(args.Element, out var keyValue2)) + { + return keyValue2; + } + + return null; + + }; + + UseKey(DefaultElementKeyProviderAction); } /// @@ -66,25 +92,13 @@ public CompareListElementsByKeyOptions ThrowKeyNotFound(bool value) /// internal Func KeyProviderAction { get; private set; } = null; - public Func DefaultKeyProvider { get; private set; } = args => - { - if (TryGetPropertyValue(args.Element, caseSensitive: false, out var keyValue, "Id", "Name")) - { - return keyValue; - } - - return args.Element; - - }; + /// + /// + /// + public Func DefaultElementKeyProviderAction { get; private set; } = null; internal static CompareListElementsByKeyOptions Default() => new CompareListElementsByKeyOptions(); - void Initialize() - { - KeyProviderAction = DefaultKeyProvider; - //UseKey(new string[] { "Id", "Name" }, caseSensitive: false); - } - /// /// Key identification. It attempts to find the key using the property specified by the parameter. /// @@ -145,7 +159,7 @@ public CompareListElementsByKeyOptions UseKey(Func parameter, then it returns its value. /// /// Returns the value of the property that corresponds to the specified key. If no property matches the specified key, it returns the itself. - static bool TryGetPropertyValue(object instance, bool caseSensitive, out object value, params string[] properties) + bool TryGetPropertyValue(object instance, bool caseSensitive, out object value, params string[] properties) { if (instance != null) { @@ -170,6 +184,32 @@ static bool TryGetPropertyValue(object instance, bool caseSensitive, out object return false; } + internal static bool TryGetKeyValueFromElement(object element, out object keyValue) + { + var elementType = element.GetType(); + + if (elementType.InheritsFrom(typeof(System.Collections.Generic.KeyValuePair<,>))) + { + keyValue = elementType.GetTypeInfo().GetProperty("Key").GetValue(element); + return TryGetKeyValueFromElement(keyValue, out keyValue); + } + + if (elementType.InheritsFrom(typeof(IEquatable<>))) + { + keyValue = element; + return true; + } + + //if (elementType.InheritsFrom(Nullable.GetUnderlyingType(elementType))) + //{ + // keyValue = element; + // return true; + //} + + keyValue = null; + return false; + } + /// /// Returns optional formatted or unformatted . See /// @@ -187,7 +227,7 @@ internal string GetFormattedElementKey(FormatListElementKeyArgs formatElementKey formattedKey = formatElementKeyArgs.ElementKey.ToString(); } - return formattedKey.Left(FormattedKeyMaxLength); + return formattedKey.Left(FormattedElementKeyMaxLength); } /// diff --git a/ObjectsComparer/ObjectsComparer/ListConfigurationOptions.cs b/ObjectsComparer/ObjectsComparer/ListConfigurationOptions.cs index cbfacf0..4b73037 100644 --- a/ObjectsComparer/ObjectsComparer/ListConfigurationOptions.cs +++ b/ObjectsComparer/ObjectsComparer/ListConfigurationOptions.cs @@ -45,7 +45,7 @@ public ListConfigurationOptions CompareElementsByIndex() internal Action KeyOptionsAction { get; private set; } /// - /// Compares list elements by key. + /// Compares list elements by key using . /// public ListConfigurationOptions CompareElementsByKey() { From 5ec142a8a8986137ea65944de61a96994980f1ee Mon Sep 17 00:00:00 2001 From: "ASD\\nemec" Date: Mon, 15 Nov 2021 13:17:59 +0100 Subject: [PATCH 071/181] Edit tests. ComparerMultidimensionalArraysTests, ComparerGenericEnumerableTests. --- .../Comparer_GenericEnumerableTests.cs | 58 ++++++++++++++ .../Comparer_MultidimensionalArraysTests.cs | 79 ++++++++++++++++--- .../ObjectsComparer/ComparisonSettings.cs | 2 +- .../ListConfigurationOptions.cs | 1 + 4 files changed, 130 insertions(+), 10 deletions(-) diff --git a/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs b/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs index 16a1d39..3f6a80d 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs @@ -1287,6 +1287,23 @@ public void DictionaryInequalityDifferentNumberOfElements() Assert.AreEqual(DifferenceTypes.MissedElementInFirstObject, differences.First().DifferenceType); } + [Test] + public void DictionaryInequalityDifferentNumberOfElements_CompareByKey() + { + var a1 = new Dictionary { { 1, "One" }, { 2, "Two" } }; + var a2 = new Dictionary { { 1, "One" }, { 2, "Two" }, { 3, "Three" } }; + + var settings = new ComparisonSettings(); + settings.ConfigureList(listOptions => listOptions.CompareElementsByKey()); + + var comparer = new Comparer>(settings); + + var differences = comparer.CalculateDifferences(a1, a2).ToList(); + + Assert.AreEqual(1, differences.Count); + Assert.AreEqual(DifferenceTypes.NumberOfElementsMismatch, differences.First().DifferenceType); + } + [Test] public void DictionaryInequalityDifferentValue() { @@ -1302,5 +1319,46 @@ public void DictionaryInequalityDifferentValue() Assert.AreEqual("Two!", differences.First().Value2); Assert.AreEqual("[1].Value", differences.First().MemberPath); } + + [Test] + public void DictionaryInequalityDifferentValue_CompareByKey() + { + var a1 = new Dictionary { { 1, "One" }, { 2, "Two" } }; + var a2 = new Dictionary { { 1, "One" }, { 2, "Two!" } }; + + var settings = new ComparisonSettings(); + settings.ConfigureList(listOptions => listOptions.CompareElementsByKey()); + + var comparer = new Comparer>(settings); + + var differences = comparer.CalculateDifferences(a1, a2).ToList(); + + Assert.AreEqual(1, differences.Count); + Assert.AreEqual(DifferenceTypes.ValueMismatch, differences.First().DifferenceType); + Assert.AreEqual("Two", differences.First().Value1); + Assert.AreEqual("Two!", differences.First().Value2); + Assert.AreEqual("[2].Value", differences.First().MemberPath); + } + + [Test] + public void DictionaryInequalityDifferentValue_CompareByKey_FormatElementKey() + { + var a1 = new Dictionary { { 1, "One" }, { 2, "Two" } }; + var a2 = new Dictionary { { 1, "One" }, { 2, "Two!" } }; + + var settings = new ComparisonSettings(); + settings.ConfigureList(listOptions => listOptions + .CompareElementsByKey(keyOptions => keyOptions.FormatElementKey(args => $"Key={args.ElementKey}"))); + + var comparer = new Comparer>(settings); + + var differences = comparer.CalculateDifferences(a1, a2).ToList(); + + Assert.AreEqual(1, differences.Count); + Assert.AreEqual(DifferenceTypes.ValueMismatch, differences.First().DifferenceType); + Assert.AreEqual("Two", differences.First().Value1); + Assert.AreEqual("Two!", differences.First().Value2); + Assert.AreEqual("[Key=2].Value", differences.First().MemberPath); + } } } diff --git a/ObjectsComparer/ObjectsComparer.Tests/Comparer_MultidimensionalArraysTests.cs b/ObjectsComparer/ObjectsComparer.Tests/Comparer_MultidimensionalArraysTests.cs index 23107d5..942347e 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/Comparer_MultidimensionalArraysTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/Comparer_MultidimensionalArraysTests.cs @@ -1,6 +1,7 @@ using System; using System.Linq; using NUnit.Framework; +using ObjectsComparer.Exceptions; using ObjectsComparer.Tests.TestClasses; namespace ObjectsComparer.Tests @@ -36,15 +37,11 @@ public void IntOfIntInequality1_CompareByKey() var comparer = new Comparer(settings); - var isEqual = comparer.Compare(a1, a2, out var differencesEnum); - var differences = differencesEnum.ToList(); - - Assert.IsFalse(isEqual); - CollectionAssert.IsNotEmpty(differences); - Assert.AreEqual(1, differences.Count); - Assert.AreEqual("IntOfInt[0][1]", differences[0].MemberPath); - Assert.AreEqual("2", differences[0].Value1); - Assert.AreEqual("3", differences[0].Value2); + Assert.Throws(() => + { + var isEqual = comparer.Compare(a1, a2, out var differencesEnum); + var differences = differencesEnum.ToList(); + }); } [Test] @@ -86,6 +83,41 @@ public void IntOfIntInequality3() Assert.AreEqual("2", differences[0].Value2); } + [Test] + public void IntOfIntInequality3_CompareUnequalLists() + { + var a1 = new MultidimensionalArrays { IntOfInt = new[] { new[] { 1, 2 } } }; + var a2 = new MultidimensionalArrays { IntOfInt = new[] { new[] { 2, 2 }, new[] { 3, 5 } } }; + + var settings = new ComparisonSettings(); + settings.ConfigureList(listOptions => listOptions.CompareUnequalLists(true)); + + var comparer = new Comparer(settings); + + var isEqual = comparer.Compare(a1, a2, out var differencesEnum); + var differences = differencesEnum.ToList(); + + Assert.IsFalse(isEqual); + + CollectionAssert.IsNotEmpty(differences); + Assert.AreEqual(3, differences.Count); + + Assert.AreEqual(DifferenceTypes.ValueMismatch, differences[0].DifferenceType); + Assert.AreEqual("IntOfInt[0][0]", differences[0].MemberPath); + Assert.AreEqual("1", differences[0].Value1); + Assert.AreEqual("2", differences[0].Value2); + + Assert.AreEqual(DifferenceTypes.MissedElementInFirstObject, differences[1].DifferenceType); + Assert.AreEqual("IntOfInt[1]", differences[1].MemberPath); + Assert.AreEqual("", differences[1].Value1); + Assert.AreEqual("System.Int32[]", differences[1].Value2); + + Assert.AreEqual(DifferenceTypes.ValueMismatch, differences[2].DifferenceType); + Assert.AreEqual("IntOfInt.Length", differences[2].MemberPath); + Assert.AreEqual("1", differences[2].Value1); + Assert.AreEqual("2", differences[2].Value2); + } + [Test] public void IntOfIntInequality4() { @@ -122,6 +154,35 @@ public void IntOfIntInequality5() Assert.AreEqual("3", differences[0].Value2); } + [Test] + public void IntOfIntInequality5____() + { + var a1 = new MultidimensionalArrays { IntOfInt = new[] { new[] { 1, 2 }, new[] { 3, 5 } } }; + var a2 = new MultidimensionalArrays { IntOfInt = new[] { new[] { 1, 2 }, new[] { 3, 5, 6 } } }; + + var settings = new ComparisonSettings(); + settings.ConfigureList(listOptions => listOptions.CompareUnequalLists(true)); + + var comparer = new Comparer(settings); + + var isEqual = comparer.Compare(a1, a2, out var differencesEnum); + var differences = differencesEnum.ToList(); + + Assert.IsFalse(isEqual); + CollectionAssert.IsNotEmpty(differences); + Assert.AreEqual(2, differences.Count); + + Assert.AreEqual(DifferenceTypes.MissedElementInFirstObject, differences[0].DifferenceType); + Assert.AreEqual("IntOfInt[1][2]", differences[0].MemberPath); + Assert.AreEqual("", differences[0].Value1); + Assert.AreEqual("6", differences[0].Value2); + + Assert.AreEqual(DifferenceTypes.ValueMismatch, differences[1].DifferenceType); + Assert.AreEqual("IntOfInt[1].Length", differences[1].MemberPath); + Assert.AreEqual("2", differences[1].Value1); + Assert.AreEqual("3", differences[1].Value2); + } + [Test] public void IntOfIntInequality6() { diff --git a/ObjectsComparer/ObjectsComparer/ComparisonSettings.cs b/ObjectsComparer/ObjectsComparer/ComparisonSettings.cs index c7a0f0c..91624dd 100644 --- a/ObjectsComparer/ObjectsComparer/ComparisonSettings.cs +++ b/ObjectsComparer/ObjectsComparer/ComparisonSettings.cs @@ -86,7 +86,7 @@ public ComparisonSettings ConfigureList(Action - /// Configures list comparison behavior, especially the type of comparison.. See . + /// Configures list comparison behavior, especially the type of comparison. See . /// /// See . public ComparisonSettings ConfigureList(Action configureOptions) diff --git a/ObjectsComparer/ObjectsComparer/ListConfigurationOptions.cs b/ObjectsComparer/ObjectsComparer/ListConfigurationOptions.cs index 4b73037..00fcadd 100644 --- a/ObjectsComparer/ObjectsComparer/ListConfigurationOptions.cs +++ b/ObjectsComparer/ObjectsComparer/ListConfigurationOptions.cs @@ -6,6 +6,7 @@ namespace ObjectsComparer { + //TODO: Rename to ListComparisonOptions /// /// Configures list comparison behavior. /// From a0dab25aafa8dd031ca25da2969c8344f61b7807 Mon Sep 17 00:00:00 2001 From: "ASD\\nemec" Date: Mon, 15 Nov 2021 14:26:18 +0100 Subject: [PATCH 072/181] Rename "options" clasess. ListConfigurationOptions > ListComparisonOptions, CompareListElementsByKeyOptions >ListElementComparisonByKeyOptions. Rename ComparisonSettings.ConfigureList >ConfigureListComparison. --- .../Comparer_GenericEnumerableTests.cs | 68 +++++++++---------- .../Comparer_MultidimensionalArraysTests.cs | 6 +- .../Comparer_NonGenericEnumerableTests.cs | 16 ++--- .../ComparisonSettingsTests.cs | 30 ++++---- .../ObjectsComparer/ComparisonSettings.cs | 20 +++--- .../CustomComparers/EnumerablesComparer.cs | 8 +-- .../EnumerablesComparerBase.cs | 28 ++++---- .../CustomComparers/EnumerablesComparer~1.cs | 8 +-- .../Exceptions/ElementKeyNotFoundException.cs | 2 +- .../FormatListElementKeyArgs.cs | 2 +- .../FormatNullElementIdentifierArgs.cs | 2 +- ...ionOptions.cs => ListComparisonOptions.cs} | 24 ++++--- ...s => ListElementComparisonByKeyOptions.cs} | 44 +++++++----- 13 files changed, 135 insertions(+), 123 deletions(-) rename ObjectsComparer/ObjectsComparer/{ListConfigurationOptions.cs => ListComparisonOptions.cs} (66%) rename ObjectsComparer/ObjectsComparer/{CompareListElementsByKeyOptions.cs => ListElementComparisonByKeyOptions.cs} (83%) diff --git a/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs b/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs index 3f6a80d..e30a41a 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs @@ -32,7 +32,7 @@ public void ValueTypeArrayEquality_CompareByKey() var settings = new ComparisonSettings(); - settings.ConfigureList(listOptions => listOptions.CompareElementsByKey()); + settings.ConfigureListComparison(listOptions => listOptions.CompareElementsByKey()); var comparer = new Comparer(settings); @@ -64,7 +64,7 @@ public void PrimitiveTypeArrayInequalityCount_CompareUnequalLists() var a2 = new A { IntArray = new[] { 1, 2, 3 } }; var settings = new ComparisonSettings(); - settings.ConfigureList(listOptions => listOptions.CompareUnequalLists(true)); + settings.ConfigureListComparison(listOptions => listOptions.CompareUnequalLists(true)); var comparer = new Comparer(settings); var rootCtx = ComparisonContext.CreateRoot(); @@ -110,7 +110,7 @@ public void PrimitiveTypeArrayInequalityMember_CompareByKey() var a2 = new A { IntArray = new[] { 1, 3 } }; var settings = new ComparisonSettings(); - settings.ConfigureList(listOptions => listOptions.CompareElementsByKey()); + settings.ConfigureListComparison(listOptions => listOptions.CompareElementsByKey()); var comparer = new Comparer(settings); @@ -138,7 +138,7 @@ public void PrimitiveTypeArrayInequalityMember_CompareByKey_FormatKey() var a2 = new A { IntArray = new[] { 1, 3 } }; var settings = new ComparisonSettings(); - settings.ConfigureList(listOptions => + settings.ConfigureListComparison(listOptions => { listOptions.CompareElementsByKey(keyOptions => keyOptions.FormatElementKey(args => $"Key={args.ElementKey}")); }); @@ -184,7 +184,7 @@ public void PrimitiveTypeArrayInequalityFirstNull_CompareBykey() var a1 = new A(); var a2 = new A { IntArray = new int[0] }; var settings = new ComparisonSettings(); - settings.ConfigureList(listOptions => listOptions.CompareElementsByKey()); + settings.ConfigureListComparison(listOptions => listOptions.CompareElementsByKey()); var comparer = new Comparer(settings); @@ -219,7 +219,7 @@ public void PrimitiveTypeArrayInequalitySecondNull_CompareByKey() var a2 = new A(); var settings = new ComparisonSettings(); - settings.ConfigureList(listOptions => listOptions.CompareElementsByKey()); + settings.ConfigureListComparison(listOptions => listOptions.CompareElementsByKey()); var comparer = new Comparer(settings); @@ -250,7 +250,7 @@ public void ClassArrayEquality_ComareByKey_Throw_ElementKeyNotFoundException() var a2 = new A { ArrayOfB = new[] { new B { Property1 = "Str1" }, new B { Property1 = "Str2" } } }; var settings = new ComparisonSettings(); - settings.ConfigureList(listOptions => listOptions.CompareElementsByKey()); + settings.ConfigureListComparison(listOptions => listOptions.CompareElementsByKey()); var comparer = new Comparer(settings); @@ -267,7 +267,7 @@ public void ClassArrayEquality_ComareByKey_DoesNotThrow_ElementKeyNotFoundExcept var a2 = new A { ArrayOfB = new[] { new B { Property1 = "Str1" }, new B { Property1 = "Str2" } } }; var settings = new ComparisonSettings(); - settings.ConfigureList(listOptions => listOptions.CompareElementsByKey(keyOptions => keyOptions.ThrowKeyNotFound(false))); + settings.ConfigureListComparison(listOptions => listOptions.CompareElementsByKey(keyOptions => keyOptions.ThrowKeyNotFound(false))); var comparer = new Comparer(settings); bool isEqual = false; @@ -303,7 +303,7 @@ public void ClassArrayInequalityCount_CompareByKey_DoesNotThrow_ElementKeyNotFou var a2 = new A { ArrayOfB = new[] { new B { Property1 = "Str1" }, new B { Property1 = "Str2" } } }; var settings = new ComparisonSettings(); - settings.ConfigureList(listOptions => listOptions + settings.ConfigureListComparison(listOptions => listOptions .CompareUnequalLists(true) .CompareElementsByKey(keyOptions => keyOptions.ThrowKeyNotFound(false))); @@ -327,7 +327,7 @@ public void ClassArrayInequalityCount_CompareUnequalLists() var a2 = new A { ArrayOfB = new[] { new B { Property1 = "Str1" }, new B { Property1 = "Str2" } } }; var settings = new ComparisonSettings(); - settings.ConfigureList(listOptions => listOptions.CompareUnequalLists(true)); + settings.ConfigureListComparison(listOptions => listOptions.CompareUnequalLists(true)); var comparer = new Comparer(settings); @@ -368,7 +368,7 @@ public void ClassArrayInequalityProperty_CompareByKey() var a2 = new A { ArrayOfB = new[] { new B { Property1 = "Str1", Id = 2 }, new B { Property1 = "Str3", Id = 1 } } }; var settings = new ComparisonSettings(); - settings.ConfigureList(listOptions => listOptions.CompareElementsByKey()); + settings.ConfigureListComparison(listOptions => listOptions.CompareElementsByKey()); var comparer = new Comparer(settings); @@ -387,7 +387,7 @@ public void ClassArrayInequalityProperty_CompareByKey_FormatKey() var a2 = new A { ArrayOfB = new[] { new B { Property1 = "Str1", Id = 1 }, new B { Property1 = "Str3", Id = 2 } } }; var settings = new ComparisonSettings(); - settings.ConfigureList(listOptions => listOptions.CompareElementsByKey(keyOptions => keyOptions.FormatElementKey(args => $"Id={args.ElementKey}"))); + settings.ConfigureListComparison(listOptions => listOptions.CompareElementsByKey(keyOptions => keyOptions.FormatElementKey(args => $"Id={args.ElementKey}"))); var comparer = new Comparer(settings); @@ -418,7 +418,7 @@ public void CollectionEquality_CompareByKey() var a2 = new A { CollectionOfB = new Collection { new B { Property1 = "Str1", Id = 2 }, new B { Property1 = "Str2", Id = 1 } } }; var settings = new ComparisonSettings(); - settings.ConfigureList(listOptions => listOptions.CompareElementsByKey()); + settings.ConfigureListComparison(listOptions => listOptions.CompareElementsByKey()); var comparer = new Comparer(settings); @@ -451,7 +451,7 @@ public void CollectionInequalityCount_CompareUnequalLists() var a2 = new A { CollectionOfB = new Collection { new B { Property1 = "Str1" } } }; var settings = new ComparisonSettings(); - settings.ConfigureList(listOptions => listOptions.CompareUnequalLists(true)); + settings.ConfigureListComparison(listOptions => listOptions.CompareUnequalLists(true)); var comparer = new Comparer(settings); @@ -494,7 +494,7 @@ public void CollectionAndNullInequality_CompareByKey() var a2 = new A(); var settings = new ComparisonSettings(); - settings.ConfigureList(listOptions => + settings.ConfigureListComparison(listOptions => { listOptions.CompareElementsByKey(); }); @@ -533,7 +533,7 @@ public void NullAndCollectionInequality_CompareByKey() var a2 = new A { CollectionOfB = new Collection { new B { Property1 = "Str1" }, new B { Property1 = "Str2" } } }; var settings = new ComparisonSettings(); - settings.ConfigureList(listOptions => + settings.ConfigureListComparison(listOptions => { listOptions.CompareElementsByKey(); }); @@ -571,7 +571,7 @@ public void CollectionInequalityProperty_CompareByKey() var a2 = new A { CollectionOfB = new Collection { new B { Property1 = "Str1", Id = 2 }, new B { Property1 = "Str3", Id = 1 } } }; var settings = new ComparisonSettings(); - settings.ConfigureList(listOptions => listOptions.CompareElementsByKey()); + settings.ConfigureListComparison(listOptions => listOptions.CompareElementsByKey()); var comparer = new Comparer(settings); @@ -602,7 +602,7 @@ public void ClassImplementsCollectionEquality_CompareByKey() var a2 = new A { ClassImplementsCollectionOfB = new CollectionOfB { new B { Property1 = "Str1", Id = 1 }, new B { Property1 = "Str2", Id = 2 } } }; var settings = new ComparisonSettings(); - settings.ConfigureList(listOptions => listOptions.CompareElementsByKey()); + settings.ConfigureListComparison(listOptions => listOptions.CompareElementsByKey()); var comparer = new Comparer(settings); @@ -635,7 +635,7 @@ public void ClassImplementsCollectionInequalityCount_CompareUnequalLists() var a2 = new A { ClassImplementsCollectionOfB = new CollectionOfB { new B { Property1 = "Str1" } } }; var settings = new ComparisonSettings(); - settings.ConfigureList(listOptions => listOptions.CompareUnequalLists(true)); + settings.ConfigureListComparison(listOptions => listOptions.CompareUnequalLists(true)); var comparer = new Comparer(settings); @@ -662,7 +662,7 @@ public void ClassImplementsCollectionInequalityCount_CompareUnequalLists_Compare var a2 = new A { ClassImplementsCollectionOfB = new CollectionOfB { new B { Property1 = "Str1", Id = 1 } } }; var settings = new ComparisonSettings(); - settings.ConfigureList(listOptions => listOptions.CompareUnequalLists(true).CompareElementsByKey()); + settings.ConfigureListComparison(listOptions => listOptions.CompareUnequalLists(true).CompareElementsByKey()); var comparer = new Comparer(settings); @@ -704,7 +704,7 @@ public void ClassImplementsCollectionInequalityProperty_CompareByKey() var a2 = new A { ClassImplementsCollectionOfB = new CollectionOfB { new B { Property1 = "Str1", Id = 1 }, new B { Property1 = "Str3", Id = 2 } } }; var settings = new ComparisonSettings(); - settings.ConfigureList(listOptions => listOptions.CompareUnequalLists(true).CompareElementsByKey()); + settings.ConfigureListComparison(listOptions => listOptions.CompareUnequalLists(true).CompareElementsByKey()); var comparer = new Comparer(settings); @@ -817,7 +817,7 @@ public void CollectionOfBCountInequality1_CompareElementsByKey() }; var settings = new ComparisonSettings(); - settings.ConfigureList(listOptions => listOptions.CompareElementsByKey()); + settings.ConfigureListComparison(listOptions => listOptions.CompareElementsByKey()); var comparer = new Comparer(settings); @@ -846,7 +846,7 @@ public void CollectionOfBCountInequality1_CompareElementsByKey_CompareUnequalLis }; var settings = new ComparisonSettings(); - settings.ConfigureList(listOptions => listOptions.CompareUnequalLists(true).CompareElementsByKey()); + settings.ConfigureListComparison(listOptions => listOptions.CompareUnequalLists(true).CompareElementsByKey()); var comparer = new Comparer(settings); @@ -906,7 +906,7 @@ public void CollectionOfBCountInequality2_CompareByKey() }; var settings = new ComparisonSettings(); - settings.ConfigureList(listOptions => listOptions.CompareUnequalLists(true).CompareElementsByKey()); + settings.ConfigureListComparison(listOptions => listOptions.CompareUnequalLists(true).CompareElementsByKey()); var comparer = new Comparer(settings); var isEqual = comparer.Compare(a1, a2, out var differencesEnum); @@ -1048,7 +1048,7 @@ public void PrimitiveTypeArray_CompareByKey_CompareUnequalLists_Ignore_Repeated_ var a2 = new A() { IntArray = new int[] { 1, 2, 1, 2, 1, 2, 1, 2, 1, 2 } }; var settings = new ComparisonSettings(); - settings.ConfigureList(listOptions => listOptions.CompareElementsByKey().CompareUnequalLists(true)); + settings.ConfigureListComparison(listOptions => listOptions.CompareElementsByKey().CompareUnequalLists(true)); var comparer = new Comparer(settings); @@ -1068,7 +1068,7 @@ public void PrimitiveTypeArray_CompareByIndex_CompareUnequalLists_Dont_Ignore_Re var a2 = new A() { IntArray = new int[] { 1, 2, 1, 2, 1, 2, 1, 2, 1, 2 } }; var settings = new ComparisonSettings(); - settings.ConfigureList(listOptions => listOptions.CompareUnequalLists(true)); + settings.ConfigureListComparison(listOptions => listOptions.CompareUnequalLists(true)); var comparer = new Comparer(settings); @@ -1129,7 +1129,7 @@ public void CompareAsIList_CompareUnequalLists() var list2 = new List { 1 }; var settings = new ComparisonSettings(); - settings.ConfigureList(listOptions => listOptions.CompareUnequalLists(true)); + settings.ConfigureListComparison(listOptions => listOptions.CompareUnequalLists(true)); var comparer = new Comparer>(settings); @@ -1154,7 +1154,7 @@ public void CompareAsIList_CompareUnequalLists_CompareElementsByKey() var list2 = new List { 1 }; var settings = new ComparisonSettings(); - settings.ConfigureList(listOptions => listOptions.CompareUnequalLists(true).CompareElementsByKey()); + settings.ConfigureListComparison(listOptions => listOptions.CompareUnequalLists(true).CompareElementsByKey()); var comparer = new Comparer>(settings); @@ -1179,7 +1179,7 @@ public void CompareAsIList_CompareUnequalLists_CompareElementsByKey_FormatKey() var list2 = new List { 1 }; var settings = new ComparisonSettings(); - settings.ConfigureList(listOptions => + settings.ConfigureListComparison(listOptions => { //DaN Fluent. //listOptions.CompareUnequalLists().CompareElementsByKey(keyOptions => keyOptions.FormatElementKey(elementKey => $"Key={elementKey}")); @@ -1236,7 +1236,7 @@ public void DictionaryEqualitySameOrder_CompareByKey() var a2 = new Dictionary { { 1, "One" }, { 2, "Two" } }; var settings = new ComparisonSettings(); - settings.ConfigureList(listOptions => listOptions.CompareElementsByKey()); + settings.ConfigureListComparison(listOptions => listOptions.CompareElementsByKey()); var comparer = new Comparer>(settings); @@ -1265,7 +1265,7 @@ public void DictionaryEqualityDifferentOrder_CompareByKey() var a2 = new Dictionary { { 2, "Two" }, { 1, "One" } }; var settings = new ComparisonSettings(); - settings.ConfigureList(listOptions => listOptions.CompareElementsByKey()); + settings.ConfigureListComparison(listOptions => listOptions.CompareElementsByKey()); var comparer = new Comparer>(settings); @@ -1294,7 +1294,7 @@ public void DictionaryInequalityDifferentNumberOfElements_CompareByKey() var a2 = new Dictionary { { 1, "One" }, { 2, "Two" }, { 3, "Three" } }; var settings = new ComparisonSettings(); - settings.ConfigureList(listOptions => listOptions.CompareElementsByKey()); + settings.ConfigureListComparison(listOptions => listOptions.CompareElementsByKey()); var comparer = new Comparer>(settings); @@ -1327,7 +1327,7 @@ public void DictionaryInequalityDifferentValue_CompareByKey() var a2 = new Dictionary { { 1, "One" }, { 2, "Two!" } }; var settings = new ComparisonSettings(); - settings.ConfigureList(listOptions => listOptions.CompareElementsByKey()); + settings.ConfigureListComparison(listOptions => listOptions.CompareElementsByKey()); var comparer = new Comparer>(settings); @@ -1347,7 +1347,7 @@ public void DictionaryInequalityDifferentValue_CompareByKey_FormatElementKey() var a2 = new Dictionary { { 1, "One" }, { 2, "Two!" } }; var settings = new ComparisonSettings(); - settings.ConfigureList(listOptions => listOptions + settings.ConfigureListComparison(listOptions => listOptions .CompareElementsByKey(keyOptions => keyOptions.FormatElementKey(args => $"Key={args.ElementKey}"))); var comparer = new Comparer>(settings); diff --git a/ObjectsComparer/ObjectsComparer.Tests/Comparer_MultidimensionalArraysTests.cs b/ObjectsComparer/ObjectsComparer.Tests/Comparer_MultidimensionalArraysTests.cs index 942347e..22a3c1a 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/Comparer_MultidimensionalArraysTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/Comparer_MultidimensionalArraysTests.cs @@ -33,7 +33,7 @@ public void IntOfIntInequality1_CompareByKey() var a2 = new MultidimensionalArrays { IntOfInt = new[] { new[] { 1, 3 } } }; var settings = new ComparisonSettings(); - settings.ConfigureList(options => options.CompareElementsByKey()); + settings.ConfigureListComparison(options => options.CompareElementsByKey()); var comparer = new Comparer(settings); @@ -90,7 +90,7 @@ public void IntOfIntInequality3_CompareUnequalLists() var a2 = new MultidimensionalArrays { IntOfInt = new[] { new[] { 2, 2 }, new[] { 3, 5 } } }; var settings = new ComparisonSettings(); - settings.ConfigureList(listOptions => listOptions.CompareUnequalLists(true)); + settings.ConfigureListComparison(listOptions => listOptions.CompareUnequalLists(true)); var comparer = new Comparer(settings); @@ -161,7 +161,7 @@ public void IntOfIntInequality5____() var a2 = new MultidimensionalArrays { IntOfInt = new[] { new[] { 1, 2 }, new[] { 3, 5, 6 } } }; var settings = new ComparisonSettings(); - settings.ConfigureList(listOptions => listOptions.CompareUnequalLists(true)); + settings.ConfigureListComparison(listOptions => listOptions.CompareUnequalLists(true)); var comparer = new Comparer(settings); diff --git a/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs b/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs index f0a800d..89d4e20 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs @@ -35,7 +35,7 @@ public void Equality_CompareByKey() var a2 = new A { NonGenericEnumerable = new ArrayList { new B { Property1 = "Str1" }, new B { Property1 = "Str2" } } }; var settings = new ComparisonSettings(); - settings.ConfigureList(listOptions => listOptions.CompareElementsByKey(keyOptions => keyOptions.UseKey("Property1"))); + settings.ConfigureListComparison(listOptions => listOptions.CompareElementsByKey(keyOptions => keyOptions.UseKey("Property1"))); var comparer = new Comparer(settings); var isEqual = comparer.Compare(a1, a2); @@ -66,7 +66,7 @@ public void InequalityCount_CompareUnequalLists() var a2 = new A { NonGenericEnumerable = new ArrayList { new B { Property1 = "Str1" } } }; var settings = new ComparisonSettings(); - settings.ConfigureList(listOptions => listOptions.CompareUnequalLists(true)); + settings.ConfigureListComparison(listOptions => listOptions.CompareUnequalLists(true)); var comparer = new Comparer(settings); var differences = comparer.CalculateDifferences(a1, a2).ToList(); @@ -91,7 +91,7 @@ public void InequalityCount_CompareUnequalLists_CompareByKey() var a2 = new A { NonGenericEnumerable = new ArrayList { new B { Property1 = "Str1" } } }; var settings = new ComparisonSettings(); - settings.ConfigureList(listOptions => + settings.ConfigureListComparison(listOptions => { listOptions.CompareUnequalLists(true); listOptions.CompareElementsByKey(keyOptions => @@ -124,7 +124,7 @@ public void InequalityCount_CompareUnequalLists_CompareByKey_DontFormatKey() var a2 = new A { NonGenericEnumerable = new ArrayList { new B { Property1 = "Str1" } } }; var settings = new ComparisonSettings(); - settings.ConfigureList(listOptions => listOptions.CompareUnequalLists(true).CompareElementsByKey(keyOptions => keyOptions.UseKey("Property1"))); + settings.ConfigureListComparison(listOptions => listOptions.CompareUnequalLists(true).CompareElementsByKey(keyOptions => keyOptions.UseKey("Property1"))); var comparer = new Comparer(settings); @@ -165,7 +165,7 @@ public void InequalityProperty_CompareByKey() var a2 = new A { NonGenericEnumerable = new ArrayList { new B { Property1 = "Str3", Id = 2 }, new B { Property1 = "Str1", Id = 1 } } }; var settings = new ComparisonSettings(); - settings.ConfigureList(listOptions => listOptions.CompareElementsByKey()); + settings.ConfigureListComparison(listOptions => listOptions.CompareElementsByKey()); var comparer = new Comparer(settings); @@ -202,7 +202,7 @@ public void NullElementsEquality_CompareUnequalLists() var a2 = new A { NonGenericEnumerable = new ArrayList { null, null } }; var settings = new ComparisonSettings(); - settings.ConfigureList(listOptions => listOptions.CompareUnequalLists(true)); + settings.ConfigureListComparison(listOptions => listOptions.CompareUnequalLists(true)); var comparer = new Comparer(settings); var isEqual = comparer.Compare(a1, a2, out var diffs); @@ -225,7 +225,7 @@ public void NullElementsEquality_CompareUnequalLists_CompareByKey() var a2 = new A { NonGenericEnumerable = new ArrayList { null, null } }; var settings = new ComparisonSettings(); - settings.ConfigureList(listOptions => listOptions.CompareUnequalLists(true).CompareElementsByKey()); + settings.ConfigureListComparison(listOptions => listOptions.CompareUnequalLists(true).CompareElementsByKey()); var comparer = new Comparer(settings); var isEqual = comparer.Compare(a1, a2, out var diffs); @@ -263,7 +263,7 @@ public void NullAndNotNullElementsInequality_CompareByKey() var a2 = new A { NonGenericEnumerable = new ArrayList { "Str2", null } }; var settings = new ComparisonSettings(); - settings.ConfigureList(listOptions => + settings.ConfigureListComparison(listOptions => { listOptions.CompareElementsByKey(); }); diff --git a/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs b/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs index 6dad896..0134967 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs @@ -62,7 +62,7 @@ public void CompareListElementsByKeyIsCorrectlySet() //Client side. var settings = new ComparisonSettings(); - settings.ConfigureList((comparisonContext, listOptions) => + settings.ConfigureListComparison((comparisonContext, listOptions) => { listOptions.CompareUnequalLists(true); @@ -74,15 +74,15 @@ public void CompareListElementsByKeyIsCorrectlySet() }); //Component side. - var listConfigurationOptions = ListConfigurationOptions.Default(); + var listComparisonOptions = ListComparisonOptions.Default(); var ctx = ComparisonContext.Create(); - settings.ConfigureOptionsAction(ctx, listConfigurationOptions); - var compareElementsByKeyOptions = CompareListElementsByKeyOptions.Default(); - listConfigurationOptions.KeyOptionsAction(compareElementsByKeyOptions); + settings.ListComparisonOptionsAction(ctx, listComparisonOptions); + var listElementComparisonByKeyOptions = ListElementComparisonByKeyOptions.Default(); + listComparisonOptions.KeyOptionsAction(listElementComparisonByKeyOptions); - Assert.AreEqual(true, listConfigurationOptions.UnequalListsComparisonEnabled); - Assert.AreEqual(true, listConfigurationOptions.ElementSearchMode == ListElementSearchMode.Key); - Assert.AreEqual(false, compareElementsByKeyOptions.ThrowKeyNotFoundEnabled); + Assert.AreEqual(true, listComparisonOptions.UnequalListsComparisonEnabled); + Assert.AreEqual(true, listComparisonOptions.ElementSearchMode == ListElementSearchMode.Key); + Assert.AreEqual(false, listElementComparisonByKeyOptions.ThrowKeyNotFoundEnabled); } /// @@ -91,7 +91,7 @@ public void CompareListElementsByKeyIsCorrectlySet() [Test] public void ListComparisonConfigurationBackwardCompatibilityEnsured() { - var options = ListConfigurationOptions.Default(); + var options = ListComparisonOptions.Default(); Assert.AreEqual(false, options.UnequalListsComparisonEnabled); Assert.AreEqual(true, options.ElementSearchMode == ListElementSearchMode.Index); @@ -104,7 +104,7 @@ public void FluentTest_CompareUnequalLists() var a2 = new int[] { 1, 2, 3, 4 }; var settings = new ComparisonSettings(); - settings.ConfigureList(listOptions => listOptions.CompareUnequalLists(true)); + settings.ConfigureListComparison(listOptions => listOptions.CompareUnequalLists(true)); var comparer = new Comparer(settings); var differences = comparer.CalculateDifferences(a1, a2).ToList(); @@ -139,7 +139,7 @@ public void FluentTest_CompareUnequalLists_CompareElementsByKey() var a2 = new int[] { 1, 2, 3, 4 }; var settings = new ComparisonSettings(); - settings.ConfigureList(listOptions => listOptions.CompareUnequalLists(true).CompareElementsByKey()); + settings.ConfigureListComparison(listOptions => listOptions.CompareUnequalLists(true).CompareElementsByKey()); var comparer = new Comparer(settings); var differences = comparer.CalculateDifferences(a1, a2).ToList(); @@ -164,7 +164,7 @@ public void FluentTest_CompareUnequalLists_CompareElementsByKey_FormatKey() var a2 = new int[] { 1, 2, 3, 4 }; var settings = new ComparisonSettings(); - settings.ConfigureList(listOptions => listOptions + settings.ConfigureListComparison(listOptions => listOptions .CompareUnequalLists(true) .CompareElementsByKey(keyOptions => keyOptions.FormatElementKey(args => $"Key={args.ElementKey}"))); @@ -191,7 +191,7 @@ public void FluentTest_CompareUnequalLists_CompareElementsByKey_FormatKey_Defaul var a2 = new int?[] { 1, 2, 3, 4, null }; var settings = new ComparisonSettings(); - settings.ConfigureList(listOptions => listOptions + settings.ConfigureListComparison(listOptions => listOptions .CompareUnequalLists(true) .CompareElementsByKey(keyOptions => keyOptions.FormatElementKey(args => $"Key={args.ElementKey}"))); @@ -223,7 +223,7 @@ public void FluentTest_CompareUnequalLists_CompareElementsByKey_FormatKey_Format var a2 = new int?[] { 1, 2, 3, 4, null }; var settings = new ComparisonSettings(); - settings.ConfigureList(listOptions => listOptions + settings.ConfigureListComparison(listOptions => listOptions .CompareUnequalLists(true) .CompareElementsByKey(keyOptions => keyOptions .FormatElementKey(formatArgs => $"Key={formatArgs.ElementKey}") @@ -296,7 +296,7 @@ public void FluentTest_List() var a2 = new List { 1, 2, 3, 4 }; var settings = new ComparisonSettings(); - settings.ConfigureList(listOptions => listOptions.CompareUnequalLists(true).CompareElementsByKey()); + settings.ConfigureListComparison(listOptions => listOptions.CompareUnequalLists(true).CompareElementsByKey()); var comparer = new Comparer(settings); var differences = comparer.CalculateDifferences(a1, a2).ToList(); diff --git a/ObjectsComparer/ObjectsComparer/ComparisonSettings.cs b/ObjectsComparer/ObjectsComparer/ComparisonSettings.cs index 91624dd..2875187 100644 --- a/ObjectsComparer/ObjectsComparer/ComparisonSettings.cs +++ b/ObjectsComparer/ObjectsComparer/ComparisonSettings.cs @@ -67,20 +67,20 @@ public T GetCustomSetting(string key = null) throw new KeyNotFoundException(); } - internal Action ConfigureOptionsAction { get; private set; } = null; + internal Action ListComparisonOptionsAction { get; private set; } = null; /// - /// Configures list comparison behavior, especially the type of comparison. See . + /// Configures list comparison behavior, especially the type of the comparison. See . /// - /// First parameter: Current list comparison context. - public ComparisonSettings ConfigureList(Action configureOptions) + /// First parameter: Current list comparison context. + public ComparisonSettings ConfigureListComparison(Action comparisonOptions) { - if (configureOptions is null) + if (comparisonOptions is null) { - throw new ArgumentNullException(nameof(configureOptions)); + throw new ArgumentNullException(nameof(comparisonOptions)); } - ConfigureOptionsAction = configureOptions; + ListComparisonOptionsAction = comparisonOptions; return this; } @@ -88,10 +88,10 @@ public ComparisonSettings ConfigureList(Action /// Configures list comparison behavior, especially the type of comparison. See . /// - /// See . - public ComparisonSettings ConfigureList(Action configureOptions) + /// See . + public ComparisonSettings ConfigureListComparison(Action comparisonOptions) { - return ConfigureList((_, options) => configureOptions(options)); + return ConfigureListComparison((_, options) => comparisonOptions(options)); } } } diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs index 93ac723..3ed6549 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs @@ -57,20 +57,20 @@ public IEnumerable CalculateDifferences(Type type, object obj1, obje var array1 = ((IEnumerable)obj1).Cast().ToArray(); var array2 = ((IEnumerable)obj2).Cast().ToArray(); - var listConfigurationOptions = ListConfigurationOptions.Default(); - Settings.ConfigureOptionsAction?.Invoke(listComparisonContext, listConfigurationOptions); + var listComparisonOptions = ListComparisonOptions.Default(); + Settings.ListComparisonOptionsAction?.Invoke(listComparisonContext, listComparisonOptions); if (array1.Length != array2.Length) { yield return AddDifferenceToComparisonContext(new Difference("", array1.Length.ToString(), array2.Length.ToString(), DifferenceTypes.NumberOfElementsMismatch), listComparisonContext); - if (listConfigurationOptions.UnequalListsComparisonEnabled == false) + if (listComparisonOptions.UnequalListsComparisonEnabled == false) { yield break; } } - IEnumerable failrues = CalculateDifferences(array1, array2, listComparisonContext, listConfigurationOptions); + IEnumerable failrues = CalculateDifferences(array1, array2, listComparisonContext, listComparisonOptions); foreach (var failrue in failrues) { diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparerBase.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparerBase.cs index 6845ebe..7632fc4 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparerBase.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparerBase.cs @@ -13,33 +13,33 @@ public EnumerablesComparerBase(ComparisonSettings settings, BaseComparer parentC } /// - /// Selects calculation operation based on the current value of the property. + /// Selects calculation operation based on the current value of the property. /// - protected virtual IEnumerable CalculateDifferences(IList list1, IList list2, ComparisonContext listComparisonContext, ListConfigurationOptions listConfigurationOptions) + protected virtual IEnumerable CalculateDifferences(IList list1, IList list2, ComparisonContext listComparisonContext, ListComparisonOptions listComparisonOptions) { - if (listConfigurationOptions.ElementSearchMode == ListElementSearchMode.Key) + if (listComparisonOptions.ElementSearchMode == ListElementSearchMode.Key) { - return CalculateDifferencesByKey(list1, list2, listComparisonContext, listConfigurationOptions); + return CalculateDifferencesByKey(list1, list2, listComparisonContext, listComparisonOptions); } - else if (listConfigurationOptions.ElementSearchMode == ListElementSearchMode.Index) + else if (listComparisonOptions.ElementSearchMode == ListElementSearchMode.Index) { return CalculateDifferencesByIndex(list1, list2, listComparisonContext); } else { - throw new NotImplementedException($"{listConfigurationOptions.ElementSearchMode} not implemented yet."); + throw new NotImplementedException($"{listComparisonOptions.ElementSearchMode} not implemented yet."); } } /// /// Calculates differences using comparison mode. /// - protected virtual IEnumerable CalculateDifferencesByKey(IList array1, IList array2, ComparisonContext listComparisonContext, ListConfigurationOptions listConfigurationOptions) + protected virtual IEnumerable CalculateDifferencesByKey(IList array1, IList array2, ComparisonContext listComparisonContext, ListComparisonOptions listComparisonOptions) { Debug.WriteLine($"{GetType().Name}.{nameof(CalculateDifferencesByKey)}: {array1?.GetType().Name}"); - var keyOptions = CompareListElementsByKeyOptions.Default(); - listConfigurationOptions.KeyOptionsAction?.Invoke(keyOptions); + var keyOptions = ListElementComparisonByKeyOptions.Default(); + listComparisonOptions.KeyOptionsAction?.Invoke(keyOptions); for (int element1Index = 0; element1Index < array1.Count(); element1Index++) { @@ -59,7 +59,7 @@ protected virtual IEnumerable CalculateDifferencesByKey(IList continue; } - var element1Key = keyOptions.KeyProviderAction(new ListElementKeyProviderArgs(element1)); + var element1Key = keyOptions.ElementKeyProviderAction(new ListElementKeyProviderArgs(element1)); if (element1Key == null) { @@ -73,9 +73,9 @@ protected virtual IEnumerable CalculateDifferencesByKey(IList var formattedElement1Key = keyOptions.GetFormattedElementKey(new FormatListElementKeyArgs(element1Index, element1Key, element1)); - if (array2.Any(elm2 => elm2 != null && object.Equals(element1Key, keyOptions.KeyProviderAction(new ListElementKeyProviderArgs(elm2))))) + if (array2.Any(elm2 => elm2 != null && object.Equals(element1Key, keyOptions.ElementKeyProviderAction(new ListElementKeyProviderArgs(elm2))))) { - var element2 = array2.First(elm2 => elm2 != null && object.Equals(element1Key, keyOptions.KeyProviderAction(new ListElementKeyProviderArgs(elm2)))); + var element2 = array2.First(elm2 => elm2 != null && object.Equals(element1Key, keyOptions.ElementKeyProviderAction(new ListElementKeyProviderArgs(elm2)))); var comparer = Factory.GetObjectsComparer(element1.GetType(), Settings, this); foreach (var failure in comparer.CalculateDifferences(element1.GetType(), element1, element2, elementComparisonContext)) @@ -108,7 +108,7 @@ protected virtual IEnumerable CalculateDifferencesByKey(IList continue; } - var element2Key = keyOptions.KeyProviderAction(new ListElementKeyProviderArgs(element2)); + var element2Key = keyOptions.ElementKeyProviderAction(new ListElementKeyProviderArgs(element2)); if (element2Key == null) { @@ -120,7 +120,7 @@ protected virtual IEnumerable CalculateDifferencesByKey(IList continue; } - if (array1.Any(elm1 => elm1 != null && object.Equals(element2Key, keyOptions.KeyProviderAction(new ListElementKeyProviderArgs(elm1)))) == false) + if (array1.Any(elm1 => elm1 != null && object.Equals(element2Key, keyOptions.ElementKeyProviderAction(new ListElementKeyProviderArgs(elm1)))) == false) { var formattedElement2Key = keyOptions.GetFormattedElementKey(new FormatListElementKeyArgs(element2Index, element2Key, element2)); var valueComparer2 = OverridesCollection.GetComparer(element2.GetType()) ?? DefaultValueComparer; diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer~1.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer~1.cs index 0dfd07a..40577c6 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer~1.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer~1.cs @@ -57,8 +57,8 @@ public IEnumerable CalculateDifferences(Type type, object obj1, obje var list1 = ((IEnumerable)obj1).ToList(); var list2 = ((IEnumerable)obj2).ToList(); - var listConfigurationOptions = ListConfigurationOptions.Default(); - Settings.ConfigureOptionsAction?.Invoke(listComparisonContext, listConfigurationOptions); + var listComparisonOptions = ListComparisonOptions.Default(); + Settings.ListComparisonOptionsAction?.Invoke(listComparisonContext, listComparisonOptions); if (list1.Count != list2.Count) { @@ -67,13 +67,13 @@ public IEnumerable CalculateDifferences(Type type, object obj1, obje yield return AddDifferenceToComparisonContext(new Difference("", list1.Count().ToString(), list2.Count().ToString(), DifferenceTypes.NumberOfElementsMismatch), listComparisonContext); } - if (listConfigurationOptions.UnequalListsComparisonEnabled == false) + if (listComparisonOptions.UnequalListsComparisonEnabled == false) { yield break; } } - IEnumerable failrues = CalculateDifferences(list1, list2, listComparisonContext, listConfigurationOptions); + IEnumerable failrues = CalculateDifferences(list1, list2, listComparisonContext, listComparisonOptions); foreach (var failrue in failrues) { diff --git a/ObjectsComparer/ObjectsComparer/Exceptions/ElementKeyNotFoundException.cs b/ObjectsComparer/ObjectsComparer/Exceptions/ElementKeyNotFoundException.cs index d8f8334..7978843 100644 --- a/ObjectsComparer/ObjectsComparer/Exceptions/ElementKeyNotFoundException.cs +++ b/ObjectsComparer/ObjectsComparer/Exceptions/ElementKeyNotFoundException.cs @@ -5,7 +5,7 @@ namespace ObjectsComparer.Exceptions { /// - /// Depending on the configuration, the exception is thrown if the key provider does not supply the key for list element . For more information see and . + /// Depending on the configuration, the exception is thrown if the key provider does not supply the key for list element . For more information see and . /// public class ElementKeyNotFoundException : Exception { diff --git a/ObjectsComparer/ObjectsComparer/FormatListElementKeyArgs.cs b/ObjectsComparer/ObjectsComparer/FormatListElementKeyArgs.cs index cbe4860..c373465 100644 --- a/ObjectsComparer/ObjectsComparer/FormatListElementKeyArgs.cs +++ b/ObjectsComparer/ObjectsComparer/FormatListElementKeyArgs.cs @@ -3,7 +3,7 @@ namespace ObjectsComparer { /// - /// Useful arguments for list element key formatter. See . + /// Useful arguments for list element key formatter. See . /// public class FormatListElementKeyArgs { diff --git a/ObjectsComparer/ObjectsComparer/FormatNullElementIdentifierArgs.cs b/ObjectsComparer/ObjectsComparer/FormatNullElementIdentifierArgs.cs index 756aca1..2dae19f 100644 --- a/ObjectsComparer/ObjectsComparer/FormatNullElementIdentifierArgs.cs +++ b/ObjectsComparer/ObjectsComparer/FormatNullElementIdentifierArgs.cs @@ -3,7 +3,7 @@ namespace ObjectsComparer { /// - /// Useful arguments for null element identifier formatter. See . + /// Useful arguments for null element identifier formatter. See . /// public class FormatNullElementIdentifierArgs { diff --git a/ObjectsComparer/ObjectsComparer/ListConfigurationOptions.cs b/ObjectsComparer/ObjectsComparer/ListComparisonOptions.cs similarity index 66% rename from ObjectsComparer/ObjectsComparer/ListConfigurationOptions.cs rename to ObjectsComparer/ObjectsComparer/ListComparisonOptions.cs index 00fcadd..d627891 100644 --- a/ObjectsComparer/ObjectsComparer/ListConfigurationOptions.cs +++ b/ObjectsComparer/ObjectsComparer/ListComparisonOptions.cs @@ -6,13 +6,12 @@ namespace ObjectsComparer { - //TODO: Rename to ListComparisonOptions /// /// Configures list comparison behavior. /// - public class ListConfigurationOptions + public class ListComparisonOptions { - ListConfigurationOptions() + ListComparisonOptions() { } @@ -24,31 +23,35 @@ public class ListConfigurationOptions /// /// Whether to compare elements of the lists even if their number differs. Regardless of the , if lists are unequal, the difference of type will always be logged. Default value = false - unequal lists will not be compared. /// - public ListConfigurationOptions CompareUnequalLists(bool value) + public ListComparisonOptions CompareUnequalLists(bool value) { UnequalListsComparisonEnabled = value; return this; } - internal static ListConfigurationOptions Default() => new ListConfigurationOptions(); + /// + /// Default options. + /// + /// + internal static ListComparisonOptions Default() => new ListComparisonOptions(); /// /// Compares list elements by index. Default behavior. /// - public ListConfigurationOptions CompareElementsByIndex() + public ListComparisonOptions CompareElementsByIndex() { KeyOptionsAction = null; return this; } - internal Action KeyOptionsAction { get; private set; } + internal Action KeyOptionsAction { get; private set; } /// - /// Compares list elements by key using . + /// Compares list elements by key using element key provider. /// - public ListConfigurationOptions CompareElementsByKey() + public ListComparisonOptions CompareElementsByKey() { return CompareElementsByKey(options => { }); } @@ -56,7 +59,8 @@ public ListConfigurationOptions CompareElementsByKey() /// /// Compares list elements by key. /// - public ListConfigurationOptions CompareElementsByKey(Action keyOptions) + /// List element comparison options + public ListComparisonOptions CompareElementsByKey(Action keyOptions) { if (keyOptions is null) { diff --git a/ObjectsComparer/ObjectsComparer/CompareListElementsByKeyOptions.cs b/ObjectsComparer/ObjectsComparer/ListElementComparisonByKeyOptions.cs similarity index 83% rename from ObjectsComparer/ObjectsComparer/CompareListElementsByKeyOptions.cs rename to ObjectsComparer/ObjectsComparer/ListElementComparisonByKeyOptions.cs index c26bfb1..81f78d1 100644 --- a/ObjectsComparer/ObjectsComparer/CompareListElementsByKeyOptions.cs +++ b/ObjectsComparer/ObjectsComparer/ListElementComparisonByKeyOptions.cs @@ -10,7 +10,7 @@ namespace ObjectsComparer /// /// Configures the behavior of list elements if list elements are to be compared by key. /// - public class CompareListElementsByKeyOptions + public class ListElementComparisonByKeyOptions { /// /// Default element identifier template for element that refers to null value. See for more info. @@ -37,18 +37,18 @@ public class CompareListElementsByKeyOptions /// const bool DefaultElementKeyCaseSensitivity = false; - CompareListElementsByKeyOptions() + ListElementComparisonByKeyOptions() { DefaultElementKeyProviderAction = args => { - if (TryGetPropertyValue(args.Element, caseSensitive: DefaultElementKeyCaseSensitivity, out var keyValue, DefaultElementKeys)) + if (TryGetKeyValueFromElement(args.Element, out var keyValue2)) { - return keyValue; + return keyValue2; } - if (TryGetKeyValueFromElement(args.Element, out var keyValue2)) + if (TryGetPropertyValue(args.Element, caseSensitive: DefaultElementKeyCaseSensitivity, out var keyValue, DefaultElementKeys)) { - return keyValue2; + return keyValue; } return null; @@ -80,7 +80,7 @@ public class CompareListElementsByKeyOptions /// /// /// - public CompareListElementsByKeyOptions ThrowKeyNotFound(bool value) + public ListElementComparisonByKeyOptions ThrowKeyNotFound(bool value) { ThrowKeyNotFoundEnabled = value; @@ -90,19 +90,21 @@ public CompareListElementsByKeyOptions ThrowKeyNotFound(bool value) /// /// See . /// - internal Func KeyProviderAction { get; private set; } = null; + internal Func ElementKeyProviderAction { get; private set; } = null; /// - /// + /// Default list element key provider. If the element implements , the provider returns the element itself. + /// Otherwise, if the element contains one of the properties "Id", "Key", "Name", the provider returns first of them, in that order, even it will be null. + /// Otherwise the provider returns null. /// public Func DefaultElementKeyProviderAction { get; private set; } = null; - internal static CompareListElementsByKeyOptions Default() => new CompareListElementsByKeyOptions(); + internal static ListElementComparisonByKeyOptions Default() => new ListElementComparisonByKeyOptions(); /// /// Key identification. It attempts to find the key using the property specified by the parameter. /// - public CompareListElementsByKeyOptions UseKey(string key, bool caseSensitive = false) + public ListElementComparisonByKeyOptions UseKey(string key, bool caseSensitive = false) { if (string.IsNullOrWhiteSpace(key)) { @@ -115,7 +117,7 @@ public CompareListElementsByKeyOptions UseKey(string key, bool caseSensitive = f /// /// Key identification. It attempts to find the key using one of the public properties specified by the parameter, in the specified order. /// - public CompareListElementsByKeyOptions UseKey(string[] keys, bool caseSensitive = false) + public ListElementComparisonByKeyOptions UseKey(string[] keys, bool caseSensitive = false) { if (keys is null) { @@ -143,22 +145,22 @@ public CompareListElementsByKeyOptions UseKey(string[] keys, bool caseSensitive /// Key identification. It attempts to find the key using the parameter. /// /// First parameter: The element whose key is required. Return value: The element's key. - public CompareListElementsByKeyOptions UseKey(Func keyProvider) + public ListElementComparisonByKeyOptions UseKey(Func keyProvider) { if (keyProvider is null) { throw new ArgumentNullException(nameof(keyProvider)); } - KeyProviderAction = keyProvider; + ElementKeyProviderAction = keyProvider; return this; } /// - /// It will try to find one of the public properties specified by the parameter, then it returns its value. + /// The out parameter returns first property value of the from properties defined by , in specified order. Value can be null. + /// If no property is found in the object, false is returned by operation. /// - /// Returns the value of the property that corresponds to the specified key. If no property matches the specified key, it returns the itself. bool TryGetPropertyValue(object instance, bool caseSensitive, out object value, params string[] properties) { if (instance != null) @@ -184,6 +186,12 @@ bool TryGetPropertyValue(object instance, bool caseSensitive, out object value, return false; } + /// + /// If is returns , otherwise returns null. + /// + /// + /// + /// internal static bool TryGetKeyValueFromElement(object element, out object keyValue) { var elementType = element.GetType(); @@ -257,7 +265,7 @@ internal string GetNullElementIdentifier(FormatNullElementIdentifierArgs args) /// The formatted element key is then used as part of the property, e.g. "Addresses[Id=1]" instead of "Addresses[1]".
/// By default the element key is not formatted. /// - public CompareListElementsByKeyOptions FormatElementKey(Func formatter) + public ListElementComparisonByKeyOptions FormatElementKey(Func formatter) { if (formatter is null) { @@ -274,7 +282,7 @@ public CompareListElementsByKeyOptions FormatElementKey(Func template will be used to format the identifier. /// /// First parameter: Element index. Return value: Formatted identifier. - public CompareListElementsByKeyOptions FormatNullElementIdentifier(Func formatter) + public ListElementComparisonByKeyOptions FormatNullElementIdentifier(Func formatter) { if (formatter is null) { From 8f3b8970fd0c7cf831224a82529a4777439d0265 Mon Sep 17 00:00:00 2001 From: "ASD\\nemec" Date: Mon, 15 Nov 2021 14:40:00 +0100 Subject: [PATCH 073/181] Delete obsolete code. --- .../ComparisonSettingsTests.cs | 38 ------------------- 1 file changed, 38 deletions(-) diff --git a/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs b/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs index 0134967..a322d08 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs @@ -231,44 +231,6 @@ public void FluentTest_CompareUnequalLists_CompareElementsByKey_FormatKey_Format var comparer = new Comparer(settings); - //settings = new ComparisonSettings(); - //settings.ConfigureList(listOptions => - //{ - // listOptions.CompareUnequalLists(true); - - // listOptions.CompareElementsByKey(keyOptions => - // { - // keyOptions.FormatElementKey(args => $"Key={args.ElementKey}"); - // keyOptions.FormatNullElementIdentifier(idx => $"Null at {idx}"); - // }); - //}); - - //settings = new ComparisonSettings(); - //settings.ConfigureList((ctx, listOptions) => - //{ - // bool unequalEnabled = ctx.Member.Name == "List1"; - // listOptions.CompareUnequalLists(unequalEnabled); - - // listOptions.CompareElementsByKey(keyOptions => - // { - // keyOptions.FormatElementKey(args => $"Key={args.ElementKey}"); - // keyOptions.FormatNullElementIdentifier(args => $"Null at {args.ElementIndex}"); - - // if (ctx.Member.Name == nameof(A.ListOfB)) - // { - // keyOptions.UseKey(args => - // { - // if (args.Element is B element) - // { - // return element.Property1; - // } - - // return args.Element; - // }); - // } - // }); - //}); - var differences = comparer.CalculateDifferences(a1, a2).ToList(); Assert.AreEqual(3, differences.Count); From 10c0938adc3417255bbe82cde23eea51b2577f90 Mon Sep 17 00:00:00 2001 From: Daniel Nemec Date: Wed, 17 Nov 2021 07:26:21 +0100 Subject: [PATCH 074/181] CalculateDifferencesByIndex: Add parameter listComparisonOptions. --- .../CustomComparers/EnumerablesComparerBase.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparerBase.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparerBase.cs index 7632fc4..b000d50 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparerBase.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparerBase.cs @@ -23,7 +23,7 @@ protected virtual IEnumerable CalculateDifferences(IList list1 } else if (listComparisonOptions.ElementSearchMode == ListElementSearchMode.Index) { - return CalculateDifferencesByIndex(list1, list2, listComparisonContext); + return CalculateDifferencesByIndex(list1, list2, listComparisonContext, listComparisonOptions); } else { @@ -132,7 +132,7 @@ protected virtual IEnumerable CalculateDifferencesByKey(IList /// /// Calculates differences using comparison mode. /// - protected virtual IEnumerable CalculateDifferencesByIndex(IList array1, IList array2, ComparisonContext listComparisonContext) + protected virtual IEnumerable CalculateDifferencesByIndex(IList array1, IList array2, ComparisonContext listComparisonContext, ListComparisonOptions listComparisonOptions) { Debug.WriteLine($"{GetType().Name}.{nameof(CalculateDifferencesByIndex)}: {array1?.GetType().Name}"); From e030697c0b30bec46dcefbd3e94431edab15f7e9 Mon Sep 17 00:00:00 2001 From: Daniel Nemec Date: Wed, 17 Nov 2021 16:55:38 +0100 Subject: [PATCH 075/181] Add ComparisonSettings.ConfigureListComparison override. --- .../Comparer_NonGenericEnumerableTests.cs | 20 +++++++++++- .../ObjectsComparer/ComparisonContext.cs | 9 +++--- .../ObjectsComparer/ComparisonSettings.cs | 31 ++++++++++++++++--- 3 files changed, 50 insertions(+), 10 deletions(-) diff --git a/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs b/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs index 89d4e20..1734251 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs @@ -38,11 +38,29 @@ public void Equality_CompareByKey() settings.ConfigureListComparison(listOptions => listOptions.CompareElementsByKey(keyOptions => keyOptions.UseKey("Property1"))); var comparer = new Comparer(settings); - var isEqual = comparer.Compare(a1, a2); + var isEqual = comparer.Compare(a1, a2, out _); Assert.IsTrue(isEqual); } + [Test] + [TestCase(true, 0)] + [TestCase(false, 4)] + public void ShortcutConfigureListComparison(bool compareElementsByKey, int expectedDiffsCount) + { + var a1 = new int?[] { 1, 2, 3, null }; + var a2 = new int?[] { null, 3, 2, 1 }; + + var settings = new ComparisonSettings(); + settings.ConfigureListComparison(compareElementsByKey, false); + + var comparer = new Comparer(settings); + + var differences = comparer.CalculateDifferences(a1, a2).ToList(); + + Assert.IsTrue(differences.Count == expectedDiffsCount); + } + [Test] public void InequalityCount() { diff --git a/ObjectsComparer/ObjectsComparer/ComparisonContext.cs b/ObjectsComparer/ObjectsComparer/ComparisonContext.cs index 1c8fc0c..39a7978 100644 --- a/ObjectsComparer/ObjectsComparer/ComparisonContext.cs +++ b/ObjectsComparer/ObjectsComparer/ComparisonContext.cs @@ -140,18 +140,17 @@ public void Shrink() { List removeDescendants = new List(); - _descendants.ForEach(d => + _descendants.ForEach(descendantContext => { - d.Shrink(); + descendantContext.Shrink(); - if (d.HasDifferences(true) == false) + if (descendantContext.HasDifferences(true) == false) { - removeDescendants.Add(d); + removeDescendants.Add(descendantContext); } }); _descendants.RemoveAll(ctx => removeDescendants.Contains(ctx)); - //removeDescendants.ForEach(d => _descendants.Remove(d)); } } } diff --git a/ObjectsComparer/ObjectsComparer/ComparisonSettings.cs b/ObjectsComparer/ObjectsComparer/ComparisonSettings.cs index 2875187..c8c6184 100644 --- a/ObjectsComparer/ObjectsComparer/ComparisonSettings.cs +++ b/ObjectsComparer/ObjectsComparer/ComparisonSettings.cs @@ -70,7 +70,7 @@ public T GetCustomSetting(string key = null) internal Action ListComparisonOptionsAction { get; private set; } = null; /// - /// Configures list comparison behavior, especially the type of the comparison. See . + /// Configures list comparison behavior, especially the type of the comparison. For more info, see . /// /// First parameter: Current list comparison context. public ComparisonSettings ConfigureListComparison(Action comparisonOptions) @@ -86,12 +86,35 @@ public ComparisonSettings ConfigureListComparison(Action - /// Configures list comparison behavior, especially the type of comparison. See . + /// Configures list comparison behavior, especially the type of comparison. For more info, see . /// /// See . - public ComparisonSettings ConfigureListComparison(Action comparisonOptions) + public void ConfigureListComparison(Action comparisonOptions) { - return ConfigureListComparison((_, options) => comparisonOptions(options)); + ConfigureListComparison((_, options) => comparisonOptions(options)); + } + + /// + /// Configures the type of list comparison and whether to compare unequal lists. For more info, see . + /// + /// + /// True value is shortcut for operation. + /// False value is shortcut for operation. + /// + /// + /// Shortcut for operation. + /// + public void ConfigureListComparison(bool compareElementsByKey, bool compareUnequalLists) + { + ConfigureListComparison(options => + { + options.CompareUnequalLists(compareUnequalLists); + + if (compareElementsByKey) + { + options.CompareElementsByKey(); + } + }); } } } From eb10914c85dd0bb0ec12ea4bc215e454ac2128cb Mon Sep 17 00:00:00 2001 From: Daniel Nemec Date: Sun, 28 Nov 2021 18:36:13 +0100 Subject: [PATCH 076/181] Additional IContextableComparer implementations. AbstractDynamicObjectsComprer, HashSetsComparer, MultidimensionalArrayComparer, TypesComparer. Throw ContextableComparerNotImplementedException. Add test methods. --- .../Comparer_CompilerGeneratedObjectsTests.cs | 58 ++++++++++++++ .../Comparer_ExpandoObjectsTests.cs | 54 +++++++++++++ .../Comparer_GenericEnumerableTests.cs | 77 +++++++++++++++++++ .../Comparer_MultidimensionalArraysTests.cs | 23 ++++++ .../ComparisonSettingsTests.cs | 2 + .../AbstractDynamicObjectsComprer.cs | 52 ++++++++++--- .../CustomComparers/HashSetsComparer~1.cs | 31 ++++++-- .../MultidimensionalArrayComparer~1.cs | 25 +++++- .../CustomComparers/TypesComparer.cs | 15 +++- ...textableComparerNotImplementedException.cs | 14 ++++ .../ObjectsComparer/IComparerExtensions.cs | 35 ++++++++- 11 files changed, 360 insertions(+), 26 deletions(-) create mode 100644 ObjectsComparer/ObjectsComparer/Exceptions/ContextableComparerNotImplementedException.cs diff --git a/ObjectsComparer/ObjectsComparer.Tests/Comparer_CompilerGeneratedObjectsTests.cs b/ObjectsComparer/ObjectsComparer.Tests/Comparer_CompilerGeneratedObjectsTests.cs index 3128f7a..d6152ed 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/Comparer_CompilerGeneratedObjectsTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/Comparer_CompilerGeneratedObjectsTests.cs @@ -1,6 +1,7 @@ using System.Linq; using NUnit.Framework; using NSubstitute; +using System.Collections.Generic; namespace ObjectsComparer.Tests { @@ -60,6 +61,36 @@ public void MissedFields() Assert.IsTrue(differences.Any(d => d.DifferenceType == DifferenceTypes.MissedMemberInFirstObject && d.MemberPath == "Field3" && d.Value2 == "False")); } + [Test] + public void MissedFields_CheckComparisonContext() + { + dynamic a1 = new + { + Field1 = "A", + Field2 = 5 + }; + + dynamic a2 = new + { + Field1 = "B", + Field2 = 8, + Field3 = false + }; + + var comparer = new Comparer(); + + var comparisonContext = ComparisonContext.CreateRoot(); + IEnumerable calculateDifferences = comparer.CalculateDifferences(typeof(object), (object)a1, (object)a2, comparisonContext).ToArray(); + var comparisonContextDifferences = comparisonContext.GetDifferences(true).ToArray(); + + Assert.AreEqual(3, calculateDifferences.Count()); + Assert.IsTrue(calculateDifferences.Any(d => d.MemberPath == "Field1" && d.Value1 == "A" && d.Value2 == "B")); + Assert.IsTrue(calculateDifferences.Any(d => d.MemberPath == "Field2" && d.Value1 == "5" && d.Value2 == "8")); + Assert.IsTrue(calculateDifferences.Any(d => d.DifferenceType == DifferenceTypes.MissedMemberInFirstObject && d.MemberPath == "Field3" && d.Value2 == "False")); + + CollectionAssert.AreEquivalent(calculateDifferences, comparisonContextDifferences); + } + [Test] public void MissedFieldsAndUseDefaults() { @@ -171,6 +202,33 @@ public void NullAndMissedMemberAreNotEqual() d => d.MemberPath == "Field2" && d.DifferenceType == DifferenceTypes.MissedMemberInFirstObject)); } + [Test] + public void NullAndMissedMemberAreNotEqual_CheckComparisonContext() + { + dynamic a1 = new + { + Field1 = (object)null + }; + dynamic a2 = new + { + Field2 = (object)null + }; + var comparer = new Comparer(); + + var comparisonContext = ComparisonContext.CreateRoot(); + var calculateDifferences = comparer.CalculateDifferences(typeof(object), (object)a1, (object)a2, comparisonContext).ToArray(); + var comparisonContextDifferences = comparisonContext.GetDifferences(true).ToArray(); + + Assert.IsTrue(calculateDifferences.Any()); + Assert.AreEqual(2, calculateDifferences.Count()); + Assert.IsTrue(calculateDifferences.Any( + d => d.MemberPath == "Field1" && d.DifferenceType == DifferenceTypes.MissedMemberInSecondObject)); + Assert.IsTrue(calculateDifferences.Any( + d => d.MemberPath == "Field2" && d.DifferenceType == DifferenceTypes.MissedMemberInFirstObject)); + + CollectionAssert.AreEquivalent(calculateDifferences, comparisonContextDifferences); + } + [Test] public void NullValues() { diff --git a/ObjectsComparer/ObjectsComparer.Tests/Comparer_ExpandoObjectsTests.cs b/ObjectsComparer/ObjectsComparer.Tests/Comparer_ExpandoObjectsTests.cs index f286784..3d41e1e 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/Comparer_ExpandoObjectsTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/Comparer_ExpandoObjectsTests.cs @@ -255,6 +255,26 @@ public void UseDefaultValuesWhenSubclassNotSpecified() Assert.IsTrue(isEqual); } + [Test] + public void UseDefaultValuesWhenSubclassNotSpecified_CheckComparisonContext() + { + dynamic a1 = new ExpandoObject(); + a1.Field1 = new ExpandoObject(); + a1.Field1.SubField1 = 0; + a1.Field1.SubField2 = null; + a1.Field1.SubField3 = 0.0; + dynamic a2 = new ExpandoObject(); + var comparer = new Comparer(new ComparisonSettings { UseDefaultIfMemberNotExist = true }); + + var rootComparisonContext = ComparisonContext.CreateRoot(); + IEnumerable diffs = comparer.CalculateDifferences(((object)a1).GetType(), a1, a2, rootComparisonContext); + var differences = diffs.ToArray(); + var comparisonContextDifferences = rootComparisonContext.GetDifferences(recursive: true).ToList(); + + CollectionAssert.IsEmpty(differences); + CollectionAssert.IsEmpty(comparisonContextDifferences); + } + [Test] public void DifferenceWhenSubclassNotSpecified() { @@ -275,6 +295,40 @@ public void DifferenceWhenSubclassNotSpecified() d => d.MemberPath == "Field1" && d.DifferenceType == DifferenceTypes.MissedMemberInSecondObject)); } + [Test] + public void DifferenceWhenSubclassNotSpecified_CheckComparisonContext() + { + dynamic a1 = new ExpandoObject(); + a1.Field1 = new ExpandoObject(); + a1.Field1.SubField1 = 0; + a1.Field1.SubField2 = null; + a1.Field1.SubField3 = 0.0; + dynamic a2 = new ExpandoObject(); + var comparer = new Comparer(); + + var isEqual = comparer.Compare(a1, a2, out IEnumerable differencesEnum); + var compareDifferences = differencesEnum.ToList(); + + Assert.IsFalse(isEqual); + Assert.AreEqual(1, compareDifferences.Count); + Assert.IsTrue(compareDifferences.Any( + d => d.MemberPath == "Field1" && d.DifferenceType == DifferenceTypes.MissedMemberInSecondObject)); + + var rootComparisonContext = ComparisonContext.CreateRoot(); + IEnumerable calculateDiffs = comparer.CalculateDifferences(((object)a1).GetType(), a1, a2, rootComparisonContext); + var calculateDifferences = calculateDiffs.ToList(); + var comparisonContextDifferences = rootComparisonContext.GetDifferences(recursive: true).ToList(); + + Assert.IsTrue(comparisonContextDifferences.Any( + d => d.MemberPath == "Field1" && d.DifferenceType == DifferenceTypes.MissedMemberInSecondObject)); + + Assert.IsTrue(calculateDifferences.Any( + d => d.MemberPath == "Field1" && d.DifferenceType == DifferenceTypes.MissedMemberInSecondObject)); + + comparisonContextDifferences.ForEach(ctxDiff => CollectionAssert.Contains(calculateDifferences, ctxDiff)); + calculateDifferences.ForEach(calculateDiff => CollectionAssert.Contains(comparisonContextDifferences, calculateDiff)); + } + [Test] public void ExpandoObjectWithCollections() { diff --git a/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs b/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs index e30a41a..4da0c8c 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs @@ -1304,6 +1304,83 @@ public void DictionaryInequalityDifferentNumberOfElements_CompareByKey() Assert.AreEqual(DifferenceTypes.NumberOfElementsMismatch, differences.First().DifferenceType); } + [Test] + public void DictionaryInequalityDifferentNumberOfElements_CompareByKey_CompareUnequalLists() + { + var a1 = new Dictionary { { 1, "One" }, { 2, "Two" } }; + var a2 = new Dictionary { { 1, "One" }, { 2, "Two" }, { 3, "Three" } }; + + var settings = new ComparisonSettings(); + settings.ConfigureListComparison(compareElementsByKey: true, compareUnequalLists: true); + + var comparer = new Comparer>(settings); + + var differences = comparer.CalculateDifferences(a1, a2).ToList(); + + Assert.AreEqual(2, differences.Count); + + Assert.AreEqual(DifferenceTypes.NumberOfElementsMismatch, differences[0].DifferenceType); + Assert.AreEqual("2", differences[0].Value1); + Assert.AreEqual("3", differences[0].Value2); + + Assert.AreEqual(DifferenceTypes.MissedElementInFirstObject, differences[1].DifferenceType); + Assert.AreEqual("[3]", differences[1].MemberPath); + Assert.AreEqual("", differences[1].Value1); + Assert.AreEqual("[3, Three]", differences[1].Value2); + } + + [Test] + public void DictionaryInequalityDifferentNumberOfElements_CompareByKey_CompareUnequalLists_FormatKey() + { + var a1 = new Dictionary { { 1, "One" }, { 2, "Two" } }; + var a2 = new Dictionary { { 1, "One" }, { 2, "Two" }, { 3, "Three" } }; + + var settings = new ComparisonSettings(); + settings.ConfigureListComparison(listOptions => listOptions + .CompareUnequalLists(true) + .CompareElementsByKey(keyOptions => keyOptions.FormatElementKey(keyArgs => $"Key={keyArgs.ElementKey}"))); + + var comparer = new Comparer>(settings); + + var differences = comparer.CalculateDifferences(a1, a2).ToList(); + + Assert.AreEqual(2, differences.Count); + + Assert.AreEqual(DifferenceTypes.NumberOfElementsMismatch, differences[0].DifferenceType); + Assert.AreEqual("2", differences[0].Value1); + Assert.AreEqual("3", differences[0].Value2); + + Assert.AreEqual(DifferenceTypes.MissedElementInFirstObject, differences[1].DifferenceType); + Assert.AreEqual("[Key=3]", differences[1].MemberPath); + Assert.AreEqual("", differences[1].Value1); + Assert.AreEqual("[3, Three]", differences[1].Value2); + } + + [Test] + public void DictionaryInequalityDifferentNumberOfElements_CompareByIndex_CompareUnequalLists() + { + var a1 = new Dictionary { { 1, "One" }, { 2, "Two" } }; + var a2 = new Dictionary { { 1, "One" }, { 2, "Two" }, { 3, "Three" } }; + + var settings = new ComparisonSettings(); + settings.ConfigureListComparison(compareElementsByKey: false, compareUnequalLists: true); + + var comparer = new Comparer>(settings); + + var differences = comparer.CalculateDifferences(a1, a2).ToList(); + + Assert.AreEqual(2, differences.Count); + + Assert.AreEqual(DifferenceTypes.NumberOfElementsMismatch, differences[0].DifferenceType); + Assert.AreEqual("2", differences[0].Value1); + Assert.AreEqual("3", differences[0].Value2); + + Assert.AreEqual(DifferenceTypes.MissedElementInFirstObject, differences[1].DifferenceType); + Assert.AreEqual("[2]", differences[1].MemberPath); + Assert.AreEqual("", differences[1].Value1); + Assert.AreEqual("[3, Three]", differences[1].Value2); + } + [Test] public void DictionaryInequalityDifferentValue() { diff --git a/ObjectsComparer/ObjectsComparer.Tests/Comparer_MultidimensionalArraysTests.cs b/ObjectsComparer/ObjectsComparer.Tests/Comparer_MultidimensionalArraysTests.cs index 22a3c1a..4135aa9 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/Comparer_MultidimensionalArraysTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/Comparer_MultidimensionalArraysTests.cs @@ -405,6 +405,29 @@ public void IntIntInequality7() Assert.AreEqual(string.Empty, differences[0].Value2); } + [Test] + public void IntIntInequality7_CheckComparisonContext() + { + var a1 = new MultidimensionalArrays { IntInt = new int[0, 0] }; + var a2 = new MultidimensionalArrays { IntInt = null }; + var comparer = new Comparer(); + + var rootComparisonContext = ComparisonContext.CreateRoot(); + var differences = comparer.CalculateDifferences(a1, a2, rootComparisonContext).ToList(); + + CollectionAssert.IsNotEmpty(differences); + Assert.AreEqual(1, differences.Count()); + Assert.AreEqual("IntInt", differences[0].MemberPath); + Assert.AreEqual(typeof(int[,]).FullName, differences[0].Value1); + Assert.AreEqual(string.Empty, differences[0].Value2); + + var comparisonContextDifferences = rootComparisonContext.GetDifferences(recursive: true).ToList(); + + comparisonContextDifferences.ForEach(ctxDiff => CollectionAssert.Contains(differences, ctxDiff)); + + differences.ForEach(diff => CollectionAssert.Contains(comparisonContextDifferences, diff)); + } + [Test] public void IntIntEquality1() { diff --git a/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs b/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs index a322d08..84cca62 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs @@ -7,6 +7,8 @@ namespace ObjectsComparer.Tests { + //NullAndMissedMemberAreNotEqual_CheckComparisonContext + [TestFixture] public class ComparisonSettingsTests { diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractDynamicObjectsComprer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractDynamicObjectsComprer.cs index ac08834..b0e1402 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractDynamicObjectsComprer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractDynamicObjectsComprer.cs @@ -6,13 +6,23 @@ namespace ObjectsComparer { - internal abstract class AbstractDynamicObjectsComprer: AbstractComparer, IComparerWithCondition + internal abstract class AbstractDynamicObjectsComprer: AbstractComparer, IComparerWithCondition, IContextableComparer, IContextableComparer { protected AbstractDynamicObjectsComprer(ComparisonSettings settings, BaseComparer parentComparer, IComparersFactory factory) : base(settings, parentComparer, factory) { } public override IEnumerable CalculateDifferences(Type type, object obj1, object obj2) + { + return CalculateDifferences(type, obj1, obj2, ComparisonContext.CreateRoot()); + } + + public virtual IEnumerable CalculateDifferences(T obj1, T obj2, ComparisonContext comparisonContext) + { + return CalculateDifferences(typeof(T), obj1, obj2, ComparisonContext.CreateRoot()); + } + + public virtual IEnumerable CalculateDifferences(Type type, object obj1, object obj2, ComparisonContext comparisonContext) { var castedObject1 = (T)obj1; var castedObject2 = (T)obj2; @@ -59,15 +69,21 @@ public override IEnumerable CalculateDifferences(Type type, object o { if (!existsInObject1) { - yield return new Difference(propertyKey, string.Empty, valueComparer.ToString(value2), - DifferenceTypes.MissedMemberInFirstObject); + var difference = AddDifferenceToComparisonContext( + new Difference(propertyKey, string.Empty, valueComparer.ToString(value2), DifferenceTypes.MissedMemberInFirstObject), + comparisonContext); + + yield return difference; continue; } if (!existsInObject2) { - yield return new Difference(propertyKey, valueComparer.ToString(value1), string.Empty, - DifferenceTypes.MissedMemberInSecondObject); + var difference = AddDifferenceToComparisonContext( + new Difference(propertyKey, valueComparer.ToString(value1), string.Empty, DifferenceTypes.MissedMemberInSecondObject), + comparisonContext); + + yield return difference; continue; } } @@ -77,8 +93,12 @@ public override IEnumerable CalculateDifferences(Type type, object o var valueComparer2 = OverridesCollection.GetComparer(value2.GetType()) ?? OverridesCollection.GetComparer(propertyKey) ?? DefaultValueComparer; - yield return new Difference(propertyKey, valueComparer.ToString(value1), valueComparer2.ToString(value2), - DifferenceTypes.TypeMismatch); + + var difference = AddDifferenceToComparisonContext( + new Difference(propertyKey, valueComparer.ToString(value1), valueComparer2.ToString(value2), DifferenceTypes.TypeMismatch), + comparisonContext); + + yield return difference; continue; } @@ -89,8 +109,12 @@ public override IEnumerable CalculateDifferences(Type type, object o var valueComparer2 = value2 != null ? OverridesCollection.GetComparer(value2.GetType()) ?? OverridesCollection.GetComparer(propertyKey) ?? DefaultValueComparer : DefaultValueComparer; - yield return new Difference(propertyKey, valueComparer.ToString(value1), valueComparer2.ToString(value2), - DifferenceTypes.TypeMismatch); + + var difference = AddDifferenceToComparisonContext( + new Difference(propertyKey, valueComparer.ToString(value1), valueComparer2.ToString(value2), DifferenceTypes.TypeMismatch), + comparisonContext); + + yield return difference; continue; } @@ -98,19 +122,23 @@ public override IEnumerable CalculateDifferences(Type type, object o { if (!customComparer.Compare(value1, value2, Settings)) { - yield return new Difference(propertyKey, customComparer.ToString(value1), customComparer.ToString(value2)); + var difference = AddDifferenceToComparisonContext( + new Difference(propertyKey, customComparer.ToString(value1), customComparer.ToString(value2)), + comparisonContext); + + yield return difference; } continue; } var comparer = Factory.GetObjectsComparer(propertyType, Settings, this); - foreach (var failure in comparer.CalculateDifferences(propertyType, value1, value2)) + foreach (var failure in comparer.CalculateDifferences(propertyType, value1, value2, comparisonContext)) { yield return failure.InsertPath(propertyKey); } } - } + } public abstract bool IsMatch(Type type, object obj1, object obj2); diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/HashSetsComparer~1.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/HashSetsComparer~1.cs index 0153066..98cc14d 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/HashSetsComparer~1.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/HashSetsComparer~1.cs @@ -5,15 +5,30 @@ namespace ObjectsComparer { - internal class HashSetsComparer : AbstractComparer + internal class HashSetsComparer : AbstractComparer, IContextableComparer, IContextableComparer { public HashSetsComparer(ComparisonSettings settings, BaseComparer parentComparer, IComparersFactory factory) :base(settings, parentComparer, factory) { } + public IEnumerable CalculateDifferences(T obj1, T obj2, ComparisonContext comparisonContext) + { + return CalculateDifferences(typeof(T), obj1, obj2, comparisonContext); + } + public override IEnumerable CalculateDifferences(Type type, object obj1, object obj2) { + return CalculateDifferences(type, obj1, obj2, ComparisonContext.CreateRoot()); + } + + public IEnumerable CalculateDifferences(Type type, object obj1, object obj2, ComparisonContext comparisonContext) + { + if (comparisonContext is null) + { + throw new ArgumentNullException(nameof(comparisonContext)); + } + if (!type.InheritsFrom(typeof(HashSet<>))) { throw new ArgumentException("Invalid type"); @@ -46,8 +61,11 @@ public override IEnumerable CalculateDifferences(Type type, object o { if (!hashSet2.Contains(element)) { - yield return new Difference("", valueComparer.ToString(element), string.Empty, - DifferenceTypes.MissedElementInSecondObject); + var difference = AddDifferenceToComparisonContext( + new Difference("", valueComparer.ToString(element), string.Empty, DifferenceTypes.MissedElementInSecondObject), + comparisonContext); + + yield return difference; } } @@ -55,11 +73,14 @@ public override IEnumerable CalculateDifferences(Type type, object o { if (!hashSet1.Contains(element)) { - yield return new Difference("", string.Empty, valueComparer.ToString(element), - DifferenceTypes.MissedElementInFirstObject); + var difference = AddDifferenceToComparisonContext(new Difference("", string.Empty, valueComparer.ToString(element), + DifferenceTypes.MissedElementInFirstObject), comparisonContext); + + yield return difference; } } } + public bool IsMatch(Type type, object obj1, object obj2) { diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/MultidimensionalArrayComparer~1.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/MultidimensionalArrayComparer~1.cs index 0a84774..8a5d97b 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/MultidimensionalArrayComparer~1.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/MultidimensionalArrayComparer~1.cs @@ -5,7 +5,7 @@ namespace ObjectsComparer { - internal class MultidimensionalArrayComparer : AbstractComparer + internal class MultidimensionalArrayComparer : AbstractComparer, IContextableComparer, IContextableComparer { private readonly IComparer _comparer; @@ -17,6 +17,21 @@ public MultidimensionalArrayComparer(ComparisonSettings settings, BaseComparer p public override IEnumerable CalculateDifferences(Type type, object obj1, object obj2) { + return CalculateDifferences(type, obj1, obj2, ComparisonContext.CreateRoot()); + } + + public IEnumerable CalculateDifferences(T obj1, T obj2, ComparisonContext comparisonContext) + { + return CalculateDifferences(typeof(T), obj1, obj2, comparisonContext); + } + + public IEnumerable CalculateDifferences(Type type, object obj1, object obj2, ComparisonContext comparisonContext) + { + if (comparisonContext is null) + { + throw new ArgumentNullException(nameof(comparisonContext)); + } + if (!type.InheritsFrom(typeof(Array))) { throw new ArgumentException("Invalid type"); @@ -43,7 +58,8 @@ public override IEnumerable CalculateDifferences(Type type, object o if (array1.Rank != array2.Rank) { - yield return new Difference("Rank", array1.Rank.ToString(), array2.Rank.ToString()); + var difference = AddDifferenceToComparisonContext(new Difference("Rank", array1.Rank.ToString(), array2.Rank.ToString()), comparisonContext); + yield return difference; yield break; } @@ -57,7 +73,8 @@ public override IEnumerable CalculateDifferences(Type type, object o if (length1 != length2) { dimensionsFailure = true; - yield return new Difference($"Dimension{i}", length1.ToString(), length2.ToString()); + var difference = AddDifferenceToComparisonContext(new Difference($"Dimension{i}", length1.ToString(), length2.ToString()), comparisonContext); + yield return difference; } } @@ -70,7 +87,7 @@ public override IEnumerable CalculateDifferences(Type type, object o { var indecies = IndexToCoordinates(array1, i); - foreach (var failure in _comparer.CalculateDifferences((T)array1.GetValue(indecies), (T)array2.GetValue(indecies))) + foreach (var failure in _comparer.CalculateDifferences((T)array1.GetValue(indecies), (T)array2.GetValue(indecies), comparisonContext)) { yield return failure.InsertPath($"[{string.Join(",", indecies)}]"); } diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/TypesComparer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/TypesComparer.cs index b733a9e..be7adf2 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/TypesComparer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/TypesComparer.cs @@ -5,7 +5,7 @@ namespace ObjectsComparer { - internal class TypesComparer : AbstractComparer, IComparerWithCondition + internal class TypesComparer : AbstractComparer, IComparerWithCondition, IContextableComparer { public TypesComparer(ComparisonSettings settings, BaseComparer parentComparer, IComparersFactory factory) @@ -15,6 +15,16 @@ public TypesComparer(ComparisonSettings settings, BaseComparer parentComparer, public override IEnumerable CalculateDifferences(Type type, object obj1, object obj2) { + return CalculateDifferences(type, obj1, obj2, ComparisonContext.CreateRoot()); + } + + public IEnumerable CalculateDifferences(Type type, object obj1, object obj2, ComparisonContext comparisonContext) + { + if (comparisonContext is null) + { + throw new ArgumentNullException(nameof(comparisonContext)); + } + if (obj1 == null && obj2 == null) { yield break; @@ -35,7 +45,8 @@ public override IEnumerable CalculateDifferences(Type type, object o if (type1Str != type2Str) { - yield return new Difference(string.Empty, type1Str, type2Str); + //yield return new Difference(string.Empty, type1Str, type2Str); + yield return AddDifferenceToComparisonContext(new Difference(string.Empty, type1Str, type2Str), comparisonContext); } } diff --git a/ObjectsComparer/ObjectsComparer/Exceptions/ContextableComparerNotImplementedException.cs b/ObjectsComparer/ObjectsComparer/Exceptions/ContextableComparerNotImplementedException.cs new file mode 100644 index 0000000..01c224f --- /dev/null +++ b/ObjectsComparer/ObjectsComparer/Exceptions/ContextableComparerNotImplementedException.cs @@ -0,0 +1,14 @@ +using System; + +namespace ObjectsComparer.Exceptions +{ + public class ContextableComparerNotImplementedException : NotImplementedException + { + internal ContextableComparerNotImplementedException(object comparer) : base(message: $"The comparer argument of type {comparer?.GetType()?.FullName} does not implement IContextableComparer interface.") + { + Comparer = comparer ?? throw new ArgumentNullException(nameof(comparer)); + } + + public object Comparer { get; } + } +} diff --git a/ObjectsComparer/ObjectsComparer/IComparerExtensions.cs b/ObjectsComparer/ObjectsComparer/IComparerExtensions.cs index 6817f95..c183b91 100644 --- a/ObjectsComparer/ObjectsComparer/IComparerExtensions.cs +++ b/ObjectsComparer/ObjectsComparer/IComparerExtensions.cs @@ -1,4 +1,5 @@ -using System; +using ObjectsComparer.Exceptions; +using System; using System.Collections.Generic; namespace ObjectsComparer @@ -18,24 +19,52 @@ public static class IComparerExtensions /// Object 2. /// Current comparison context. For more info see class. /// List of differences between objects. + /// If does not implement . public static IEnumerable CalculateDifferences(this IComparer comparer, Type type, object obj1, object obj2, ComparisonContext comparisonContext) { + if (comparer is null) + { + throw new ArgumentNullException(nameof(comparer)); + } + + if (type is null) + { + throw new ArgumentNullException(nameof(type)); + } + + if (comparisonContext is null) + { + throw new ArgumentNullException(nameof(comparisonContext)); + } + if (comparer is IContextableComparer contextableComparer) { return contextableComparer.CalculateDifferences(type, obj1, obj2, comparisonContext); } - return comparer.CalculateDifferences(type, obj1, obj2); + throw new ContextableComparerNotImplementedException(comparer); + //return comparer.CalculateDifferences(type, obj1, obj2); } public static IEnumerable CalculateDifferences(this IComparer comparer, T obj1, T obj2, ComparisonContext comparisonContext) { + if (comparer is null) + { + throw new ArgumentNullException(nameof(comparer)); + } + + if (comparisonContext is null) + { + throw new ArgumentNullException(nameof(comparisonContext)); + } + if (comparer is IContextableComparer contextableComparer) { return contextableComparer.CalculateDifferences(obj1, obj2, comparisonContext); } - return comparer.CalculateDifferences(obj1, obj2); + throw new ContextableComparerNotImplementedException(comparer); + //return comparer.CalculateDifferences(obj1, obj2); } } } \ No newline at end of file From f00760b75934fd5d0f83987fd337a1a4f3f10108 Mon Sep 17 00:00:00 2001 From: nemec Date: Fri, 3 Dec 2021 10:33:59 +0100 Subject: [PATCH 077/181] Add AbstractDynamicObjectsComprer.TryGetMember. --- .../Comparer_CompilerGeneratedObjectsTests.cs | 5 +++++ .../AbstractDynamicObjectsComprer.cs | 2 ++ .../CompilerGeneratedObjectComparer.cs | 19 +++++++++++++++++++ .../CustomComparers/DynamicObjectComparer.cs | 5 +++++ .../CustomComparers/ExpandoObjectComparer.cs | 5 +++++ 5 files changed, 36 insertions(+) diff --git a/ObjectsComparer/ObjectsComparer.Tests/Comparer_CompilerGeneratedObjectsTests.cs b/ObjectsComparer/ObjectsComparer.Tests/Comparer_CompilerGeneratedObjectsTests.cs index d6152ed..a6ed9c6 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/Comparer_CompilerGeneratedObjectsTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/Comparer_CompilerGeneratedObjectsTests.cs @@ -213,7 +213,12 @@ public void NullAndMissedMemberAreNotEqual_CheckComparisonContext() { Field2 = (object)null }; + + var t = (a1 as object).GetType(); + var members = t.GetMembers(); + var comparer = new Comparer(); + var comparisonContext = ComparisonContext.CreateRoot(); var calculateDifferences = comparer.CalculateDifferences(typeof(object), (object)a1, (object)a2, comparisonContext).ToArray(); diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractDynamicObjectsComprer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractDynamicObjectsComprer.cs index b0e1402..a14869c 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractDynamicObjectsComprer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractDynamicObjectsComprer.cs @@ -149,5 +149,7 @@ public virtual IEnumerable CalculateDifferences(Type type, object ob protected abstract IList GetProperties(T obj); protected abstract bool TryGetMemberValue(T obj, string propertyName, out object value); + + protected abstract bool TryGetMember(T obj, string propertyName, out MemberInfo value); } } \ No newline at end of file diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/CompilerGeneratedObjectComparer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/CompilerGeneratedObjectComparer.cs index a034d6c..9d318d0 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/CompilerGeneratedObjectComparer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/CompilerGeneratedObjectComparer.cs @@ -58,5 +58,24 @@ protected override bool TryGetMemberValue(object obj, string propertyName, out o return true; } + + protected override bool TryGetMember(object obj, string propertyName, out MemberInfo value) + { + value = null; + + if (obj == null) + { + return false; + } + + value = obj.GetType().GetTypeInfo().GetProperty(propertyName); + + if (value == null) + { + return false; + } + + return false; + } } } diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/DynamicObjectComparer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/DynamicObjectComparer.cs index f37ce23..3d830e0 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/DynamicObjectComparer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/DynamicObjectComparer.cs @@ -59,5 +59,10 @@ protected override bool TryGetMemberValue(DynamicObject obj, string propertyName return obj.TryGetMember(getBinder, out value); } + + protected override bool TryGetMember(DynamicObject obj, string propertyName, out MemberInfo value) + { + throw new NotImplementedException(); + } } } diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/ExpandoObjectComparer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/ExpandoObjectComparer.cs index ca8684f..02a8526 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/ExpandoObjectComparer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/ExpandoObjectComparer.cs @@ -32,6 +32,11 @@ protected override IList GetProperties(ExpandoObject obj) return ((IDictionary) obj)?.Keys.ToList() ?? new List(); } + protected override bool TryGetMember(ExpandoObject obj, string propertyName, out MemberInfo value) + { + throw new NotImplementedException(); + } + protected override bool TryGetMemberValue(ExpandoObject obj, string propertyName, out object value) { if (obj != null) From 9c210e477f08f531eeb9c74e03639d5b6c7e4e44 Mon Sep 17 00:00:00 2001 From: "ASD\\nemec" Date: Mon, 6 Dec 2021 13:53:36 +0100 Subject: [PATCH 078/181] =?UTF-8?q?Drobn=C3=A1=20vylep=C5=A1en=C3=AD.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Comparer.CalculateDifferences: Check comparer is CalculateDifferences. ComparisonSettings.ConfigureListComparison: Argumens defaults. Buil-in alternative to the Example 4. --- .../Example4Tests_BuiltInKeyComparison.cs | 309 ++++++++++++++++++ ObjectsComparer/ObjectsComparer/Comparer.cs | 16 +- .../ObjectsComparer/ComparisonSettings.cs | 6 +- 3 files changed, 324 insertions(+), 7 deletions(-) create mode 100644 ObjectsComparer/ObjectsComparer.Examples/Example4/Example4Tests_BuiltInKeyComparison.cs diff --git a/ObjectsComparer/ObjectsComparer.Examples/Example4/Example4Tests_BuiltInKeyComparison.cs b/ObjectsComparer/ObjectsComparer.Examples/Example4/Example4Tests_BuiltInKeyComparison.cs new file mode 100644 index 0000000..1e9806b --- /dev/null +++ b/ObjectsComparer/ObjectsComparer.Examples/Example4/Example4Tests_BuiltInKeyComparison.cs @@ -0,0 +1,309 @@ +using System.Collections.Generic; +using System.Linq; +using NUnit.Framework; +using static ObjectsComparer.Examples.OutputHelper; + +// ReSharper disable PossibleMultipleEnumeration +namespace ObjectsComparer.Examples.Example4 +{ + [TestFixture] + public class Example4Tests_BuiltInKeyComparison + { + [Test] + public void List_Of_Equal_Sizes_But_Is_Inequality() + { + var formula1 = new Formula + { + Id = 1, + Name = "Formula 1", + Items = new List + { + new FormulaItem + { + Id = 1, + Delay = 60, + Name = "Item 1", + Instruction = "Instruction 1" + } + } + }; + + var formula2 = new Formula + { + Id = 1, + Name = "Formula 1", + Items = new List + { + new FormulaItem + { + Id = 1, + Delay = 80, + Name = "Item One", + Instruction = "Instruction One" + } + } + }; + + var settings = new ComparisonSettings(); + settings.ConfigureListComparison(compareElementsByKey: true); + + var comparer = new Comparer(settings); + + var isEqual = comparer.Compare(formula1, formula2, out var differences); + + ResultToOutput(isEqual, differences); + + Assert.IsFalse(isEqual); + Assert.AreEqual(3, differences.Count()); + Assert.IsTrue(differences.Any(d => d.MemberPath == "Items[1].Delay" && d.Value1 == "60" && d.Value2 == "80")); + Assert.IsTrue(differences.Any(d => d.MemberPath == "Items[1].Name" && d.Value1 == "Item 1" && d.Value2 == "Item One")); + Assert.IsTrue(differences.Any(d => d.MemberPath == "Items[1].Instruction" && d.Value1 == "Instruction 1" && d.Value2 == "Instruction One")); + } + + [Test] + public void List_Of_Equal_Sizes_But_Is_Inequality_FormatKey() + { + var formula1 = new Formula + { + Id = 1, + Name = "Formula 1", + Items = new List + { + new FormulaItem + { + Id = 1, + Delay = 60, + Name = "Item 1", + Instruction = "Instruction 1" + } + } + }; + + var formula2 = new Formula + { + Id = 1, + Name = "Formula 1", + Items = new List + { + new FormulaItem + { + Id = 1, + Delay = 80, + Name = "Item One", + Instruction = "Instruction One" + } + } + }; + + var settings = new ComparisonSettings(); + + settings.ConfigureListComparison(listOptions => listOptions + .CompareElementsByKey(keyOptions => keyOptions + .FormatElementKey(formatKeyArgs => $"Id={formatKeyArgs.ElementKey}"))); + + var comparer = new Comparer(settings); + + var isEqual = comparer.Compare(formula1, formula2, out var differences); + + ResultToOutput(isEqual, differences); + + Assert.IsFalse(isEqual); + Assert.AreEqual(3, differences.Count()); + Assert.IsTrue(differences.Any(d => d.MemberPath == "Items[Id=1].Delay" && d.Value1 == "60" && d.Value2 == "80")); + Assert.IsTrue(differences.Any(d => d.MemberPath == "Items[Id=1].Name" && d.Value1 == "Item 1" && d.Value2 == "Item One")); + Assert.IsTrue(differences.Any(d => d.MemberPath == "Items[Id=1].Instruction" && d.Value1 == "Instruction 1" && d.Value2 == "Instruction One")); + } + + + [Test] + public void List_Of_Different_Sizes_But_Is_Inequality() + { + var formula1 = new Formula + { + Id = 1, + Name = "Formula 1", + Items = new List + { + new FormulaItem + { + Id = 1, + Delay = 60, + Name = "Item 1", + Instruction = "Instruction 1" + } + } + }; + + var formula2 = new Formula + { + Id = 1, + Name = "Formula 1", + Items = new List + { + new FormulaItem + { + Id = 1, + Delay = 80, + Name = "Item One", + Instruction = "Instruction One" + }, + new FormulaItem + { + Id = 2, + Delay = 30, + Name = "Item Two", + Instruction = "Instruction Two" + } + } + }; + + var settings = new ComparisonSettings(); + settings.ConfigureListComparison(compareElementsByKey: true, compareUnequalLists: true); + + var comparer = new Comparer(settings); + + var isEqual = comparer.Compare(formula1, formula2, out var differences); + + ResultToOutput(isEqual, differences); + + Assert.IsFalse(isEqual); + Assert.AreEqual(5, differences.Count()); + Assert.IsTrue(differences.Any(d => d.MemberPath == "Items" && d.Value1 == "1" && d.Value2 == "2" && d.DifferenceType == DifferenceTypes.NumberOfElementsMismatch)); + Assert.IsTrue(differences.Any(d => d.MemberPath == "Items[1].Delay" && d.Value1 == "60" && d.Value2 == "80")); + Assert.IsTrue(differences.Any(d => d.MemberPath == "Items[1].Name" && d.Value1 == "Item 1" && d.Value2 == "Item One")); + Assert.IsTrue(differences.Any(d => d.MemberPath == "Items[1].Instruction" && d.Value1 == "Instruction 1" && d.Value2 == "Instruction One")); + Assert.IsTrue(differences.Any(d => d.DifferenceType == DifferenceTypes.MissedElementInFirstObject && d.Value1 == "" && d.Value2 == "ObjectsComparer.Examples.Example4.FormulaItem")); + } + + [Test] + public void List_Of_Different_Sizes_But_Is_Inequality_FormatKey() + { + var formula1 = new Formula + { + Id = 1, + Name = "Formula 1", + Items = new List + { + new FormulaItem + { + Id = 1, + Delay = 60, + Name = "Item 1", + Instruction = "Instruction 1" + } + } + }; + + var formula2 = new Formula + { + Id = 1, + Name = "Formula 1", + Items = new List + { + new FormulaItem + { + Id = 1, + Delay = 80, + Name = "Item One", + Instruction = "Instruction One" + }, + new FormulaItem + { + Id = 2, + Delay = 30, + Name = "Item Two", + Instruction = "Instruction Two" + } + } + }; + + var settings = new ComparisonSettings(); + + settings.ConfigureListComparison(listOptions => listOptions + .CompareUnequalLists(true) + .CompareElementsByKey(keyOptions => keyOptions + .FormatElementKey(formatKeyArgs => $"Id={formatKeyArgs.ElementKey}"))); + + var comparer = new Comparer(settings); + + var isEqual = comparer.Compare(formula1, formula2, out var differences); + + ResultToOutput(isEqual, differences); + + Assert.IsFalse(isEqual); + Assert.AreEqual(5, differences.Count()); + Assert.IsTrue(differences.Any(d => d.MemberPath == "Items" && d.Value1 == "1" && d.Value2 == "2" && d.DifferenceType == DifferenceTypes.NumberOfElementsMismatch)); + Assert.IsTrue(differences.Any(d => d.MemberPath == "Items[Id=1].Delay" && d.Value1 == "60" && d.Value2 == "80")); + Assert.IsTrue(differences.Any(d => d.MemberPath == "Items[Id=1].Name" && d.Value1 == "Item 1" && d.Value2 == "Item One")); + Assert.IsTrue(differences.Any(d => d.MemberPath == "Items[Id=1].Instruction" && d.Value1 == "Instruction 1" && d.Value2 == "Instruction One")); + Assert.IsTrue(differences.Any(d => d.DifferenceType == DifferenceTypes.MissedElementInFirstObject && d.Value1 == "" && d.Value2 == "ObjectsComparer.Examples.Example4.FormulaItem")); + } + + [Test] + public void List_Of_Different_Sizes_But_Is_Inequality_FormatKey_CheckComparisonContext() + { + var formula1 = new Formula + { + Id = 1, + Name = "Formula 1", + Items = new List + { + new FormulaItem + { + Id = 1, + Delay = 60, + Name = "Item 1", + Instruction = "Instruction 1" + } + } + }; + + var formula2 = new Formula + { + Id = 1, + Name = "Formula 1", + Items = new List + { + new FormulaItem + { + Id = 1, + Delay = 80, + Name = "Item One", + Instruction = "Instruction One" + }, + new FormulaItem + { + Id = 2, + Delay = 30, + Name = "Item Two", + Instruction = "Instruction Two" + } + } + }; + + var settings = new ComparisonSettings(); + + settings.ConfigureListComparison(listOptions => listOptions + .CompareUnequalLists(true) + .CompareElementsByKey(keyOptions => keyOptions + .FormatElementKey(formatKeyArgs => $"Id={formatKeyArgs.ElementKey}"))); + + var comparer = new Comparer(settings); + var rootContext = ComparisonContext.CreateRoot(); + var differences = comparer.CalculateDifferences(formula1, formula2, rootContext).ToArray(); + rootContext.Shrink(); + bool isEqual = differences.Any() == false; + ResultToOutput(isEqual, differences); + + CollectionAssert.AreEquivalent(differences, rootContext.GetDifferences(true)); + + Assert.IsFalse(isEqual); + Assert.AreEqual(5, differences.Count()); + Assert.IsTrue(differences.Any(d => d.MemberPath == "Items" && d.Value1 == "1" && d.Value2 == "2" && d.DifferenceType == DifferenceTypes.NumberOfElementsMismatch)); + Assert.IsTrue(differences.Any(d => d.MemberPath == "Items[Id=1].Delay" && d.Value1 == "60" && d.Value2 == "80")); + Assert.IsTrue(differences.Any(d => d.MemberPath == "Items[Id=1].Name" && d.Value1 == "Item 1" && d.Value2 == "Item One")); + Assert.IsTrue(differences.Any(d => d.MemberPath == "Items[Id=1].Instruction" && d.Value1 == "Instruction 1" && d.Value2 == "Instruction One")); + Assert.IsTrue(differences.Any(d => d.DifferenceType == DifferenceTypes.MissedElementInFirstObject && d.Value1 == "" && d.Value2 == "ObjectsComparer.Examples.Example4.FormulaItem")); + } + } +} \ No newline at end of file diff --git a/ObjectsComparer/ObjectsComparer/Comparer.cs b/ObjectsComparer/ObjectsComparer/Comparer.cs index 335d26b..3b3829b 100644 --- a/ObjectsComparer/ObjectsComparer/Comparer.cs +++ b/ObjectsComparer/ObjectsComparer/Comparer.cs @@ -43,13 +43,21 @@ public IEnumerable CalculateDifferences(Type type, object obj1, obje var getObjectsComparerGenericMethod = getObjectsComparerMethod.MakeGenericMethod(type); var comparer = getObjectsComparerGenericMethod.Invoke(Factory, new object[] { Settings, this }); - bool comparerIsContextable = comparer.GetType().GetTypeInfo().GetInterfaces() + bool comparerIsIContextableComparerT = comparer.GetType().GetTypeInfo().GetInterfaces() .Any(intft => intft.GetTypeInfo().IsGenericType && intft.GetGenericTypeDefinition() == typeof(IContextableComparer<>)); - var genericType = comparerIsContextable ? typeof(IContextableComparer<>).MakeGenericType(type) : typeof(IComparer<>).MakeGenericType(type); - var genericMethodParameterTypes = comparerIsContextable ? new[] { type, type, typeof(ComparisonContext) } : new[] { type, type }; + if (comparerIsIContextableComparerT == false) + { + if (comparer is IContextableComparer contextableComparer) + { + return contextableComparer.CalculateDifferences(type, obj1, obj2, comparisonContext); + } + } + + var genericType = comparerIsIContextableComparerT ? typeof(IContextableComparer<>).MakeGenericType(type) : typeof(IComparer<>).MakeGenericType(type); + var genericMethodParameterTypes = comparerIsIContextableComparerT ? new[] { type, type, typeof(ComparisonContext) } : new[] { type, type }; var genericMethod = genericType.GetTypeInfo().GetMethod(CalculateDifferencesMethodName, genericMethodParameterTypes); - var genericMethodParameters = comparerIsContextable ? new[] { obj1, obj2, comparisonContext } : new[] { obj1, obj2 }; + var genericMethodParameters = comparerIsIContextableComparerT ? new[] { obj1, obj2, comparisonContext } : new[] { obj1, obj2 }; // ReSharper disable once PossibleNullReferenceException return (IEnumerable)genericMethod.Invoke(comparer, genericMethodParameters); diff --git a/ObjectsComparer/ObjectsComparer/ComparisonSettings.cs b/ObjectsComparer/ObjectsComparer/ComparisonSettings.cs index c8c6184..9248b98 100644 --- a/ObjectsComparer/ObjectsComparer/ComparisonSettings.cs +++ b/ObjectsComparer/ObjectsComparer/ComparisonSettings.cs @@ -99,12 +99,12 @@ public void ConfigureListComparison(Action comparisonOpti /// /// /// True value is shortcut for operation. - /// False value is shortcut for operation. + /// False value is shortcut for operation. Default value = false. /// /// - /// Shortcut for operation. + /// Shortcut for operation. Default value = false. /// - public void ConfigureListComparison(bool compareElementsByKey, bool compareUnequalLists) + public void ConfigureListComparison(bool compareElementsByKey = false, bool compareUnequalLists = false) { ConfigureListComparison(options => { From 11597f52e02930406d67ee6ed951e3de2ff1b61f Mon Sep 17 00:00:00 2001 From: "ASD\\nemec" Date: Mon, 6 Dec 2021 14:37:19 +0100 Subject: [PATCH 079/181] Edit AbstractDynamicObjectsComprer.CalculateDifferences. --- .../AbstractDynamicObjectsComprer.cs | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractDynamicObjectsComprer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractDynamicObjectsComprer.cs index a14869c..b1ae667 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractDynamicObjectsComprer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractDynamicObjectsComprer.cs @@ -33,6 +33,9 @@ public virtual IEnumerable CalculateDifferences(Type type, object ob foreach (var propertyKey in propertyKeys) { + //TODO: MemberInfo >> ComparsionContextMemberInfo { MemberInfo: Member } + var keyComparisonContext = ComparisonContext.Create(null, comparisonContext); + var existsInObject1 = propertyKeys1.Contains(propertyKey); var existsInObject2 = propertyKeys2.Contains(propertyKey); object value1 = null; @@ -71,7 +74,7 @@ public virtual IEnumerable CalculateDifferences(Type type, object ob { var difference = AddDifferenceToComparisonContext( new Difference(propertyKey, string.Empty, valueComparer.ToString(value2), DifferenceTypes.MissedMemberInFirstObject), - comparisonContext); + keyComparisonContext); yield return difference; continue; @@ -81,7 +84,7 @@ public virtual IEnumerable CalculateDifferences(Type type, object ob { var difference = AddDifferenceToComparisonContext( new Difference(propertyKey, valueComparer.ToString(value1), string.Empty, DifferenceTypes.MissedMemberInSecondObject), - comparisonContext); + keyComparisonContext); yield return difference; continue; @@ -96,7 +99,7 @@ public virtual IEnumerable CalculateDifferences(Type type, object ob var difference = AddDifferenceToComparisonContext( new Difference(propertyKey, valueComparer.ToString(value1), valueComparer2.ToString(value2), DifferenceTypes.TypeMismatch), - comparisonContext); + keyComparisonContext); yield return difference; continue; @@ -111,8 +114,8 @@ public virtual IEnumerable CalculateDifferences(Type type, object ob DefaultValueComparer; var difference = AddDifferenceToComparisonContext( - new Difference(propertyKey, valueComparer.ToString(value1), valueComparer2.ToString(value2), DifferenceTypes.TypeMismatch), - comparisonContext); + new Difference(propertyKey, valueComparer.ToString(value1), valueComparer2.ToString(value2), DifferenceTypes.TypeMismatch), + keyComparisonContext); yield return difference; continue; @@ -123,8 +126,8 @@ public virtual IEnumerable CalculateDifferences(Type type, object ob if (!customComparer.Compare(value1, value2, Settings)) { var difference = AddDifferenceToComparisonContext( - new Difference(propertyKey, customComparer.ToString(value1), customComparer.ToString(value2)), - comparisonContext); + new Difference(propertyKey, customComparer.ToString(value1), customComparer.ToString(value2)), + keyComparisonContext); yield return difference; } From 8a17518df553e7f721368eff9427c9fd10eb5071 Mon Sep 17 00:00:00 2001 From: nemec Date: Mon, 6 Dec 2021 23:43:37 +0100 Subject: [PATCH 080/181] Add ComparisonContextMemberBase, MemberInfoComparisonContextMember. --- .../ObjectsComparer/ComparisonContext.cs | 26 +++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/ObjectsComparer/ObjectsComparer/ComparisonContext.cs b/ObjectsComparer/ObjectsComparer/ComparisonContext.cs index 39a7978..8f27724 100644 --- a/ObjectsComparer/ObjectsComparer/ComparisonContext.cs +++ b/ObjectsComparer/ObjectsComparer/ComparisonContext.cs @@ -6,6 +6,28 @@ namespace ObjectsComparer { + public abstract class ComparisonContextMemberBase + { + public abstract string Name { get; } + } + + public class MemberInfoComparisonContextMember : ComparisonContextMemberBase + { + private MemberInfoComparisonContextMember(MemberInfo member) + { + Member = member ?? throw new ArgumentNullException(nameof(member)); + } + + public override string Name => throw new NotImplementedException(); + + public MemberInfo Member { get; } + + public static MemberInfoComparisonContextMember Create(MemberInfo member) + { + return new MemberInfoComparisonContextMember(member); + } + } + /// /// Information about the , which is typically a property or field, in comparison process. It has its ancestor and descendant objects in the same way as its has its ancestor and descendant members in an object graph. contains all possible member differences. /// Once the comparison is completed, it is possible to traverse the object graph and see differences at particular members. @@ -18,7 +40,7 @@ public sealed class ComparisonContext /// Creates comparison context root. /// /// - public static ComparisonContext CreateRoot() => new ComparisonContext(); + public static ComparisonContext CreateRoot() => Create(); readonly List _descendants = new List(); @@ -60,7 +82,7 @@ private ComparisonContext(MemberInfo currentMember) /// See . /// See . /// - internal static ComparisonContext Create(MemberInfo member = null, ComparisonContext ancestor = null) + public static ComparisonContext Create(MemberInfo member = null, ComparisonContext ancestor = null) { var context = new ComparisonContext(member); From 0624d444645340e4b1178e4a91ba5ad1fa1a9008 Mon Sep 17 00:00:00 2001 From: Daniel Nemec Date: Sat, 11 Dec 2021 00:57:35 +0100 Subject: [PATCH 081/181] Add namespace Context. Implement IComparisonContextMember. --- .../{ => Context}/ComparisonContext.cs | 30 +++---------------- .../{ => Context}/IComparerExtensions.cs | 0 .../Context/IComparisonContextMember.cs | 11 +++++++ .../{ => Context}/IContextableComparer.cs | 0 .../{ => Context}/IContextableComparer~1.cs | 0 .../ListElementComparisonContextMember.cs | 19 ++++++++++++ .../MemberInfoComparisonContextMember.cs | 22 ++++++++++++++ .../PropertyKeyComparisonContextMember.cs | 19 ++++++++++++ 8 files changed, 75 insertions(+), 26 deletions(-) rename ObjectsComparer/ObjectsComparer/{ => Context}/ComparisonContext.cs (85%) rename ObjectsComparer/ObjectsComparer/{ => Context}/IComparerExtensions.cs (100%) create mode 100644 ObjectsComparer/ObjectsComparer/Context/IComparisonContextMember.cs rename ObjectsComparer/ObjectsComparer/{ => Context}/IContextableComparer.cs (100%) rename ObjectsComparer/ObjectsComparer/{ => Context}/IContextableComparer~1.cs (100%) create mode 100644 ObjectsComparer/ObjectsComparer/Context/ListElementComparisonContextMember.cs create mode 100644 ObjectsComparer/ObjectsComparer/Context/MemberInfoComparisonContextMember.cs create mode 100644 ObjectsComparer/ObjectsComparer/Context/PropertyKeyComparisonContextMember.cs diff --git a/ObjectsComparer/ObjectsComparer/ComparisonContext.cs b/ObjectsComparer/ObjectsComparer/Context/ComparisonContext.cs similarity index 85% rename from ObjectsComparer/ObjectsComparer/ComparisonContext.cs rename to ObjectsComparer/ObjectsComparer/Context/ComparisonContext.cs index 8f27724..3a83a7a 100644 --- a/ObjectsComparer/ObjectsComparer/ComparisonContext.cs +++ b/ObjectsComparer/ObjectsComparer/Context/ComparisonContext.cs @@ -6,28 +6,6 @@ namespace ObjectsComparer { - public abstract class ComparisonContextMemberBase - { - public abstract string Name { get; } - } - - public class MemberInfoComparisonContextMember : ComparisonContextMemberBase - { - private MemberInfoComparisonContextMember(MemberInfo member) - { - Member = member ?? throw new ArgumentNullException(nameof(member)); - } - - public override string Name => throw new NotImplementedException(); - - public MemberInfo Member { get; } - - public static MemberInfoComparisonContextMember Create(MemberInfo member) - { - return new MemberInfoComparisonContextMember(member); - } - } - /// /// Information about the , which is typically a property or field, in comparison process. It has its ancestor and descendant objects in the same way as its has its ancestor and descendant members in an object graph. contains all possible member differences. /// Once the comparison is completed, it is possible to traverse the object graph and see differences at particular members. @@ -50,7 +28,7 @@ private ComparisonContext() { } - private ComparisonContext(MemberInfo currentMember) + private ComparisonContext(IComparisonContextMember currentMember) { Member = currentMember; } @@ -59,7 +37,7 @@ private ComparisonContext(MemberInfo currentMember) /// Typically a property or field in comparison process. /// It is always null for the root context (the starting point of the comparison) and always null for the list element. A list element never has a member, but it has an ancestor context which is the list and that list has its member. /// - public MemberInfo Member { get; } + public IComparisonContextMember Member { get; } /// /// Ancestor context. @@ -82,7 +60,7 @@ private ComparisonContext(MemberInfo currentMember) /// See . /// See . /// - public static ComparisonContext Create(MemberInfo member = null, ComparisonContext ancestor = null) + public static ComparisonContext Create(IComparisonContextMember member = null, ComparisonContext ancestor = null) { var context = new ComparisonContext(member); @@ -90,7 +68,7 @@ public static ComparisonContext Create(MemberInfo member = null, ComparisonConte { ancestor.AddDescendant(context); } - + return context; } diff --git a/ObjectsComparer/ObjectsComparer/IComparerExtensions.cs b/ObjectsComparer/ObjectsComparer/Context/IComparerExtensions.cs similarity index 100% rename from ObjectsComparer/ObjectsComparer/IComparerExtensions.cs rename to ObjectsComparer/ObjectsComparer/Context/IComparerExtensions.cs diff --git a/ObjectsComparer/ObjectsComparer/Context/IComparisonContextMember.cs b/ObjectsComparer/ObjectsComparer/Context/IComparisonContextMember.cs new file mode 100644 index 0000000..6fd8cc6 --- /dev/null +++ b/ObjectsComparer/ObjectsComparer/Context/IComparisonContextMember.cs @@ -0,0 +1,11 @@ +using System.Reflection; + +namespace ObjectsComparer +{ + public interface IComparisonContextMember + { + string Name { get; } + + MemberInfo Member { get; } + } +} \ No newline at end of file diff --git a/ObjectsComparer/ObjectsComparer/IContextableComparer.cs b/ObjectsComparer/ObjectsComparer/Context/IContextableComparer.cs similarity index 100% rename from ObjectsComparer/ObjectsComparer/IContextableComparer.cs rename to ObjectsComparer/ObjectsComparer/Context/IContextableComparer.cs diff --git a/ObjectsComparer/ObjectsComparer/IContextableComparer~1.cs b/ObjectsComparer/ObjectsComparer/Context/IContextableComparer~1.cs similarity index 100% rename from ObjectsComparer/ObjectsComparer/IContextableComparer~1.cs rename to ObjectsComparer/ObjectsComparer/Context/IContextableComparer~1.cs diff --git a/ObjectsComparer/ObjectsComparer/Context/ListElementComparisonContextMember.cs b/ObjectsComparer/ObjectsComparer/Context/ListElementComparisonContextMember.cs new file mode 100644 index 0000000..da9b092 --- /dev/null +++ b/ObjectsComparer/ObjectsComparer/Context/ListElementComparisonContextMember.cs @@ -0,0 +1,19 @@ +using System; +using System.Reflection; + +namespace ObjectsComparer +{ + public class ListElementComparisonContextMember : IComparisonContextMember + { + ListElementComparisonContextMember(MemberInfoComparisonContextMember listMember) + { + ListMember = listMember ?? throw new ArgumentNullException(nameof(listMember)); + } + + public MemberInfoComparisonContextMember ListMember { get; } + + public string Name => null; + + public MemberInfo Member => null; + } +} \ No newline at end of file diff --git a/ObjectsComparer/ObjectsComparer/Context/MemberInfoComparisonContextMember.cs b/ObjectsComparer/ObjectsComparer/Context/MemberInfoComparisonContextMember.cs new file mode 100644 index 0000000..2945d2f --- /dev/null +++ b/ObjectsComparer/ObjectsComparer/Context/MemberInfoComparisonContextMember.cs @@ -0,0 +1,22 @@ +using System; +using System.Reflection; + +namespace ObjectsComparer +{ + public class MemberInfoComparisonContextMember : IComparisonContextMember + { + MemberInfoComparisonContextMember(MemberInfo member) + { + Member = member ?? throw new ArgumentNullException(nameof(member)); + } + + public string Name => Member.Name; + + public MemberInfo Member { get; } + + public static MemberInfoComparisonContextMember Create(MemberInfo member) + { + return new MemberInfoComparisonContextMember(member); + } + } +} \ No newline at end of file diff --git a/ObjectsComparer/ObjectsComparer/Context/PropertyKeyComparisonContextMember.cs b/ObjectsComparer/ObjectsComparer/Context/PropertyKeyComparisonContextMember.cs new file mode 100644 index 0000000..c3ee8d4 --- /dev/null +++ b/ObjectsComparer/ObjectsComparer/Context/PropertyKeyComparisonContextMember.cs @@ -0,0 +1,19 @@ +using System; +using System.Reflection; + +namespace ObjectsComparer +{ + internal class PropertyKeyComparisonContextMember : IComparisonContextMember + { + PropertyKeyComparisonContextMember(string propertyKey) + { + PropertyKey = string.IsNullOrWhiteSpace(propertyKey) ? throw new ArgumentNullException(nameof(propertyKey)) : propertyKey; + } + + public string PropertyKey { get; } + + public string Name => PropertyKey; + + public MemberInfo Member => null; + } +} \ No newline at end of file From d1d19517aa22578df499f739717f1f250ac17dbb Mon Sep 17 00:00:00 2001 From: Daniel Nemec Date: Sat, 11 Dec 2021 20:52:48 +0100 Subject: [PATCH 082/181] Edit IComparisonContextMember implementors. --- ObjectsComparer/ObjectsComparer/Comparer~1.cs | 3 +- .../Context/ComparisonContext.cs | 40 +++++++++++++++++++ .../Context/IComparisonContextMember.cs | 5 ++- .../Context/ListComparisonContextMember.cs | 11 +++++ .../ListElementComparisonContextMember.cs | 6 +-- .../MemberInfoComparisonContextMember.cs | 13 ++---- .../PropertyKeyComparisonContextMember.cs | 4 +- 7 files changed, 66 insertions(+), 16 deletions(-) create mode 100644 ObjectsComparer/ObjectsComparer/Context/ListComparisonContextMember.cs diff --git a/ObjectsComparer/ObjectsComparer/Comparer~1.cs b/ObjectsComparer/ObjectsComparer/Comparer~1.cs index df842c9..3e3ada4 100644 --- a/ObjectsComparer/ObjectsComparer/Comparer~1.cs +++ b/ObjectsComparer/ObjectsComparer/Comparer~1.cs @@ -124,7 +124,8 @@ IEnumerable CalculateDifferences(T obj1, T obj2, MemberInfo memberIn continue; } - var memberContext = ComparisonContext.Create(member: member, ancestor: comparisonContext); + //var memberContext = ComparisonContext.Create(member: member, ancestor: comparisonContext); + var memberContext = ComparisonContext.ForMemberInfo(memberInfo: member, ancestor: comparisonContext); var valueComparer = DefaultValueComparer; var hasCustomComparer = false; diff --git a/ObjectsComparer/ObjectsComparer/Context/ComparisonContext.cs b/ObjectsComparer/ObjectsComparer/Context/ComparisonContext.cs index 3a83a7a..80ac4f5 100644 --- a/ObjectsComparer/ObjectsComparer/Context/ComparisonContext.cs +++ b/ObjectsComparer/ObjectsComparer/Context/ComparisonContext.cs @@ -153,5 +153,45 @@ public void Shrink() _descendants.RemoveAll(ctx => removeDescendants.Contains(ctx)); } } + + public static ComparisonContext ForListElement(ComparisonContext ancestor) + { + if (ancestor is null) + { + throw new ArgumentNullException(nameof(ancestor)); + } + + if (ancestor.Member is ListComparisonContextMember memberInfoMember) + { + var member = new ListElementComparisonContextMember(memberInfoMember); + return Create(member, ancestor); + } + + throw new ArgumentException("Ancestor's member must be ListComparisonContextMember.", nameof(ancestor)); + } + + public static ComparisonContext ForMemberInfo(MemberInfo memberInfo, ComparisonContext ancestor) + { + if (ancestor is null) + { + throw new ArgumentNullException(nameof(ancestor)); + } + + var member = new MemberInfoComparisonContextMember(memberInfo); + + return Create(member, ancestor); + } + + internal static ComparisonContext ForPropertyKey(string propertyKey, ComparisonContext ancestor) + { + if (propertyKey is null) + { + throw new ArgumentNullException(nameof(propertyKey)); + } + + var member = new PropertyKeyComparisonContextMember(propertyKey); + + return Create(member, ancestor); + } } } \ No newline at end of file diff --git a/ObjectsComparer/ObjectsComparer/Context/IComparisonContextMember.cs b/ObjectsComparer/ObjectsComparer/Context/IComparisonContextMember.cs index 6fd8cc6..fbeebfe 100644 --- a/ObjectsComparer/ObjectsComparer/Context/IComparisonContextMember.cs +++ b/ObjectsComparer/ObjectsComparer/Context/IComparisonContextMember.cs @@ -6,6 +6,9 @@ public interface IComparisonContextMember { string Name { get; } - MemberInfo Member { get; } + /// + /// Optional. + /// + MemberInfo Info { get; } } } \ No newline at end of file diff --git a/ObjectsComparer/ObjectsComparer/Context/ListComparisonContextMember.cs b/ObjectsComparer/ObjectsComparer/Context/ListComparisonContextMember.cs new file mode 100644 index 0000000..7b4a7a5 --- /dev/null +++ b/ObjectsComparer/ObjectsComparer/Context/ListComparisonContextMember.cs @@ -0,0 +1,11 @@ +using System.Reflection; + +namespace ObjectsComparer +{ + public class ListComparisonContextMember : MemberInfoComparisonContextMember + { + public ListComparisonContextMember(MemberInfo member) : base(member) + { + } + } +} \ No newline at end of file diff --git a/ObjectsComparer/ObjectsComparer/Context/ListElementComparisonContextMember.cs b/ObjectsComparer/ObjectsComparer/Context/ListElementComparisonContextMember.cs index da9b092..d6530b6 100644 --- a/ObjectsComparer/ObjectsComparer/Context/ListElementComparisonContextMember.cs +++ b/ObjectsComparer/ObjectsComparer/Context/ListElementComparisonContextMember.cs @@ -5,15 +5,15 @@ namespace ObjectsComparer { public class ListElementComparisonContextMember : IComparisonContextMember { - ListElementComparisonContextMember(MemberInfoComparisonContextMember listMember) + public ListElementComparisonContextMember(ListComparisonContextMember listMember) { ListMember = listMember ?? throw new ArgumentNullException(nameof(listMember)); } - public MemberInfoComparisonContextMember ListMember { get; } + public ListComparisonContextMember ListMember { get; } public string Name => null; - public MemberInfo Member => null; + public MemberInfo Info => null; } } \ No newline at end of file diff --git a/ObjectsComparer/ObjectsComparer/Context/MemberInfoComparisonContextMember.cs b/ObjectsComparer/ObjectsComparer/Context/MemberInfoComparisonContextMember.cs index 2945d2f..1731539 100644 --- a/ObjectsComparer/ObjectsComparer/Context/MemberInfoComparisonContextMember.cs +++ b/ObjectsComparer/ObjectsComparer/Context/MemberInfoComparisonContextMember.cs @@ -5,18 +5,13 @@ namespace ObjectsComparer { public class MemberInfoComparisonContextMember : IComparisonContextMember { - MemberInfoComparisonContextMember(MemberInfo member) + public MemberInfoComparisonContextMember(MemberInfo member) { - Member = member ?? throw new ArgumentNullException(nameof(member)); + Info = member ?? throw new ArgumentNullException(nameof(member)); } - public string Name => Member.Name; + public virtual string Name => Info.Name; - public MemberInfo Member { get; } - - public static MemberInfoComparisonContextMember Create(MemberInfo member) - { - return new MemberInfoComparisonContextMember(member); - } + public MemberInfo Info { get; } } } \ No newline at end of file diff --git a/ObjectsComparer/ObjectsComparer/Context/PropertyKeyComparisonContextMember.cs b/ObjectsComparer/ObjectsComparer/Context/PropertyKeyComparisonContextMember.cs index c3ee8d4..fd4d27a 100644 --- a/ObjectsComparer/ObjectsComparer/Context/PropertyKeyComparisonContextMember.cs +++ b/ObjectsComparer/ObjectsComparer/Context/PropertyKeyComparisonContextMember.cs @@ -5,7 +5,7 @@ namespace ObjectsComparer { internal class PropertyKeyComparisonContextMember : IComparisonContextMember { - PropertyKeyComparisonContextMember(string propertyKey) + public PropertyKeyComparisonContextMember(string propertyKey) { PropertyKey = string.IsNullOrWhiteSpace(propertyKey) ? throw new ArgumentNullException(nameof(propertyKey)) : propertyKey; } @@ -14,6 +14,6 @@ internal class PropertyKeyComparisonContextMember : IComparisonContextMember public string Name => PropertyKey; - public MemberInfo Member => null; + public MemberInfo Info => null; } } \ No newline at end of file From 0a8cc9042ee31ba8b211dc61cebb3be2213a57cc Mon Sep 17 00:00:00 2001 From: Daniel Nemec Date: Sat, 11 Dec 2021 23:35:25 +0100 Subject: [PATCH 083/181] Edit IComparisonContextMember implementors. --- .../ObjectsComparer/Context/ComparisonContext.cs | 4 ++-- .../Context/PropertyKeyComparisonContextMember.cs | 5 +++-- .../CustomComparers/AbstractDynamicObjectsComprer.cs | 10 +++++++--- .../CustomComparers/DynamicObjectComparer.cs | 3 ++- .../CustomComparers/EnumerablesComparerBase.cs | 9 ++++++--- .../CustomComparers/ExpandoObjectComparer.cs | 3 ++- 6 files changed, 22 insertions(+), 12 deletions(-) diff --git a/ObjectsComparer/ObjectsComparer/Context/ComparisonContext.cs b/ObjectsComparer/ObjectsComparer/Context/ComparisonContext.cs index 80ac4f5..027a475 100644 --- a/ObjectsComparer/ObjectsComparer/Context/ComparisonContext.cs +++ b/ObjectsComparer/ObjectsComparer/Context/ComparisonContext.cs @@ -182,14 +182,14 @@ public static ComparisonContext ForMemberInfo(MemberInfo memberInfo, ComparisonC return Create(member, ancestor); } - internal static ComparisonContext ForPropertyKey(string propertyKey, ComparisonContext ancestor) + internal static ComparisonContext ForPropertyKey(ComparisonContext ancestor, string propertyKey, MemberInfo info = null) { if (propertyKey is null) { throw new ArgumentNullException(nameof(propertyKey)); } - var member = new PropertyKeyComparisonContextMember(propertyKey); + var member = new PropertyKeyComparisonContextMember(propertyKey, info); return Create(member, ancestor); } diff --git a/ObjectsComparer/ObjectsComparer/Context/PropertyKeyComparisonContextMember.cs b/ObjectsComparer/ObjectsComparer/Context/PropertyKeyComparisonContextMember.cs index fd4d27a..cb4bc66 100644 --- a/ObjectsComparer/ObjectsComparer/Context/PropertyKeyComparisonContextMember.cs +++ b/ObjectsComparer/ObjectsComparer/Context/PropertyKeyComparisonContextMember.cs @@ -5,15 +5,16 @@ namespace ObjectsComparer { internal class PropertyKeyComparisonContextMember : IComparisonContextMember { - public PropertyKeyComparisonContextMember(string propertyKey) + public PropertyKeyComparisonContextMember(string propertyKey, MemberInfo info = null) { PropertyKey = string.IsNullOrWhiteSpace(propertyKey) ? throw new ArgumentNullException(nameof(propertyKey)) : propertyKey; + Info = info; } public string PropertyKey { get; } public string Name => PropertyKey; - public MemberInfo Info => null; + public MemberInfo Info { get; } } } \ No newline at end of file diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractDynamicObjectsComprer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractDynamicObjectsComprer.cs index b1ae667..246f514 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractDynamicObjectsComprer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractDynamicObjectsComprer.cs @@ -33,23 +33,27 @@ public virtual IEnumerable CalculateDifferences(Type type, object ob foreach (var propertyKey in propertyKeys) { - //TODO: MemberInfo >> ComparsionContextMemberInfo { MemberInfo: Member } - var keyComparisonContext = ComparisonContext.Create(null, comparisonContext); - var existsInObject1 = propertyKeys1.Contains(propertyKey); var existsInObject2 = propertyKeys2.Contains(propertyKey); object value1 = null; + MemberInfo member1 = null; if (existsInObject1) { TryGetMemberValue(castedObject1, propertyKey, out value1); + TryGetMember(castedObject1, propertyKey, out member1); } object value2 = null; + MemberInfo member2 = null; if (existsInObject2) { TryGetMemberValue(castedObject2, propertyKey, out value2); + TryGetMember(castedObject1, propertyKey, out member2); } + //var keyComparisonContext = ComparisonContext.Create(null, comparisonContext); + var keyComparisonContext = ComparisonContext.ForPropertyKey(ancestor: comparisonContext, propertyKey, info: member1 ?? member2); + var propertyType = (value1 ?? value2)?.GetType() ?? typeof(object); var customComparer = OverridesCollection.GetComparer(propertyType) ?? OverridesCollection.GetComparer(propertyKey); diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/DynamicObjectComparer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/DynamicObjectComparer.cs index 3d830e0..1b6c141 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/DynamicObjectComparer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/DynamicObjectComparer.cs @@ -62,7 +62,8 @@ protected override bool TryGetMemberValue(DynamicObject obj, string propertyName protected override bool TryGetMember(DynamicObject obj, string propertyName, out MemberInfo value) { - throw new NotImplementedException(); + value = null; + return false; } } } diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparerBase.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparerBase.cs index b000d50..14bc2e1 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparerBase.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparerBase.cs @@ -44,7 +44,8 @@ protected virtual IEnumerable CalculateDifferencesByKey(IList for (int element1Index = 0; element1Index < array1.Count(); element1Index++) { var element1 = array1[element1Index]; - var elementComparisonContext = ComparisonContext.Create(ancestor: listComparisonContext); + //var elementComparisonContext = ComparisonContext.Create(ancestor: listComparisonContext); + var elementComparisonContext = ComparisonContext.ForListElement(ancestor: listComparisonContext); if (element1 == null) { @@ -93,7 +94,8 @@ protected virtual IEnumerable CalculateDifferencesByKey(IList for (int element2Index = 0; element2Index < array2.Count(); element2Index++) { var element2 = array2[element2Index]; - var elementComparisonContext = ComparisonContext.Create(ancestor: listComparisonContext); + //var elementComparisonContext = ComparisonContext.Create(ancestor: listComparisonContext); + var elementComparisonContext = ComparisonContext.ForListElement(ancestor: listComparisonContext); if (element2 == null) { @@ -143,7 +145,8 @@ protected virtual IEnumerable CalculateDifferencesByIndex(IList GetProperties(ExpandoObject obj) protected override bool TryGetMember(ExpandoObject obj, string propertyName, out MemberInfo value) { - throw new NotImplementedException(); + value = null; + return false; } protected override bool TryGetMemberValue(ExpandoObject obj, string propertyName, out object value) From 723358d744e03aa4beb4db37b5518edff06508a4 Mon Sep 17 00:00:00 2001 From: nemec Date: Wed, 15 Dec 2021 17:33:06 +0100 Subject: [PATCH 084/181] The only implementation of interface IComparisonContextMember. --- ObjectsComparer/ObjectsComparer/Comparer~1.cs | 2 +- .../Context/ComparisonContext.cs | 41 +------------------ .../Context/ComparisonContextMember.cs | 30 ++++++++++++++ .../Context/ListComparisonContextMember.cs | 11 ----- .../ListElementComparisonContextMember.cs | 19 --------- .../MemberInfoComparisonContextMember.cs | 17 -------- .../PropertyKeyComparisonContextMember.cs | 20 --------- .../AbstractDynamicObjectsComprer.cs | 3 +- .../EnumerablesComparerBase.cs | 6 +-- 9 files changed, 37 insertions(+), 112 deletions(-) create mode 100644 ObjectsComparer/ObjectsComparer/Context/ComparisonContextMember.cs delete mode 100644 ObjectsComparer/ObjectsComparer/Context/ListComparisonContextMember.cs delete mode 100644 ObjectsComparer/ObjectsComparer/Context/ListElementComparisonContextMember.cs delete mode 100644 ObjectsComparer/ObjectsComparer/Context/MemberInfoComparisonContextMember.cs delete mode 100644 ObjectsComparer/ObjectsComparer/Context/PropertyKeyComparisonContextMember.cs diff --git a/ObjectsComparer/ObjectsComparer/Comparer~1.cs b/ObjectsComparer/ObjectsComparer/Comparer~1.cs index 3e3ada4..f6d354d 100644 --- a/ObjectsComparer/ObjectsComparer/Comparer~1.cs +++ b/ObjectsComparer/ObjectsComparer/Comparer~1.cs @@ -125,7 +125,7 @@ IEnumerable CalculateDifferences(T obj1, T obj2, MemberInfo memberIn } //var memberContext = ComparisonContext.Create(member: member, ancestor: comparisonContext); - var memberContext = ComparisonContext.ForMemberInfo(memberInfo: member, ancestor: comparisonContext); + var memberContext = ComparisonContext.Create(new ComparisonContextMember(member), comparisonContext); var valueComparer = DefaultValueComparer; var hasCustomComparer = false; diff --git a/ObjectsComparer/ObjectsComparer/Context/ComparisonContext.cs b/ObjectsComparer/ObjectsComparer/Context/ComparisonContext.cs index 027a475..42940e2 100644 --- a/ObjectsComparer/ObjectsComparer/Context/ComparisonContext.cs +++ b/ObjectsComparer/ObjectsComparer/Context/ComparisonContext.cs @@ -18,6 +18,7 @@ public sealed class ComparisonContext /// Creates comparison context root. /// /// + [Obsolete("", true)] public static ComparisonContext CreateRoot() => Create(); readonly List _descendants = new List(); @@ -153,45 +154,5 @@ public void Shrink() _descendants.RemoveAll(ctx => removeDescendants.Contains(ctx)); } } - - public static ComparisonContext ForListElement(ComparisonContext ancestor) - { - if (ancestor is null) - { - throw new ArgumentNullException(nameof(ancestor)); - } - - if (ancestor.Member is ListComparisonContextMember memberInfoMember) - { - var member = new ListElementComparisonContextMember(memberInfoMember); - return Create(member, ancestor); - } - - throw new ArgumentException("Ancestor's member must be ListComparisonContextMember.", nameof(ancestor)); - } - - public static ComparisonContext ForMemberInfo(MemberInfo memberInfo, ComparisonContext ancestor) - { - if (ancestor is null) - { - throw new ArgumentNullException(nameof(ancestor)); - } - - var member = new MemberInfoComparisonContextMember(memberInfo); - - return Create(member, ancestor); - } - - internal static ComparisonContext ForPropertyKey(ComparisonContext ancestor, string propertyKey, MemberInfo info = null) - { - if (propertyKey is null) - { - throw new ArgumentNullException(nameof(propertyKey)); - } - - var member = new PropertyKeyComparisonContextMember(propertyKey, info); - - return Create(member, ancestor); - } } } \ No newline at end of file diff --git a/ObjectsComparer/ObjectsComparer/Context/ComparisonContextMember.cs b/ObjectsComparer/ObjectsComparer/Context/ComparisonContextMember.cs new file mode 100644 index 0000000..43cb7d9 --- /dev/null +++ b/ObjectsComparer/ObjectsComparer/Context/ComparisonContextMember.cs @@ -0,0 +1,30 @@ +using System.Reflection; + +namespace ObjectsComparer +{ + internal class ComparisonContextMember : IComparisonContextMember + { + public ComparisonContextMember() + { + } + + public ComparisonContextMember(string name) + { + if (string.IsNullOrWhiteSpace(name)) + { + throw new System.ArgumentException($"'{nameof(name)}' cannot be null or whitespace.", nameof(name)); + } + + Name = name; + } + + public ComparisonContextMember(MemberInfo info) + { + Info = info ?? throw new System.ArgumentNullException(nameof(info)); + } + + public string Name { get; } + + public MemberInfo Info { get; } + } +} \ No newline at end of file diff --git a/ObjectsComparer/ObjectsComparer/Context/ListComparisonContextMember.cs b/ObjectsComparer/ObjectsComparer/Context/ListComparisonContextMember.cs deleted file mode 100644 index 7b4a7a5..0000000 --- a/ObjectsComparer/ObjectsComparer/Context/ListComparisonContextMember.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System.Reflection; - -namespace ObjectsComparer -{ - public class ListComparisonContextMember : MemberInfoComparisonContextMember - { - public ListComparisonContextMember(MemberInfo member) : base(member) - { - } - } -} \ No newline at end of file diff --git a/ObjectsComparer/ObjectsComparer/Context/ListElementComparisonContextMember.cs b/ObjectsComparer/ObjectsComparer/Context/ListElementComparisonContextMember.cs deleted file mode 100644 index d6530b6..0000000 --- a/ObjectsComparer/ObjectsComparer/Context/ListElementComparisonContextMember.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System; -using System.Reflection; - -namespace ObjectsComparer -{ - public class ListElementComparisonContextMember : IComparisonContextMember - { - public ListElementComparisonContextMember(ListComparisonContextMember listMember) - { - ListMember = listMember ?? throw new ArgumentNullException(nameof(listMember)); - } - - public ListComparisonContextMember ListMember { get; } - - public string Name => null; - - public MemberInfo Info => null; - } -} \ No newline at end of file diff --git a/ObjectsComparer/ObjectsComparer/Context/MemberInfoComparisonContextMember.cs b/ObjectsComparer/ObjectsComparer/Context/MemberInfoComparisonContextMember.cs deleted file mode 100644 index 1731539..0000000 --- a/ObjectsComparer/ObjectsComparer/Context/MemberInfoComparisonContextMember.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System; -using System.Reflection; - -namespace ObjectsComparer -{ - public class MemberInfoComparisonContextMember : IComparisonContextMember - { - public MemberInfoComparisonContextMember(MemberInfo member) - { - Info = member ?? throw new ArgumentNullException(nameof(member)); - } - - public virtual string Name => Info.Name; - - public MemberInfo Info { get; } - } -} \ No newline at end of file diff --git a/ObjectsComparer/ObjectsComparer/Context/PropertyKeyComparisonContextMember.cs b/ObjectsComparer/ObjectsComparer/Context/PropertyKeyComparisonContextMember.cs deleted file mode 100644 index cb4bc66..0000000 --- a/ObjectsComparer/ObjectsComparer/Context/PropertyKeyComparisonContextMember.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System; -using System.Reflection; - -namespace ObjectsComparer -{ - internal class PropertyKeyComparisonContextMember : IComparisonContextMember - { - public PropertyKeyComparisonContextMember(string propertyKey, MemberInfo info = null) - { - PropertyKey = string.IsNullOrWhiteSpace(propertyKey) ? throw new ArgumentNullException(nameof(propertyKey)) : propertyKey; - Info = info; - } - - public string PropertyKey { get; } - - public string Name => PropertyKey; - - public MemberInfo Info { get; } - } -} \ No newline at end of file diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractDynamicObjectsComprer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractDynamicObjectsComprer.cs index 246f514..7960ce9 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractDynamicObjectsComprer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractDynamicObjectsComprer.cs @@ -52,7 +52,8 @@ public virtual IEnumerable CalculateDifferences(Type type, object ob } //var keyComparisonContext = ComparisonContext.Create(null, comparisonContext); - var keyComparisonContext = ComparisonContext.ForPropertyKey(ancestor: comparisonContext, propertyKey, info: member1 ?? member2); + var keyComparisonContextMember = (member1 ?? member2) != null ? new ComparisonContextMember(member1 ?? member2) : new ComparisonContextMember(propertyKey); + var keyComparisonContext = ComparisonContext.Create(keyComparisonContextMember, comparisonContext); var propertyType = (value1 ?? value2)?.GetType() ?? typeof(object); var customComparer = OverridesCollection.GetComparer(propertyType) ?? diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparerBase.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparerBase.cs index 14bc2e1..d28bd26 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparerBase.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparerBase.cs @@ -45,7 +45,7 @@ protected virtual IEnumerable CalculateDifferencesByKey(IList { var element1 = array1[element1Index]; //var elementComparisonContext = ComparisonContext.Create(ancestor: listComparisonContext); - var elementComparisonContext = ComparisonContext.ForListElement(ancestor: listComparisonContext); + var elementComparisonContext = ComparisonContext.Create(new ComparisonContextMember(), listComparisonContext); if (element1 == null) { @@ -95,7 +95,7 @@ protected virtual IEnumerable CalculateDifferencesByKey(IList { var element2 = array2[element2Index]; //var elementComparisonContext = ComparisonContext.Create(ancestor: listComparisonContext); - var elementComparisonContext = ComparisonContext.ForListElement(ancestor: listComparisonContext); + var elementComparisonContext = ComparisonContext.Create(new ComparisonContextMember(), listComparisonContext); if (element2 == null) { @@ -146,7 +146,7 @@ protected virtual IEnumerable CalculateDifferencesByIndex(IList Date: Thu, 16 Dec 2021 15:31:50 +0100 Subject: [PATCH 085/181] Replace static factory methods with constructors. --- .../Example4Tests_BuiltInKeyComparison.cs | 2 +- .../Comparer_CompilerGeneratedObjectsTests.cs | 4 +- .../Comparer_ExpandoObjectsTests.cs | 4 +- .../Comparer_GenericEnumerableTests.cs | 2 +- .../Comparer_MultidimensionalArraysTests.cs | 2 +- .../Comparer_NonGenericEnumerableTests.cs | 2 +- .../ComparisonSettingsTests.cs | 2 +- ...omparisonContextSerializationExtensions.cs | 2 +- ObjectsComparer/ObjectsComparer/Comparer.cs | 2 +- ObjectsComparer/ObjectsComparer/Comparer~1.cs | 5 +- .../Context/ComparisonContext.cs | 47 ++++++++----------- .../Context/IComparerExtensions.cs | 2 +- .../AbstractDynamicObjectsComprer.cs | 7 ++- .../CustomComparers/EnumerablesComparer.cs | 2 +- .../EnumerablesComparerBase.cs | 11 ++--- .../CustomComparers/EnumerablesComparer~1.cs | 2 +- .../GenericEnumerablesComparer.cs | 2 +- .../CustomComparers/HashSetsComparer.cs | 2 +- .../CustomComparers/HashSetsComparer~1.cs | 2 +- .../MultidimensionalArrayComparer~1.cs | 2 +- .../MultidimensionalArraysComparer.cs | 2 +- .../CustomComparers/TypesComparer.cs | 2 +- 22 files changed, 49 insertions(+), 61 deletions(-) diff --git a/ObjectsComparer/ObjectsComparer.Examples/Example4/Example4Tests_BuiltInKeyComparison.cs b/ObjectsComparer/ObjectsComparer.Examples/Example4/Example4Tests_BuiltInKeyComparison.cs index 1e9806b..a2a367e 100644 --- a/ObjectsComparer/ObjectsComparer.Examples/Example4/Example4Tests_BuiltInKeyComparison.cs +++ b/ObjectsComparer/ObjectsComparer.Examples/Example4/Example4Tests_BuiltInKeyComparison.cs @@ -289,7 +289,7 @@ public void List_Of_Different_Sizes_But_Is_Inequality_FormatKey_CheckComparisonC .FormatElementKey(formatKeyArgs => $"Id={formatKeyArgs.ElementKey}"))); var comparer = new Comparer(settings); - var rootContext = ComparisonContext.CreateRoot(); + var rootContext = new ComparisonContext(); var differences = comparer.CalculateDifferences(formula1, formula2, rootContext).ToArray(); rootContext.Shrink(); bool isEqual = differences.Any() == false; diff --git a/ObjectsComparer/ObjectsComparer.Tests/Comparer_CompilerGeneratedObjectsTests.cs b/ObjectsComparer/ObjectsComparer.Tests/Comparer_CompilerGeneratedObjectsTests.cs index a6ed9c6..fe76fac 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/Comparer_CompilerGeneratedObjectsTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/Comparer_CompilerGeneratedObjectsTests.cs @@ -79,7 +79,7 @@ public void MissedFields_CheckComparisonContext() var comparer = new Comparer(); - var comparisonContext = ComparisonContext.CreateRoot(); + var comparisonContext = new ComparisonContext(); IEnumerable calculateDifferences = comparer.CalculateDifferences(typeof(object), (object)a1, (object)a2, comparisonContext).ToArray(); var comparisonContextDifferences = comparisonContext.GetDifferences(true).ToArray(); @@ -220,7 +220,7 @@ public void NullAndMissedMemberAreNotEqual_CheckComparisonContext() var comparer = new Comparer(); - var comparisonContext = ComparisonContext.CreateRoot(); + var comparisonContext = new ComparisonContext(); var calculateDifferences = comparer.CalculateDifferences(typeof(object), (object)a1, (object)a2, comparisonContext).ToArray(); var comparisonContextDifferences = comparisonContext.GetDifferences(true).ToArray(); diff --git a/ObjectsComparer/ObjectsComparer.Tests/Comparer_ExpandoObjectsTests.cs b/ObjectsComparer/ObjectsComparer.Tests/Comparer_ExpandoObjectsTests.cs index 3d41e1e..d714f71 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/Comparer_ExpandoObjectsTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/Comparer_ExpandoObjectsTests.cs @@ -266,7 +266,7 @@ public void UseDefaultValuesWhenSubclassNotSpecified_CheckComparisonContext() dynamic a2 = new ExpandoObject(); var comparer = new Comparer(new ComparisonSettings { UseDefaultIfMemberNotExist = true }); - var rootComparisonContext = ComparisonContext.CreateRoot(); + var rootComparisonContext = new ComparisonContext(); IEnumerable diffs = comparer.CalculateDifferences(((object)a1).GetType(), a1, a2, rootComparisonContext); var differences = diffs.ToArray(); var comparisonContextDifferences = rootComparisonContext.GetDifferences(recursive: true).ToList(); @@ -314,7 +314,7 @@ public void DifferenceWhenSubclassNotSpecified_CheckComparisonContext() Assert.IsTrue(compareDifferences.Any( d => d.MemberPath == "Field1" && d.DifferenceType == DifferenceTypes.MissedMemberInSecondObject)); - var rootComparisonContext = ComparisonContext.CreateRoot(); + var rootComparisonContext = new ComparisonContext(); IEnumerable calculateDiffs = comparer.CalculateDifferences(((object)a1).GetType(), a1, a2, rootComparisonContext); var calculateDifferences = calculateDiffs.ToList(); var comparisonContextDifferences = rootComparisonContext.GetDifferences(recursive: true).ToList(); diff --git a/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs b/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs index 4da0c8c..3538d0c 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs @@ -67,7 +67,7 @@ public void PrimitiveTypeArrayInequalityCount_CompareUnequalLists() settings.ConfigureListComparison(listOptions => listOptions.CompareUnequalLists(true)); var comparer = new Comparer(settings); - var rootCtx = ComparisonContext.CreateRoot(); + var rootCtx = new ComparisonContext(); var differences = comparer.CalculateDifferences(a1, a2, rootCtx).ToList(); CollectionAssert.IsNotEmpty(differences); diff --git a/ObjectsComparer/ObjectsComparer.Tests/Comparer_MultidimensionalArraysTests.cs b/ObjectsComparer/ObjectsComparer.Tests/Comparer_MultidimensionalArraysTests.cs index 4135aa9..6ad5684 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/Comparer_MultidimensionalArraysTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/Comparer_MultidimensionalArraysTests.cs @@ -412,7 +412,7 @@ public void IntIntInequality7_CheckComparisonContext() var a2 = new MultidimensionalArrays { IntInt = null }; var comparer = new Comparer(); - var rootComparisonContext = ComparisonContext.CreateRoot(); + var rootComparisonContext = new ComparisonContext(); var differences = comparer.CalculateDifferences(a1, a2, rootComparisonContext).ToList(); CollectionAssert.IsNotEmpty(differences); diff --git a/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs b/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs index 1734251..a998e07 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs @@ -187,7 +187,7 @@ public void InequalityProperty_CompareByKey() var comparer = new Comparer(settings); - var rootCtx = ComparisonContext.CreateRoot(); + var rootCtx = new ComparisonContext(); var differences = comparer.CalculateDifferences(a1, a2, rootCtx).ToList(); CollectionAssert.IsNotEmpty(differences); diff --git a/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs b/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs index 84cca62..40fe715 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs @@ -77,7 +77,7 @@ public void CompareListElementsByKeyIsCorrectlySet() //Component side. var listComparisonOptions = ListComparisonOptions.Default(); - var ctx = ComparisonContext.Create(); + var ctx = new ComparisonContext(); settings.ListComparisonOptionsAction(ctx, listComparisonOptions); var listElementComparisonByKeyOptions = ListElementComparisonByKeyOptions.Default(); listComparisonOptions.KeyOptionsAction(listElementComparisonByKeyOptions); diff --git a/ObjectsComparer/ObjectsComparer.Tests/Utils/ComparisonContextSerializationExtensions.cs b/ObjectsComparer/ObjectsComparer.Tests/Utils/ComparisonContextSerializationExtensions.cs index 0e549da..a6e3d71 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/Utils/ComparisonContextSerializationExtensions.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/Utils/ComparisonContextSerializationExtensions.cs @@ -121,7 +121,7 @@ protected override JsonProperty CreateProperty(MemberInfo member, MemberSerializ // public object GetValue(object target) // { // var ancestor = (target as ComparisonContext).Ancestor; - // var newAncestor = ComparisonContext.Create(member: ancestor?.Member); + // var newAncestor = new ComparisonContext(member: ancestor?.Member); // return newAncestor; // } diff --git a/ObjectsComparer/ObjectsComparer/Comparer.cs b/ObjectsComparer/ObjectsComparer/Comparer.cs index 3b3829b..45d0b3e 100644 --- a/ObjectsComparer/ObjectsComparer/Comparer.cs +++ b/ObjectsComparer/ObjectsComparer/Comparer.cs @@ -29,7 +29,7 @@ public Comparer(ComparisonSettings settings = null, BaseComparer parentComparer public override IEnumerable CalculateDifferences(Type type, object obj1, object obj2) { - return CalculateDifferences(type, obj1, obj2, ComparisonContext.CreateRoot()); + return CalculateDifferences(type, obj1, obj2, new ComparisonContext()); } public IEnumerable CalculateDifferences(Type type, object obj1, object obj2, ComparisonContext comparisonContext) diff --git a/ObjectsComparer/ObjectsComparer/Comparer~1.cs b/ObjectsComparer/ObjectsComparer/Comparer~1.cs index f6d354d..48baad4 100644 --- a/ObjectsComparer/ObjectsComparer/Comparer~1.cs +++ b/ObjectsComparer/ObjectsComparer/Comparer~1.cs @@ -63,7 +63,7 @@ public IEnumerable CalculateDifferences(T obj1, T obj2, ComparisonCo internal IEnumerable CalculateDifferences(T obj1, T obj2, MemberInfo memberInfo) { - return CalculateDifferences(obj1, obj2, memberInfo, ComparisonContext.CreateRoot()); + return CalculateDifferences(obj1, obj2, memberInfo, new ComparisonContext()); } IEnumerable CalculateDifferences(T obj1, T obj2, MemberInfo memberInfo, ComparisonContext comparisonContext) @@ -124,8 +124,7 @@ IEnumerable CalculateDifferences(T obj1, T obj2, MemberInfo memberIn continue; } - //var memberContext = ComparisonContext.Create(member: member, ancestor: comparisonContext); - var memberContext = ComparisonContext.Create(new ComparisonContextMember(member), comparisonContext); + var memberContext = new ComparisonContext(new ComparisonContextMember(member), comparisonContext); var valueComparer = DefaultValueComparer; var hasCustomComparer = false; diff --git a/ObjectsComparer/ObjectsComparer/Context/ComparisonContext.cs b/ObjectsComparer/ObjectsComparer/Context/ComparisonContext.cs index 42940e2..4d5b159 100644 --- a/ObjectsComparer/ObjectsComparer/Context/ComparisonContext.cs +++ b/ObjectsComparer/ObjectsComparer/Context/ComparisonContext.cs @@ -14,21 +14,32 @@ public sealed class ComparisonContext { object _shrinkLock = new object(); - /// - /// Creates comparison context root. - /// - /// - [Obsolete("", true)] - public static ComparisonContext CreateRoot() => Create(); - readonly List _descendants = new List(); readonly List _differences = new List(); - private ComparisonContext() + public ComparisonContext(IComparisonContextMember member = null, ComparisonContext ancestor = null) { + Member = member; + + if (ancestor != null) + { + ancestor.AddDescendant(this); + } } + //public static ComparisonContext Create(IComparisonContextMember member = null, ComparisonContext ancestor = null) + //{ + // var context = new ComparisonContext(member); + + // if (ancestor != null) + // { + // ancestor.AddDescendant(context); + // } + + // return context; + //} + private ComparisonContext(IComparisonContextMember currentMember) { Member = currentMember; @@ -54,25 +65,7 @@ private ComparisonContext(IComparisonContextMember currentMember) /// A list of differences directly related to this context. /// public ReadOnlyCollection Differences => _differences.AsReadOnly(); - - /// - /// - /// - /// See . - /// See . - /// - public static ComparisonContext Create(IComparisonContextMember member = null, ComparisonContext ancestor = null) - { - var context = new ComparisonContext(member); - - if (ancestor != null) - { - ancestor.AddDescendant(context); - } - - return context; - } - + void AddDescendant(ComparisonContext descendant) { _descendants.Add(descendant); diff --git a/ObjectsComparer/ObjectsComparer/Context/IComparerExtensions.cs b/ObjectsComparer/ObjectsComparer/Context/IComparerExtensions.cs index c183b91..27d151c 100644 --- a/ObjectsComparer/ObjectsComparer/Context/IComparerExtensions.cs +++ b/ObjectsComparer/ObjectsComparer/Context/IComparerExtensions.cs @@ -11,7 +11,7 @@ public static class IComparerExtensions { /// /// Calculates list of differences between objects. Accepts comparison context. - /// At the beginning of the comparison you can create instance using the operation and pass it as a parameter. + /// At the beginning of the comparison you can create instance using the operation and pass it as a parameter. /// For more info about comparison context see class. /// /// Type. diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractDynamicObjectsComprer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractDynamicObjectsComprer.cs index 7960ce9..a2b350f 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractDynamicObjectsComprer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractDynamicObjectsComprer.cs @@ -14,12 +14,12 @@ protected AbstractDynamicObjectsComprer(ComparisonSettings settings, BaseCompare public override IEnumerable CalculateDifferences(Type type, object obj1, object obj2) { - return CalculateDifferences(type, obj1, obj2, ComparisonContext.CreateRoot()); + return CalculateDifferences(type, obj1, obj2, new ComparisonContext()); } public virtual IEnumerable CalculateDifferences(T obj1, T obj2, ComparisonContext comparisonContext) { - return CalculateDifferences(typeof(T), obj1, obj2, ComparisonContext.CreateRoot()); + return CalculateDifferences(typeof(T), obj1, obj2, new ComparisonContext()); } public virtual IEnumerable CalculateDifferences(Type type, object obj1, object obj2, ComparisonContext comparisonContext) @@ -51,9 +51,8 @@ public virtual IEnumerable CalculateDifferences(Type type, object ob TryGetMember(castedObject1, propertyKey, out member2); } - //var keyComparisonContext = ComparisonContext.Create(null, comparisonContext); var keyComparisonContextMember = (member1 ?? member2) != null ? new ComparisonContextMember(member1 ?? member2) : new ComparisonContextMember(propertyKey); - var keyComparisonContext = ComparisonContext.Create(keyComparisonContextMember, comparisonContext); + var keyComparisonContext = new ComparisonContext(keyComparisonContextMember, comparisonContext); var propertyType = (value1 ?? value2)?.GetType() ?? typeof(object); var customComparer = OverridesCollection.GetComparer(propertyType) ?? diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs index 3ed6549..42bbbf0 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs @@ -17,7 +17,7 @@ public EnumerablesComparer(ComparisonSettings settings, BaseComparer parentCompa public override IEnumerable CalculateDifferences(Type type, object obj1, object obj2) { - return CalculateDifferences(type, obj1, obj2, ComparisonContext.CreateRoot()); + return CalculateDifferences(type, obj1, obj2, new ComparisonContext()); } public IEnumerable CalculateDifferences(Type type, object obj1, object obj2, ComparisonContext listComparisonContext) diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparerBase.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparerBase.cs index d28bd26..c981430 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparerBase.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparerBase.cs @@ -44,8 +44,7 @@ protected virtual IEnumerable CalculateDifferencesByKey(IList for (int element1Index = 0; element1Index < array1.Count(); element1Index++) { var element1 = array1[element1Index]; - //var elementComparisonContext = ComparisonContext.Create(ancestor: listComparisonContext); - var elementComparisonContext = ComparisonContext.Create(new ComparisonContextMember(), listComparisonContext); + var elementComparisonContext = new ComparisonContext(new ComparisonContextMember(), listComparisonContext); if (element1 == null) { @@ -94,8 +93,7 @@ protected virtual IEnumerable CalculateDifferencesByKey(IList for (int element2Index = 0; element2Index < array2.Count(); element2Index++) { var element2 = array2[element2Index]; - //var elementComparisonContext = ComparisonContext.Create(ancestor: listComparisonContext); - var elementComparisonContext = ComparisonContext.Create(new ComparisonContextMember(), listComparisonContext); + var elementComparisonContext = new ComparisonContext(new ComparisonContextMember(), listComparisonContext); if (element2 == null) { @@ -145,8 +143,7 @@ protected virtual IEnumerable CalculateDifferencesByIndex(IList CalculateDifferencesByIndex(IList array1Count ? valueComparer.ToString(largerArray[i]) : string.Empty, differenceType: array1Count > array2Count ? DifferenceTypes.MissedElementInSecondObject : DifferenceTypes.MissedElementInFirstObject); - yield return AddDifferenceToComparisonContext(difference, ComparisonContext.Create(ancestor: listComparisonContext)); + yield return AddDifferenceToComparisonContext(difference, new ComparisonContext(ancestor: listComparisonContext)); } } } diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer~1.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer~1.cs index 40577c6..cb415be 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer~1.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer~1.cs @@ -18,7 +18,7 @@ public EnumerablesComparer(ComparisonSettings settings, BaseComparer parentCompa public override IEnumerable CalculateDifferences(Type type, object obj1, object obj2) { - return CalculateDifferences(type, obj1, obj2, ComparisonContext.CreateRoot()); + return CalculateDifferences(type, obj1, obj2, new ComparisonContext()); } public IEnumerable CalculateDifferences(Type type, object obj1, object obj2, ComparisonContext listComparisonContext) diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/GenericEnumerablesComparer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/GenericEnumerablesComparer.cs index ac995fa..daf9c2e 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/GenericEnumerablesComparer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/GenericEnumerablesComparer.cs @@ -17,7 +17,7 @@ public GenericEnumerablesComparer(ComparisonSettings settings, BaseComparer pare public override IEnumerable CalculateDifferences(Type type, object obj1, object obj2) { - return CalculateDifferences(type, obj1, obj2, ComparisonContext.CreateRoot()); + return CalculateDifferences(type, obj1, obj2, new ComparisonContext()); } public override IEnumerable CalculateDifferences(Type type, object obj1, object obj2, ComparisonContext comparisonContext) diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/HashSetsComparer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/HashSetsComparer.cs index eb3597c..2a84ff3 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/HashSetsComparer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/HashSetsComparer.cs @@ -15,7 +15,7 @@ public HashSetsComparer(ComparisonSettings settings, BaseComparer parentComparer public override IEnumerable CalculateDifferences(Type type, object obj1, object obj2) { - return CalculateDifferences(type, obj1, obj2, ComparisonContext.CreateRoot()); + return CalculateDifferences(type, obj1, obj2, new ComparisonContext()); } public override IEnumerable CalculateDifferences(Type type, object obj1, object obj2, ComparisonContext comparisonContext) diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/HashSetsComparer~1.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/HashSetsComparer~1.cs index 98cc14d..e656871 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/HashSetsComparer~1.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/HashSetsComparer~1.cs @@ -19,7 +19,7 @@ public IEnumerable CalculateDifferences(T obj1, T obj2, ComparisonCo public override IEnumerable CalculateDifferences(Type type, object obj1, object obj2) { - return CalculateDifferences(type, obj1, obj2, ComparisonContext.CreateRoot()); + return CalculateDifferences(type, obj1, obj2, new ComparisonContext()); } public IEnumerable CalculateDifferences(Type type, object obj1, object obj2, ComparisonContext comparisonContext) diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/MultidimensionalArrayComparer~1.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/MultidimensionalArrayComparer~1.cs index 8a5d97b..cf73d4a 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/MultidimensionalArrayComparer~1.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/MultidimensionalArrayComparer~1.cs @@ -17,7 +17,7 @@ public MultidimensionalArrayComparer(ComparisonSettings settings, BaseComparer p public override IEnumerable CalculateDifferences(Type type, object obj1, object obj2) { - return CalculateDifferences(type, obj1, obj2, ComparisonContext.CreateRoot()); + return CalculateDifferences(type, obj1, obj2, new ComparisonContext()); } public IEnumerable CalculateDifferences(T obj1, T obj2, ComparisonContext comparisonContext) diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/MultidimensionalArraysComparer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/MultidimensionalArraysComparer.cs index 64426e5..30c6e5e 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/MultidimensionalArraysComparer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/MultidimensionalArraysComparer.cs @@ -15,7 +15,7 @@ public MultidimensionalArraysComparer(ComparisonSettings settings, BaseComparer public override IEnumerable CalculateDifferences(Type type, object obj1, object obj2) { - return CalculateDifferences(type, obj1, obj2, ComparisonContext.CreateRoot()); + return CalculateDifferences(type, obj1, obj2, new ComparisonContext()); } public override IEnumerable CalculateDifferences(Type type, object obj1, object obj2, ComparisonContext comparisonContext) diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/TypesComparer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/TypesComparer.cs index be7adf2..aafeb88 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/TypesComparer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/TypesComparer.cs @@ -15,7 +15,7 @@ public TypesComparer(ComparisonSettings settings, BaseComparer parentComparer, public override IEnumerable CalculateDifferences(Type type, object obj1, object obj2) { - return CalculateDifferences(type, obj1, obj2, ComparisonContext.CreateRoot()); + return CalculateDifferences(type, obj1, obj2, new ComparisonContext()); } public IEnumerable CalculateDifferences(Type type, object obj1, object obj2, ComparisonContext comparisonContext) From b6d8444b494a3ee7859d8c740b590c4a2d4ef7a5 Mon Sep 17 00:00:00 2001 From: Daniel Nemec Date: Sun, 19 Dec 2021 18:38:21 +0100 Subject: [PATCH 086/181] Add DifferenceExtensions. --- .../Comparer_ExpandoObjectsTests.cs | 39 ++++++++++++---- .../Comparer_GenericEnumerableTests.cs | 3 ++ .../ComparisonSettingsTests.cs | 21 ++++++--- .../Utils/DifferenceExtensions.cs | 44 +++++++++++++++++++ .../ObjectsComparer/ComparisonSettings.cs | 2 +- .../Context/ComparisonContext.cs | 4 +- .../Context/ComparisonContextMember.cs | 11 +++-- .../EnumerablesComparerBase.cs | 2 +- 8 files changed, 105 insertions(+), 21 deletions(-) create mode 100644 ObjectsComparer/ObjectsComparer.Tests/Utils/DifferenceExtensions.cs diff --git a/ObjectsComparer/ObjectsComparer.Tests/Comparer_ExpandoObjectsTests.cs b/ObjectsComparer/ObjectsComparer.Tests/Comparer_ExpandoObjectsTests.cs index d714f71..556996d 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/Comparer_ExpandoObjectsTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/Comparer_ExpandoObjectsTests.cs @@ -4,6 +4,8 @@ using System.Dynamic; using Newtonsoft.Json; using NSubstitute; +using System.Diagnostics.CodeAnalysis; +using ObjectsComparer.Tests.Utils; namespace ObjectsComparer.Tests { @@ -98,6 +100,34 @@ public void Hierarchy() Assert.IsTrue(differences.Any(d => d.MemberPath == "FieldSub1.Field1" && d.Value1 == "10" && d.Value2 == "8")); } + [Test] + public void Hierarchy_CheckComparisonContext() + { + dynamic a1Sub1 = new ExpandoObject(); + a1Sub1.Field1 = 10; + dynamic a1 = new ExpandoObject(); + a1.FieldSub1 = a1Sub1; + dynamic a2Sub1 = new ExpandoObject(); + a2Sub1.Field1 = 8; + dynamic a2 = new ExpandoObject(); + a2.FieldSub1 = a2Sub1; + var comparer = new Comparer(); + + var isEqual = comparer.Compare(a1, a2, out IEnumerable differencesEnum); + var differences = differencesEnum.ToList(); + + Assert.IsFalse(isEqual); + Assert.AreEqual(1, differences.Count); + Assert.IsTrue(differences.Any(d => d.MemberPath == "FieldSub1.Field1" && d.Value1 == "10" && d.Value2 == "8")); + + var ctx = new ComparisonContext(); + var calcDifferences = comparer.CalculateDifferences(typeof(object), (object)a1, (object)a2, ctx).ToArray(); + var ctxDifferences = ctx.GetDifferences(true).ToArray(); + + Assert.IsTrue(differences.AreEquivalent(calcDifferences)); + Assert.IsTrue(differences.AreEquivalent(ctxDifferences)); + } + [Test] public void DifferentTypes() { @@ -319,14 +349,7 @@ public void DifferenceWhenSubclassNotSpecified_CheckComparisonContext() var calculateDifferences = calculateDiffs.ToList(); var comparisonContextDifferences = rootComparisonContext.GetDifferences(recursive: true).ToList(); - Assert.IsTrue(comparisonContextDifferences.Any( - d => d.MemberPath == "Field1" && d.DifferenceType == DifferenceTypes.MissedMemberInSecondObject)); - - Assert.IsTrue(calculateDifferences.Any( - d => d.MemberPath == "Field1" && d.DifferenceType == DifferenceTypes.MissedMemberInSecondObject)); - - comparisonContextDifferences.ForEach(ctxDiff => CollectionAssert.Contains(calculateDifferences, ctxDiff)); - calculateDifferences.ForEach(calculateDiff => CollectionAssert.Contains(comparisonContextDifferences, calculateDiff)); + CollectionAssert.AreEquivalent(calculateDifferences, comparisonContextDifferences); } [Test] diff --git a/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs b/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs index 3538d0c..2aeb7a3 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs @@ -6,6 +6,7 @@ using ObjectsComparer.Exceptions; using System; using ObjectsComparer.Utils; +using ObjectsComparer.Tests.Utils; namespace ObjectsComparer.Tests { @@ -86,6 +87,8 @@ public void PrimitiveTypeArrayInequalityCount_CompareUnequalLists() Assert.AreEqual(2, diffsFromCtx.Count); Assert.AreEqual(differences[0], diffsFromCtx[0]); Assert.AreEqual(differences[1], diffsFromCtx[1]); + + var ctxjson = rootCtx.Shrink().ToJson(skipNullReference: false); } [Test] diff --git a/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs b/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs index 40fe715..c7cba19 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using NUnit.Framework; using ObjectsComparer.Tests.TestClasses; +using ObjectsComparer.Tests.Utils; namespace ObjectsComparer.Tests { @@ -106,10 +107,11 @@ public void FluentTest_CompareUnequalLists() var a2 = new int[] { 1, 2, 3, 4 }; var settings = new ComparisonSettings(); - settings.ConfigureListComparison(listOptions => listOptions.CompareUnequalLists(true)); + settings.ConfigureListComparison(compareUnequalLists: true); var comparer = new Comparer(settings); - var differences = comparer.CalculateDifferences(a1, a2).ToList(); + var ctx = new ComparisonContext(); + var differences = comparer.CalculateDifferences(a1.GetType(), a1, a2, ctx).ToList(); Assert.AreEqual(4, differences.Count); @@ -132,19 +134,24 @@ public void FluentTest_CompareUnequalLists() Assert.AreEqual("Length", differences[3].MemberPath); Assert.AreEqual("3", differences[3].Value1); Assert.AreEqual("4", differences[3].Value2); + + Assert.IsTrue(differences.AreEquivalent(ctx.GetDifferences(true))); + + var ctxJson = ctx.Shrink().ToJson(); } [Test] - public void FluentTest_CompareUnequalLists_CompareElementsByKey() + public void FluentTest_CompareUnequalLists_ByKey() { var a1 = new int[] { 3, 2, 1 }; var a2 = new int[] { 1, 2, 3, 4 }; var settings = new ComparisonSettings(); - settings.ConfigureListComparison(listOptions => listOptions.CompareUnequalLists(true).CompareElementsByKey()); + settings.ConfigureListComparison(compareUnequalLists: true, compareElementsByKey: true); var comparer = new Comparer(settings); - var differences = comparer.CalculateDifferences(a1, a2).ToList(); + var ctx = new ComparisonContext(); + var differences = comparer.CalculateDifferences(a1.GetType(), a1, a2, ctx).ToList(); Assert.AreEqual(2, differences.Count); @@ -157,10 +164,12 @@ public void FluentTest_CompareUnequalLists_CompareElementsByKey() Assert.AreEqual("Length", differences[1].MemberPath); Assert.AreEqual("3", differences[1].Value1); Assert.AreEqual("4", differences[1].Value2); + + Assert.IsTrue(differences.AreEquivalent(ctx.GetDifferences(true))); } [Test] - public void FluentTest_CompareUnequalLists_CompareElementsByKey_FormatKey() + public void FluentTest_CompareUnequalLists_ByKey_FormatKey() { var a1 = new int[] { 3, 2, 1 }; var a2 = new int[] { 1, 2, 3, 4 }; diff --git a/ObjectsComparer/ObjectsComparer.Tests/Utils/DifferenceExtensions.cs b/ObjectsComparer/ObjectsComparer.Tests/Utils/DifferenceExtensions.cs new file mode 100644 index 0000000..2be7ad2 --- /dev/null +++ b/ObjectsComparer/ObjectsComparer.Tests/Utils/DifferenceExtensions.cs @@ -0,0 +1,44 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace ObjectsComparer.Tests.Utils +{ + internal class DifferenceEqualityComparer : EqualityComparer + { + public override bool Equals(Difference b1, Difference b2) + { + if (b1 == null && b2 == null) + { + return true; + } + else if (b1 == null || b2 == null) + { + return false; + } + + return (b1.DifferenceType == b2.DifferenceType && b1.MemberPath == b2.MemberPath && b1.Value1 == b2.Value1 && b1.Value2 == b2.Value2); + } + + public override int GetHashCode(Difference obj) + { + var memberPath = obj.MemberPath ?? string.Empty; + var value1 = obj.Value1 ?? string.Empty; + var value2 = obj.Value2 ?? string.Empty; + var hcode = obj.DifferenceType.GetHashCode() ^ memberPath.GetHashCode() ^ value1.GetHashCode() ^ value2.GetHashCode(); + + return hcode.GetHashCode(); + } + } + + public static class DifferenceExtensions + { + public static bool AreEquivalent(this IEnumerable diffs1, IEnumerable diffs2) + { + return diffs1 + .Except(diffs2, new DifferenceEqualityComparer()) + .Any() == false; + } + } +} diff --git a/ObjectsComparer/ObjectsComparer/ComparisonSettings.cs b/ObjectsComparer/ObjectsComparer/ComparisonSettings.cs index 9248b98..e779a5f 100644 --- a/ObjectsComparer/ObjectsComparer/ComparisonSettings.cs +++ b/ObjectsComparer/ObjectsComparer/ComparisonSettings.cs @@ -70,7 +70,7 @@ public T GetCustomSetting(string key = null) internal Action ListComparisonOptionsAction { get; private set; } = null; /// - /// Configures list comparison behavior, especially the type of the comparison. For more info, see . + /// Configures list comparison behavior, especially the type of the comparison. For more info, see . /// /// First parameter: Current list comparison context. public ComparisonSettings ConfigureListComparison(Action comparisonOptions) diff --git a/ObjectsComparer/ObjectsComparer/Context/ComparisonContext.cs b/ObjectsComparer/ObjectsComparer/Context/ComparisonContext.cs index 4d5b159..566e2c7 100644 --- a/ObjectsComparer/ObjectsComparer/Context/ComparisonContext.cs +++ b/ObjectsComparer/ObjectsComparer/Context/ComparisonContext.cs @@ -128,7 +128,7 @@ public IEnumerable GetDifferences(bool recursive) /// /// Removes all which have no directly or indirectly in their . /// - public void Shrink() + public ComparisonContext Shrink() { lock (_shrinkLock) { @@ -146,6 +146,8 @@ public void Shrink() _descendants.RemoveAll(ctx => removeDescendants.Contains(ctx)); } + + return this; } } } \ No newline at end of file diff --git a/ObjectsComparer/ObjectsComparer/Context/ComparisonContextMember.cs b/ObjectsComparer/ObjectsComparer/Context/ComparisonContextMember.cs index 43cb7d9..5fe388f 100644 --- a/ObjectsComparer/ObjectsComparer/Context/ComparisonContextMember.cs +++ b/ObjectsComparer/ObjectsComparer/Context/ComparisonContextMember.cs @@ -1,9 +1,12 @@ -using System.Reflection; +using System; +using System.Reflection; namespace ObjectsComparer { internal class ComparisonContextMember : IComparisonContextMember { + readonly string _name; + public ComparisonContextMember() { } @@ -15,15 +18,15 @@ public ComparisonContextMember(string name) throw new System.ArgumentException($"'{nameof(name)}' cannot be null or whitespace.", nameof(name)); } - Name = name; + _name = name; } public ComparisonContextMember(MemberInfo info) { - Info = info ?? throw new System.ArgumentNullException(nameof(info)); + Info = info ?? throw new ArgumentNullException(nameof(info)); } - public string Name { get; } + public string Name => _name ?? Info?.Name; public MemberInfo Info { get; } } diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparerBase.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparerBase.cs index c981430..05a53db 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparerBase.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparerBase.cs @@ -194,7 +194,7 @@ protected virtual IEnumerable CalculateDifferencesByIndex(IList array1Count ? valueComparer.ToString(largerArray[i]) : string.Empty, differenceType: array1Count > array2Count ? DifferenceTypes.MissedElementInSecondObject : DifferenceTypes.MissedElementInFirstObject); - yield return AddDifferenceToComparisonContext(difference, new ComparisonContext(ancestor: listComparisonContext)); + yield return AddDifferenceToComparisonContext(difference, new ComparisonContext(new ComparisonContextMember(), listComparisonContext)); } } } From 9a720523c86604bd2aa35b08426b7715c10deea8 Mon Sep 17 00:00:00 2001 From: Daniel Nemec Date: Sat, 25 Dec 2021 09:55:06 +0100 Subject: [PATCH 087/181] Edit HasDiffernces. --- .../Context/ComparisonContext.cs | 29 +------------------ 1 file changed, 1 insertion(+), 28 deletions(-) diff --git a/ObjectsComparer/ObjectsComparer/Context/ComparisonContext.cs b/ObjectsComparer/ObjectsComparer/Context/ComparisonContext.cs index 566e2c7..6d0f01f 100644 --- a/ObjectsComparer/ObjectsComparer/Context/ComparisonContext.cs +++ b/ObjectsComparer/ObjectsComparer/Context/ComparisonContext.cs @@ -28,23 +28,6 @@ public ComparisonContext(IComparisonContextMember member = null, ComparisonConte } } - //public static ComparisonContext Create(IComparisonContextMember member = null, ComparisonContext ancestor = null) - //{ - // var context = new ComparisonContext(member); - - // if (ancestor != null) - // { - // ancestor.AddDescendant(context); - // } - - // return context; - //} - - private ComparisonContext(IComparisonContextMember currentMember) - { - Member = currentMember; - } - /// /// Typically a property or field in comparison process. /// It is always null for the root context (the starting point of the comparison) and always null for the list element. A list element never has a member, but it has an ancestor context which is the list and that list has its member. @@ -88,17 +71,7 @@ internal void AddDifference(Difference difference) /// If value is true, it also looks for in . public bool HasDifferences(bool recursive) { - if (_differences.Any()) - { - return true; - } - - if (recursive) - { - return _descendants.Any(d => d.HasDifferences(true)); - } - - return false; + return GetDifferences(recursive).Any(); } /// From 0e7cbc4a9eec157d8c2e184ce4b5a5e3b877611a Mon Sep 17 00:00:00 2001 From: Daniel Nemec Date: Sun, 2 Jan 2022 18:30:38 +0100 Subject: [PATCH 088/181] Init commit. --- .../Comparer_GenericEnumerableTests.cs | 2 +- .../ComparisonSettingsTests.cs | 19 ++++++++++++++--- .../ObjectsComparer/ComparisonSettings.cs | 4 ++-- .../Context/IComparisonContextInfo.cs | 9 ++++++++ .../Context/IListComparisonContextInfo.cs | 6 ++++++ .../Context/ListComparisonContextInfo.cs | 21 +++++++++++++++++++ .../CustomComparers/EnumerablesComparer.cs | 3 ++- .../CustomComparers/EnumerablesComparer~1.cs | 3 ++- 8 files changed, 59 insertions(+), 8 deletions(-) create mode 100644 ObjectsComparer/ObjectsComparer/Context/IComparisonContextInfo.cs create mode 100644 ObjectsComparer/ObjectsComparer/Context/IListComparisonContextInfo.cs create mode 100644 ObjectsComparer/ObjectsComparer/Context/ListComparisonContextInfo.cs diff --git a/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs b/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs index 2aeb7a3..cf78208 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs @@ -88,7 +88,7 @@ public void PrimitiveTypeArrayInequalityCount_CompareUnequalLists() Assert.AreEqual(differences[0], diffsFromCtx[0]); Assert.AreEqual(differences[1], diffsFromCtx[1]); - var ctxjson = rootCtx.Shrink().ToJson(skipNullReference: false); + var ctxjson = (rootCtx.Shrink() as ComparisonContext).ToJson(skipNullReference: false); } [Test] diff --git a/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs b/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs index c7cba19..748f675 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs @@ -65,7 +65,7 @@ public void CompareListElementsByKeyIsCorrectlySet() //Client side. var settings = new ComparisonSettings(); - settings.ConfigureListComparison((comparisonContext, listOptions) => + settings.ConfigureListComparison((curentContext, listOptions) => { listOptions.CompareUnequalLists(true); @@ -74,12 +74,15 @@ public void CompareListElementsByKeyIsCorrectlySet() keyOptions.UseKey("Key"); keyOptions.ThrowKeyNotFound(false); }); + + var currentMember = curentContext.Member; }); //Component side. var listComparisonOptions = ListComparisonOptions.Default(); var ctx = new ComparisonContext(); - settings.ListComparisonOptionsAction(ctx, listComparisonOptions); + var listComparisonContextInfo = new ListComparisonContextInfo(ctx); + settings.ListComparisonOptionsAction(listComparisonContextInfo, listComparisonOptions); var listElementComparisonByKeyOptions = ListElementComparisonByKeyOptions.Default(); listComparisonOptions.KeyOptionsAction(listElementComparisonByKeyOptions); @@ -137,7 +140,7 @@ public void FluentTest_CompareUnequalLists() Assert.IsTrue(differences.AreEquivalent(ctx.GetDifferences(true))); - var ctxJson = ctx.Shrink().ToJson(); + var ctxJson = (ctx.Shrink() as ComparisonContext).ToJson(); } [Test] @@ -313,6 +316,16 @@ public static void LambdaTest() // 3 is greater than 5: False // Another lambda observes a new value of captured variable: True + [Test] + public void TestListComparisonContextInfo() + { + var ancestorMember = new ComparisonContextMember("Property1"); + var ancestorCtx = new ComparisonContext(ancestorMember); + var member = new ComparisonContextMember("Property2"); + var ctx = new ComparisonContext(member, ancestorCtx); + var listCtxInfo = new ListComparisonContextInfo(ctx); + Assert.AreEqual("Property1.Property2", $"{listCtxInfo.Ancestor.Member.Name}.{listCtxInfo.Member.Name}"); + } } public class VariableCaptureGame diff --git a/ObjectsComparer/ObjectsComparer/ComparisonSettings.cs b/ObjectsComparer/ObjectsComparer/ComparisonSettings.cs index e779a5f..b3dbb0d 100644 --- a/ObjectsComparer/ObjectsComparer/ComparisonSettings.cs +++ b/ObjectsComparer/ObjectsComparer/ComparisonSettings.cs @@ -67,13 +67,13 @@ public T GetCustomSetting(string key = null) throw new KeyNotFoundException(); } - internal Action ListComparisonOptionsAction { get; private set; } = null; + internal Action ListComparisonOptionsAction { get; private set; } = null; /// /// Configures list comparison behavior, especially the type of the comparison. For more info, see . /// /// First parameter: Current list comparison context. - public ComparisonSettings ConfigureListComparison(Action comparisonOptions) + public ComparisonSettings ConfigureListComparison(Action comparisonOptions) { if (comparisonOptions is null) { diff --git a/ObjectsComparer/ObjectsComparer/Context/IComparisonContextInfo.cs b/ObjectsComparer/ObjectsComparer/Context/IComparisonContextInfo.cs new file mode 100644 index 0000000..4201ad4 --- /dev/null +++ b/ObjectsComparer/ObjectsComparer/Context/IComparisonContextInfo.cs @@ -0,0 +1,9 @@ +namespace ObjectsComparer +{ + public interface IComparisonContextInfo + { + IComparisonContextMember Member { get; } + + IComparisonContextInfo Ancestor { get; } + } +} \ No newline at end of file diff --git a/ObjectsComparer/ObjectsComparer/Context/IListComparisonContextInfo.cs b/ObjectsComparer/ObjectsComparer/Context/IListComparisonContextInfo.cs new file mode 100644 index 0000000..83c0132 --- /dev/null +++ b/ObjectsComparer/ObjectsComparer/Context/IListComparisonContextInfo.cs @@ -0,0 +1,6 @@ +namespace ObjectsComparer +{ + public interface IListComparisonContextInfo : IComparisonContextInfo + { + } +} \ No newline at end of file diff --git a/ObjectsComparer/ObjectsComparer/Context/ListComparisonContextInfo.cs b/ObjectsComparer/ObjectsComparer/Context/ListComparisonContextInfo.cs new file mode 100644 index 0000000..de61ab3 --- /dev/null +++ b/ObjectsComparer/ObjectsComparer/Context/ListComparisonContextInfo.cs @@ -0,0 +1,21 @@ +using System; + +namespace ObjectsComparer +{ + internal class ListComparisonContextInfo : IListComparisonContextInfo + { + readonly ComparisonContext _comparisonContext; + + readonly IListComparisonContextInfo _ancestor; + + public ListComparisonContextInfo(ComparisonContext comparisonContext) + { + _comparisonContext = comparisonContext ?? throw new ArgumentNullException(nameof(comparisonContext)); + _ancestor = _comparisonContext.Ancestor == null ? null : new ListComparisonContextInfo(_comparisonContext.Ancestor); + } + + public IComparisonContextMember Member => _comparisonContext.Member; + + public IComparisonContextInfo Ancestor => _ancestor; + } +} \ No newline at end of file diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs index 42bbbf0..d803bff 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs @@ -58,7 +58,8 @@ public IEnumerable CalculateDifferences(Type type, object obj1, obje var array2 = ((IEnumerable)obj2).Cast().ToArray(); var listComparisonOptions = ListComparisonOptions.Default(); - Settings.ListComparisonOptionsAction?.Invoke(listComparisonContext, listComparisonOptions); + var listComparisonContextInfo = new ListComparisonContextInfo(listComparisonContext); + Settings.ListComparisonOptionsAction?.Invoke(listComparisonContextInfo, listComparisonOptions); if (array1.Length != array2.Length) { diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer~1.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer~1.cs index cb415be..10d83b5 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer~1.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer~1.cs @@ -58,7 +58,8 @@ public IEnumerable CalculateDifferences(Type type, object obj1, obje var list2 = ((IEnumerable)obj2).ToList(); var listComparisonOptions = ListComparisonOptions.Default(); - Settings.ListComparisonOptionsAction?.Invoke(listComparisonContext, listComparisonOptions); + var listComparisonContextInfo = new ListComparisonContextInfo(listComparisonContext); + Settings.ListComparisonOptionsAction?.Invoke(listComparisonContextInfo, listComparisonOptions); if (list1.Count != list2.Count) { From cc6974960503733b115d9ad50b3e8cbf52e0751f Mon Sep 17 00:00:00 2001 From: Daniel Nemec Date: Sat, 8 Jan 2022 22:29:48 +0100 Subject: [PATCH 089/181] Add IComparisonContext, ComparisonContextBase. --- .../ObjectsComparer/BaseComparer.cs | 1 + .../Context/ComparisonContext.cs | 114 +----------------- .../Context/ComparisonContextBase.cs | 101 ++++++++++++++++ .../Context/IComparisonContext.cs | 65 ++++++++++ .../Context/IComparisonContextMember.cs | 8 +- .../Context/ListComparisonContextInfo.cs | 4 +- 6 files changed, 179 insertions(+), 114 deletions(-) create mode 100644 ObjectsComparer/ObjectsComparer/Context/ComparisonContextBase.cs create mode 100644 ObjectsComparer/ObjectsComparer/Context/IComparisonContext.cs diff --git a/ObjectsComparer/ObjectsComparer/BaseComparer.cs b/ObjectsComparer/ObjectsComparer/BaseComparer.cs index 0d220d5..496ddbe 100644 --- a/ObjectsComparer/ObjectsComparer/BaseComparer.cs +++ b/ObjectsComparer/ObjectsComparer/BaseComparer.cs @@ -201,6 +201,7 @@ protected virtual Difference AddDifferenceToComparisonContext(Difference differe } comparisonContext.AddDifference(difference); + return difference; } } diff --git a/ObjectsComparer/ObjectsComparer/Context/ComparisonContext.cs b/ObjectsComparer/ObjectsComparer/Context/ComparisonContext.cs index 6d0f01f..2333a95 100644 --- a/ObjectsComparer/ObjectsComparer/Context/ComparisonContext.cs +++ b/ObjectsComparer/ObjectsComparer/Context/ComparisonContext.cs @@ -7,120 +7,12 @@ namespace ObjectsComparer { /// - /// Information about the , which is typically a property or field, in comparison process. It has its ancestor and descendant objects in the same way as its has its ancestor and descendant members in an object graph. contains all possible member differences. - /// Once the comparison is completed, it is possible to traverse the object graph and see differences at particular members. + /// Default implementation of . /// - public sealed class ComparisonContext + public sealed class ComparisonContext : ComparisonContextBase { - object _shrinkLock = new object(); - - readonly List _descendants = new List(); - - readonly List _differences = new List(); - - public ComparisonContext(IComparisonContextMember member = null, ComparisonContext ancestor = null) - { - Member = member; - - if (ancestor != null) - { - ancestor.AddDescendant(this); - } - } - - /// - /// Typically a property or field in comparison process. - /// It is always null for the root context (the starting point of the comparison) and always null for the list element. A list element never has a member, but it has an ancestor context which is the list and that list has its member. - /// - public IComparisonContextMember Member { get; } - - /// - /// Ancestor context. - /// - public ComparisonContext Ancestor { get; private set; } - - /// - /// Children contexts. - /// - public ReadOnlyCollection Descendants => _descendants.AsReadOnly(); - - /// - /// A list of differences directly related to this context. - /// - public ReadOnlyCollection Differences => _differences.AsReadOnly(); - - void AddDescendant(ComparisonContext descendant) - { - _descendants.Add(descendant); - descendant.Ancestor = this; - } - - internal void AddDifference(Difference difference) - { - if (difference is null) - { - throw new ArgumentNullException(nameof(difference)); - } - - _differences.Add(difference); - } - - /// - /// Whether there are differences directly or indirectly related to this context. - /// - /// If value is true, it also looks for in . - public bool HasDifferences(bool recursive) - { - return GetDifferences(recursive).Any(); - } - - /// - /// Returns differences directly or indirectly related to this context. - /// - /// If value is true, it also looks for in . - public IEnumerable GetDifferences(bool recursive) - { - foreach (var difference in _differences) - { - yield return difference; - } - - if (recursive) - { - foreach (var descendant in _descendants) - { - var differences = descendant.GetDifferences(true); - foreach (var difference in differences) - { - yield return difference; - } - } - } - } - - /// - /// Removes all which have no directly or indirectly in their . - /// - public ComparisonContext Shrink() + public ComparisonContext(IComparisonContextMember member = null, IComparisonContext ancestor = null) : base(member, ancestor) { - lock (_shrinkLock) - { - List removeDescendants = new List(); - - _descendants.ForEach(descendantContext => - { - descendantContext.Shrink(); - - if (descendantContext.HasDifferences(true) == false) - { - removeDescendants.Add(descendantContext); - } - }); - - _descendants.RemoveAll(ctx => removeDescendants.Contains(ctx)); - } - - return this; } } } \ No newline at end of file diff --git a/ObjectsComparer/ObjectsComparer/Context/ComparisonContextBase.cs b/ObjectsComparer/ObjectsComparer/Context/ComparisonContextBase.cs new file mode 100644 index 0000000..d388e5d --- /dev/null +++ b/ObjectsComparer/ObjectsComparer/Context/ComparisonContextBase.cs @@ -0,0 +1,101 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace ObjectsComparer +{ + /// + /// Base class for implementors. + /// + public abstract class ComparisonContextBase : IComparisonContext + { + object _shrinkLock = new object(); + + readonly List _descendants = new List(); + + readonly List _differences = new List(); + + public ComparisonContextBase(IComparisonContextMember member = null, IComparisonContext ancestor = null) + { + Ancestor = ancestor; + ancestor?.AddDescendant(this); + Member = member; + } + + public IComparisonContext Ancestor { get; set; } + + public IEnumerable Descendants => _descendants.AsReadOnly(); + + public IEnumerable Differences => _differences.AsReadOnly(); + + public IComparisonContextMember Member { get; } + + public void AddDescendant(IComparisonContext descendant) + { + if (descendant is null) + { + throw new ArgumentNullException(nameof(descendant)); + } + + _descendants.Add(descendant); + descendant.Ancestor = this; + } + + public void AddDifference(Difference difference) + { + if (difference is null) + { + throw new ArgumentNullException(nameof(difference)); + } + + _differences.Add(difference); + } + + public IEnumerable GetDifferences(bool recursive) + { + foreach (var difference in _differences) + { + yield return difference; + } + + if (recursive) + { + foreach (var descendant in _descendants) + { + var differences = descendant.GetDifferences(true); + foreach (var difference in differences) + { + yield return difference; + } + } + } + } + + public bool HasDifferences(bool recursive) + { + return GetDifferences(recursive).Any(); + } + + public IComparisonContext Shrink() + { + lock (_shrinkLock) + { + List removeDescendants = new List(); + + _descendants.ForEach(descendantContext => + { + descendantContext.Shrink(); + + if (descendantContext.HasDifferences(true) == false) + { + removeDescendants.Add(descendantContext); + } + }); + + _descendants.RemoveAll(ctx => removeDescendants.Contains(ctx)); + } + + return this; + } + } +} diff --git a/ObjectsComparer/ObjectsComparer/Context/IComparisonContext.cs b/ObjectsComparer/ObjectsComparer/Context/IComparisonContext.cs new file mode 100644 index 0000000..16a914d --- /dev/null +++ b/ObjectsComparer/ObjectsComparer/Context/IComparisonContext.cs @@ -0,0 +1,65 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using System.Text; + +namespace ObjectsComparer +{ + /// + /// Context of comparison process. Each instance wraps compared , which is typically property. Each context has its ancestor and descendants the same way as its compared has its ancestor and descendant members. + /// Once the comparison process is completed, it is possible to traverse the comparison context graph and see differences at particular members. + /// + public interface IComparisonContext + { + /// + /// Ancestor context. + /// + IComparisonContext Ancestor { get; set; } + + /// + /// Children contexts. + /// + IEnumerable Descendants { get; } + + /// + /// A list of differences directly related to the context. + /// + IEnumerable Differences { get; } + + /// + /// Compared member, for more info see . + /// It should be null for the root context (the starting point of the comparison) and for the list element context. A list element context never has a member, but it has an ancestor context which is the list and that list has its member. + /// + IComparisonContextMember Member { get; } + + /// + /// Adds descendant to the context. + /// + /// + void AddDescendant(IComparisonContext comparisonContext); + + /// + /// Adds the difference to the context. + /// + /// + void AddDifference(Difference difference); + + /// + /// Returns differences directly or indirectly related to the context. + /// + /// If value is true, it also looks for in . + IEnumerable GetDifferences(bool recursive = true); + + /// + /// Whether there are differences directly or indirectly related to the context. + /// + /// If value is true, it also looks for in . + bool HasDifferences(bool recursive); + + /// + /// Removes all which have no directly or indirectly in their . + /// + IComparisonContext Shrink(); + } +} diff --git a/ObjectsComparer/ObjectsComparer/Context/IComparisonContextMember.cs b/ObjectsComparer/ObjectsComparer/Context/IComparisonContextMember.cs index fbeebfe..683948f 100644 --- a/ObjectsComparer/ObjectsComparer/Context/IComparisonContextMember.cs +++ b/ObjectsComparer/ObjectsComparer/Context/IComparisonContextMember.cs @@ -2,12 +2,18 @@ namespace ObjectsComparer { + /// + /// Compared member in comparison process, typically the property. + /// public interface IComparisonContextMember { + /// + /// Compared member name. + /// string Name { get; } /// - /// Optional. + /// Compared member. May be null for dynamic properties unknown at compile time. /// MemberInfo Info { get; } } diff --git a/ObjectsComparer/ObjectsComparer/Context/ListComparisonContextInfo.cs b/ObjectsComparer/ObjectsComparer/Context/ListComparisonContextInfo.cs index de61ab3..a50ce83 100644 --- a/ObjectsComparer/ObjectsComparer/Context/ListComparisonContextInfo.cs +++ b/ObjectsComparer/ObjectsComparer/Context/ListComparisonContextInfo.cs @@ -4,11 +4,11 @@ namespace ObjectsComparer { internal class ListComparisonContextInfo : IListComparisonContextInfo { - readonly ComparisonContext _comparisonContext; + readonly IComparisonContext _comparisonContext; readonly IListComparisonContextInfo _ancestor; - public ListComparisonContextInfo(ComparisonContext comparisonContext) + public ListComparisonContextInfo(IComparisonContext comparisonContext) { _comparisonContext = comparisonContext ?? throw new ArgumentNullException(nameof(comparisonContext)); _ancestor = _comparisonContext.Ancestor == null ? null : new ListComparisonContextInfo(_comparisonContext.Ancestor); From 1b584151582563719d0d7953382ce192fcd2a447 Mon Sep 17 00:00:00 2001 From: Daniel Nemec Date: Sun, 9 Jan 2022 18:13:30 +0100 Subject: [PATCH 090/181] Override DummyComparisonContext.AddDifference. --- .../Context/ComparisonContextBase.cs | 2 +- .../Context/DummyComparisonContext.cs | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 ObjectsComparer/ObjectsComparer/Context/DummyComparisonContext.cs diff --git a/ObjectsComparer/ObjectsComparer/Context/ComparisonContextBase.cs b/ObjectsComparer/ObjectsComparer/Context/ComparisonContextBase.cs index d388e5d..2c8e583 100644 --- a/ObjectsComparer/ObjectsComparer/Context/ComparisonContextBase.cs +++ b/ObjectsComparer/ObjectsComparer/Context/ComparisonContextBase.cs @@ -41,7 +41,7 @@ public void AddDescendant(IComparisonContext descendant) descendant.Ancestor = this; } - public void AddDifference(Difference difference) + public virtual void AddDifference(Difference difference) { if (difference is null) { diff --git a/ObjectsComparer/ObjectsComparer/Context/DummyComparisonContext.cs b/ObjectsComparer/ObjectsComparer/Context/DummyComparisonContext.cs new file mode 100644 index 0000000..b620bc0 --- /dev/null +++ b/ObjectsComparer/ObjectsComparer/Context/DummyComparisonContext.cs @@ -0,0 +1,18 @@ +using System.Collections.Generic; +using System.Linq; + +namespace ObjectsComparer +{ + internal class DummyComparisonContext : ComparisonContextBase + { + public DummyComparisonContext(IComparisonContextMember member = null, IComparisonContext ancestor = null) : base(member, ancestor) + { + } + + public override void AddDifference(Difference difference) + { + } + + + } +} From 93893678c7d7cb7b162da4eb85a261ad45f32b6b Mon Sep 17 00:00:00 2001 From: "ASD\\nemec" Date: Mon, 10 Jan 2022 10:39:42 +0100 Subject: [PATCH 091/181] Add IComparisonContextFactory. --- ObjectsComparer/ObjectsComparer/Comparer.cs | 2 +- .../ComparisonContextOptions.cs | 46 +++++++++++++++++++ .../ObjectsComparer/ComparisonSettings.cs | 20 ++++++-- .../DefaultComparisonContextFactory.cs | 27 +++++++++++ .../Context/IComparisonContextFactory.cs | 17 +++++++ ...sonContext.cs => NullComparisonContext.cs} | 6 +-- .../Context/NullComparisonContextFactory.cs | 17 +++++++ 7 files changed, 126 insertions(+), 9 deletions(-) create mode 100644 ObjectsComparer/ObjectsComparer/ComparisonContextOptions.cs create mode 100644 ObjectsComparer/ObjectsComparer/Context/DefaultComparisonContextFactory.cs create mode 100644 ObjectsComparer/ObjectsComparer/Context/IComparisonContextFactory.cs rename ObjectsComparer/ObjectsComparer/Context/{DummyComparisonContext.cs => NullComparisonContext.cs} (50%) create mode 100644 ObjectsComparer/ObjectsComparer/Context/NullComparisonContextFactory.cs diff --git a/ObjectsComparer/ObjectsComparer/Comparer.cs b/ObjectsComparer/ObjectsComparer/Comparer.cs index 45d0b3e..bee44dd 100644 --- a/ObjectsComparer/ObjectsComparer/Comparer.cs +++ b/ObjectsComparer/ObjectsComparer/Comparer.cs @@ -29,7 +29,7 @@ public Comparer(ComparisonSettings settings = null, BaseComparer parentComparer public override IEnumerable CalculateDifferences(Type type, object obj1, object obj2) { - return CalculateDifferences(type, obj1, obj2, new ComparisonContext()); + return CalculateDifferences(type, obj1, obj2, new NullComparisonContext(member: null, ancestor: null)); } public IEnumerable CalculateDifferences(Type type, object obj1, object obj2, ComparisonContext comparisonContext) diff --git a/ObjectsComparer/ObjectsComparer/ComparisonContextOptions.cs b/ObjectsComparer/ObjectsComparer/ComparisonContextOptions.cs new file mode 100644 index 0000000..d2629f5 --- /dev/null +++ b/ObjectsComparer/ObjectsComparer/ComparisonContextOptions.cs @@ -0,0 +1,46 @@ +using System; + +namespace ObjectsComparer +{ + public class ComparisonContextOptions + { + bool _comparisonContextDisabled = false; + + IComparisonContextFactory _customComparisonContextFactory; + + IComparisonContextFactory _defaultComparisonContextFactory = new DefaultComparisonContextFactory(); + + IComparisonContextFactory _nullComparisonContextFactory = new NullComparisonContextFactory(); + + public void UseComparisonContextFactory(IComparisonContextFactory comparisonContextFactory) + { + _customComparisonContextFactory = comparisonContextFactory ?? throw new ArgumentNullException(nameof(comparisonContextFactory)); + } + + internal void DisableComparisonContext() + { + _comparisonContextDisabled = true; + } + + internal IComparisonContextFactory GetComparisonContextFactory(IComparisonContext ancestor = null) + { + do + { + if (ancestor is NullComparisonContext) + { + return _nullComparisonContextFactory; + } + + ancestor = ancestor.Ancestor; + + } while (ancestor != null); + + if (_customComparisonContextFactory != null) + { + return _customComparisonContextFactory; + } + + return _defaultComparisonContextFactory; + } + } +} diff --git a/ObjectsComparer/ObjectsComparer/ComparisonSettings.cs b/ObjectsComparer/ObjectsComparer/ComparisonSettings.cs index b3dbb0d..9924ffa 100644 --- a/ObjectsComparer/ObjectsComparer/ComparisonSettings.cs +++ b/ObjectsComparer/ObjectsComparer/ComparisonSettings.cs @@ -6,7 +6,7 @@ namespace ObjectsComparer /// /// Configuration for Objects Comparer. /// - public class ComparisonSettings + public partial class ComparisonSettings { /// /// If true, all members which are not primitive types, do not have custom comparison rule and @@ -86,16 +86,16 @@ public ComparisonSettings ConfigureListComparison(Action - /// Configures list comparison behavior, especially the type of comparison. For more info, see . + /// Configures list comparison behavior, especially the type of comparison. For more info, see . /// - /// See . + /// See . public void ConfigureListComparison(Action comparisonOptions) { ConfigureListComparison((_, options) => comparisonOptions(options)); } /// - /// Configures the type of list comparison and whether to compare unequal lists. For more info, see . + /// Configures the type of list comparison and whether to compare unequal lists. For more info, see . /// /// /// True value is shortcut for operation. @@ -116,5 +116,17 @@ public void ConfigureListComparison(bool compareElementsByKey = false, bool comp } }); } + + internal Action ComparisonContextOptionsAction; + + public void ConfigureComparisonContext(Action comparisonContextOptions) + { + if (comparisonContextOptions is null) + { + throw new ArgumentNullException(nameof(comparisonContextOptions)); + } + + ComparisonContextOptionsAction = comparisonContextOptions; + } } } diff --git a/ObjectsComparer/ObjectsComparer/Context/DefaultComparisonContextFactory.cs b/ObjectsComparer/ObjectsComparer/Context/DefaultComparisonContextFactory.cs new file mode 100644 index 0000000..91671cc --- /dev/null +++ b/ObjectsComparer/ObjectsComparer/Context/DefaultComparisonContextFactory.cs @@ -0,0 +1,27 @@ +using System.Reflection; + +namespace ObjectsComparer +{ + internal class DefaultComparisonContextFactory : IComparisonContextFactory + { + public IComparisonContext CreateContext(IComparisonContext ancestor = null, MemberInfo member = null, string memberName = null) + { + return new ComparisonContext(CreateMember(memberName, member), ancestor); + } + + internal static IComparisonContextMember CreateMember(string memberName, MemberInfo member) + { + if (member != null) + { + return new ComparisonContextMember(member); + } + + if (string.IsNullOrWhiteSpace(memberName)) + { + return new ComparisonContextMember(); + } + + return new ComparisonContextMember(memberName); + } + } +} diff --git a/ObjectsComparer/ObjectsComparer/Context/IComparisonContextFactory.cs b/ObjectsComparer/ObjectsComparer/Context/IComparisonContextFactory.cs new file mode 100644 index 0000000..f1e7725 --- /dev/null +++ b/ObjectsComparer/ObjectsComparer/Context/IComparisonContextFactory.cs @@ -0,0 +1,17 @@ +using System.Reflection; + +namespace ObjectsComparer +{ + public interface IComparisonContextFactory + { + IComparisonContext CreateContext(IComparisonContext ancestor = null, MemberInfo member = null, string memberName = null); + } + + public class CreateComparisonContextArgs + { + internal CreateComparisonContextArgs(IComparisonContext ancestor, string memberName, MemberInfo member) + { + + } + } +} diff --git a/ObjectsComparer/ObjectsComparer/Context/DummyComparisonContext.cs b/ObjectsComparer/ObjectsComparer/Context/NullComparisonContext.cs similarity index 50% rename from ObjectsComparer/ObjectsComparer/Context/DummyComparisonContext.cs rename to ObjectsComparer/ObjectsComparer/Context/NullComparisonContext.cs index b620bc0..d7643fb 100644 --- a/ObjectsComparer/ObjectsComparer/Context/DummyComparisonContext.cs +++ b/ObjectsComparer/ObjectsComparer/Context/NullComparisonContext.cs @@ -3,16 +3,14 @@ namespace ObjectsComparer { - internal class DummyComparisonContext : ComparisonContextBase + internal class NullComparisonContext : ComparisonContextBase { - public DummyComparisonContext(IComparisonContextMember member = null, IComparisonContext ancestor = null) : base(member, ancestor) + public NullComparisonContext(IComparisonContextMember member = null, IComparisonContext ancestor = null) : base(member, ancestor) { } public override void AddDifference(Difference difference) { } - - } } diff --git a/ObjectsComparer/ObjectsComparer/Context/NullComparisonContextFactory.cs b/ObjectsComparer/ObjectsComparer/Context/NullComparisonContextFactory.cs new file mode 100644 index 0000000..a69722c --- /dev/null +++ b/ObjectsComparer/ObjectsComparer/Context/NullComparisonContextFactory.cs @@ -0,0 +1,17 @@ +using System.Reflection; + +namespace ObjectsComparer +{ + internal class NullComparisonContextFactory : IComparisonContextFactory + { + public IComparisonContext CreateContext(IComparisonContext ancestor = null, string memberName = null) + { + return new NullComparisonContext(DefaultComparisonContextFactory.CreateMember(memberName, null), ancestor); + } + + public IComparisonContext CreateContext(IComparisonContext ancestor = null, MemberInfo member = null) + { + return new NullComparisonContext(DefaultComparisonContextFactory.CreateMember(null, member), ancestor); + } + } +} From 8a2735fb2866aa0015cba6c57e7e0c53f76646a3 Mon Sep 17 00:00:00 2001 From: "ASD\\nemec" Date: Mon, 10 Jan 2022 10:44:28 +0100 Subject: [PATCH 092/181] Edit IComparisonContextFactory. --- .../Context/DefaultComparisonContextFactory.cs | 9 +++++++-- .../ObjectsComparer/Context/IComparisonContextFactory.cs | 4 +++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/ObjectsComparer/ObjectsComparer/Context/DefaultComparisonContextFactory.cs b/ObjectsComparer/ObjectsComparer/Context/DefaultComparisonContextFactory.cs index 91671cc..7febcd1 100644 --- a/ObjectsComparer/ObjectsComparer/Context/DefaultComparisonContextFactory.cs +++ b/ObjectsComparer/ObjectsComparer/Context/DefaultComparisonContextFactory.cs @@ -4,9 +4,14 @@ namespace ObjectsComparer { internal class DefaultComparisonContextFactory : IComparisonContextFactory { - public IComparisonContext CreateContext(IComparisonContext ancestor = null, MemberInfo member = null, string memberName = null) + public IComparisonContext CreateContext(IComparisonContext ancestor = null, string memberName = null) { - return new ComparisonContext(CreateMember(memberName, member), ancestor); + return new ComparisonContext(CreateMember(memberName, null), ancestor); + } + + public IComparisonContext CreateContext(IComparisonContext ancestor = null, MemberInfo member = null) + { + return new ComparisonContext(CreateMember(null, member), ancestor); } internal static IComparisonContextMember CreateMember(string memberName, MemberInfo member) diff --git a/ObjectsComparer/ObjectsComparer/Context/IComparisonContextFactory.cs b/ObjectsComparer/ObjectsComparer/Context/IComparisonContextFactory.cs index f1e7725..dabff04 100644 --- a/ObjectsComparer/ObjectsComparer/Context/IComparisonContextFactory.cs +++ b/ObjectsComparer/ObjectsComparer/Context/IComparisonContextFactory.cs @@ -4,7 +4,9 @@ namespace ObjectsComparer { public interface IComparisonContextFactory { - IComparisonContext CreateContext(IComparisonContext ancestor = null, MemberInfo member = null, string memberName = null); + IComparisonContext CreateContext(IComparisonContext ancestor = null, string memberName = null); + + IComparisonContext CreateContext(IComparisonContext ancestor = null, MemberInfo member = null); } public class CreateComparisonContextArgs From 48ba0ab0715b8e9cfd04df7ec3951c5dbe71e79e Mon Sep 17 00:00:00 2001 From: nemec Date: Fri, 14 Jan 2022 14:52:29 +0100 Subject: [PATCH 093/181] Add ComparisonContextOptions, ComparisonContextProvider. --- ObjectsComparer/ObjectsComparer/Comparer.cs | 2 +- .../ComparisonContextOptions.cs | 46 ----------- .../ObjectsComparer/ComparisonSettings.cs | 2 +- .../Context/ComparisonContextOptions.cs | 24 ++++++ .../Context/ComparisonContextProvider.cs | 79 +++++++++++++++++++ .../DefaultComparisonContextFactory.cs | 54 ++++++------- .../Context/IComparisonContextFactory.cs | 19 ++--- .../Context/ListComparisonContextInfo.cs | 18 ++++- .../Context/NullComparisonContext.cs | 3 + .../Context/NullComparisonContextFactory.cs | 30 +++---- 10 files changed, 176 insertions(+), 101 deletions(-) delete mode 100644 ObjectsComparer/ObjectsComparer/ComparisonContextOptions.cs create mode 100644 ObjectsComparer/ObjectsComparer/Context/ComparisonContextOptions.cs create mode 100644 ObjectsComparer/ObjectsComparer/Context/ComparisonContextProvider.cs diff --git a/ObjectsComparer/ObjectsComparer/Comparer.cs b/ObjectsComparer/ObjectsComparer/Comparer.cs index bee44dd..cb6c85b 100644 --- a/ObjectsComparer/ObjectsComparer/Comparer.cs +++ b/ObjectsComparer/ObjectsComparer/Comparer.cs @@ -29,7 +29,7 @@ public Comparer(ComparisonSettings settings = null, BaseComparer parentComparer public override IEnumerable CalculateDifferences(Type type, object obj1, object obj2) { - return CalculateDifferences(type, obj1, obj2, new NullComparisonContext(member: null, ancestor: null)); + return CalculateDifferences(type, obj1, obj2, ComparisonContextProvider.CreateNullContext()); } public IEnumerable CalculateDifferences(Type type, object obj1, object obj2, ComparisonContext comparisonContext) diff --git a/ObjectsComparer/ObjectsComparer/ComparisonContextOptions.cs b/ObjectsComparer/ObjectsComparer/ComparisonContextOptions.cs deleted file mode 100644 index d2629f5..0000000 --- a/ObjectsComparer/ObjectsComparer/ComparisonContextOptions.cs +++ /dev/null @@ -1,46 +0,0 @@ -using System; - -namespace ObjectsComparer -{ - public class ComparisonContextOptions - { - bool _comparisonContextDisabled = false; - - IComparisonContextFactory _customComparisonContextFactory; - - IComparisonContextFactory _defaultComparisonContextFactory = new DefaultComparisonContextFactory(); - - IComparisonContextFactory _nullComparisonContextFactory = new NullComparisonContextFactory(); - - public void UseComparisonContextFactory(IComparisonContextFactory comparisonContextFactory) - { - _customComparisonContextFactory = comparisonContextFactory ?? throw new ArgumentNullException(nameof(comparisonContextFactory)); - } - - internal void DisableComparisonContext() - { - _comparisonContextDisabled = true; - } - - internal IComparisonContextFactory GetComparisonContextFactory(IComparisonContext ancestor = null) - { - do - { - if (ancestor is NullComparisonContext) - { - return _nullComparisonContextFactory; - } - - ancestor = ancestor.Ancestor; - - } while (ancestor != null); - - if (_customComparisonContextFactory != null) - { - return _customComparisonContextFactory; - } - - return _defaultComparisonContextFactory; - } - } -} diff --git a/ObjectsComparer/ObjectsComparer/ComparisonSettings.cs b/ObjectsComparer/ObjectsComparer/ComparisonSettings.cs index 9924ffa..ad0dc6b 100644 --- a/ObjectsComparer/ObjectsComparer/ComparisonSettings.cs +++ b/ObjectsComparer/ObjectsComparer/ComparisonSettings.cs @@ -117,7 +117,7 @@ public void ConfigureListComparison(bool compareElementsByKey = false, bool comp }); } - internal Action ComparisonContextOptionsAction; + internal Action ComparisonContextOptionsAction { get; private set; } public void ConfigureComparisonContext(Action comparisonContextOptions) { diff --git a/ObjectsComparer/ObjectsComparer/Context/ComparisonContextOptions.cs b/ObjectsComparer/ObjectsComparer/Context/ComparisonContextOptions.cs new file mode 100644 index 0000000..5ad7f97 --- /dev/null +++ b/ObjectsComparer/ObjectsComparer/Context/ComparisonContextOptions.cs @@ -0,0 +1,24 @@ +using System; +using System.Reflection; + +namespace ObjectsComparer +{ + public class ComparisonContextOptions + { + ComparisonContextOptions() + { + } + + internal static ComparisonContextOptions Default() + { + return new ComparisonContextOptions(); + } + + internal IComparisonContextFactory CustomComparisonContextFactory { get; private set; } + + public void UseComparisonContextFactory(IComparisonContextFactory comparisonContextFactory) + { + CustomComparisonContextFactory = comparisonContextFactory ?? throw new ArgumentNullException(nameof(comparisonContextFactory)); + } + } +} diff --git a/ObjectsComparer/ObjectsComparer/Context/ComparisonContextProvider.cs b/ObjectsComparer/ObjectsComparer/Context/ComparisonContextProvider.cs new file mode 100644 index 0000000..b5e21a7 --- /dev/null +++ b/ObjectsComparer/ObjectsComparer/Context/ComparisonContextProvider.cs @@ -0,0 +1,79 @@ +using System; +using System.Reflection; + +namespace ObjectsComparer +{ + internal static class ComparisonContextProvider + { + public static IComparisonContext CreateNullContext() + { + return new NullComparisonContext(); + } + + /// + /// takes precedence over . + /// + public static IComparisonContext CreateContext(ComparisonContextOptions options, IComparisonContext ancestor, MemberInfo member, string memberName) + { + if (options is null) + { + throw new ArgumentNullException(nameof(options)); + } + + if (ShouldCreateNullContext(ancestor)) + { + return new NullComparisonContext(null, null); + } + + var ancestorInfo = ancestor != null ? new ComparisonContextInfo(ancestor) : null; + + if (options.CustomComparisonContextFactory != null) + { + if (member != null) + { + return options.CustomComparisonContextFactory.CreateContext(member, ancestorInfo); + } + + if (string.IsNullOrWhiteSpace(memberName)) + { + return options.CustomComparisonContextFactory.CreateContext(memberName, ancestorInfo); + } + + return options.CustomComparisonContextFactory.CreateContext(ancestorInfo); + } + + return new ComparisonContext(CreateComparisonContextMember(memberName, member), ancestor); + } + + static bool ShouldCreateNullContext(IComparisonContext ancestor) + { + do + { + if (ancestor is NullComparisonContext) + { + return true; + } + + ancestor = ancestor.Ancestor; + + } while (ancestor != null); + + return false; + } + + static IComparisonContextMember CreateComparisonContextMember(string memberName, MemberInfo member) + { + if (member != null) + { + return new ComparisonContextMember(member); + } + + if (string.IsNullOrWhiteSpace(memberName)) + { + return new ComparisonContextMember(); + } + + return new ComparisonContextMember(memberName); + } + } +} diff --git a/ObjectsComparer/ObjectsComparer/Context/DefaultComparisonContextFactory.cs b/ObjectsComparer/ObjectsComparer/Context/DefaultComparisonContextFactory.cs index 7febcd1..a5c4ee0 100644 --- a/ObjectsComparer/ObjectsComparer/Context/DefaultComparisonContextFactory.cs +++ b/ObjectsComparer/ObjectsComparer/Context/DefaultComparisonContextFactory.cs @@ -1,32 +1,32 @@ -using System.Reflection; +//using System.Reflection; -namespace ObjectsComparer -{ - internal class DefaultComparisonContextFactory : IComparisonContextFactory - { - public IComparisonContext CreateContext(IComparisonContext ancestor = null, string memberName = null) - { - return new ComparisonContext(CreateMember(memberName, null), ancestor); - } +//namespace ObjectsComparer +//{ +// internal class DefaultComparisonContextFactory : IComparisonContextFactory +// { +// public IComparisonContext CreateContext(IComparisonContext ancestor = null, string memberName = null) +// { +// return new ComparisonContext(CreateMember(memberName, null), ancestor); +// } - public IComparisonContext CreateContext(IComparisonContext ancestor = null, MemberInfo member = null) - { - return new ComparisonContext(CreateMember(null, member), ancestor); - } +// public IComparisonContext CreateContext(IComparisonContext ancestor = null, MemberInfo member = null) +// { +// return new ComparisonContext(CreateMember(null, member), ancestor); +// } - internal static IComparisonContextMember CreateMember(string memberName, MemberInfo member) - { - if (member != null) - { - return new ComparisonContextMember(member); - } +// internal static IComparisonContextMember CreateMember(string memberName, MemberInfo member) +// { +// if (member != null) +// { +// return new ComparisonContextMember(member); +// } - if (string.IsNullOrWhiteSpace(memberName)) - { - return new ComparisonContextMember(); - } +// if (string.IsNullOrWhiteSpace(memberName)) +// { +// return new ComparisonContextMember(); +// } - return new ComparisonContextMember(memberName); - } - } -} +// return new ComparisonContextMember(memberName); +// } +// } +//} diff --git a/ObjectsComparer/ObjectsComparer/Context/IComparisonContextFactory.cs b/ObjectsComparer/ObjectsComparer/Context/IComparisonContextFactory.cs index dabff04..ef64c4c 100644 --- a/ObjectsComparer/ObjectsComparer/Context/IComparisonContextFactory.cs +++ b/ObjectsComparer/ObjectsComparer/Context/IComparisonContextFactory.cs @@ -2,18 +2,19 @@ namespace ObjectsComparer { - public interface IComparisonContextFactory - { - IComparisonContext CreateContext(IComparisonContext ancestor = null, string memberName = null); + //public interface IComparisonContextFactory + //{ + // IComparisonContext CreateContext(IComparisonContext ancestor = null, string memberName = null); - IComparisonContext CreateContext(IComparisonContext ancestor = null, MemberInfo member = null); - } + // IComparisonContext CreateContext(IComparisonContext ancestor = null, MemberInfo member = null); + //} - public class CreateComparisonContextArgs + public interface IComparisonContextFactory { - internal CreateComparisonContextArgs(IComparisonContext ancestor, string memberName, MemberInfo member) - { + IComparisonContext CreateContext(IComparisonContextInfo ancestor = null); + + IComparisonContext CreateContext(string memberName, IComparisonContextInfo ancestor = null); - } + IComparisonContext CreateContext(MemberInfo member, IComparisonContextInfo ancestor = null); } } diff --git a/ObjectsComparer/ObjectsComparer/Context/ListComparisonContextInfo.cs b/ObjectsComparer/ObjectsComparer/Context/ListComparisonContextInfo.cs index a50ce83..a7a064a 100644 --- a/ObjectsComparer/ObjectsComparer/Context/ListComparisonContextInfo.cs +++ b/ObjectsComparer/ObjectsComparer/Context/ListComparisonContextInfo.cs @@ -2,13 +2,27 @@ namespace ObjectsComparer { - internal class ListComparisonContextInfo : IListComparisonContextInfo + internal class ListComparisonContextInfo : ComparisonContextInfoBase, IListComparisonContextInfo + { + public ListComparisonContextInfo(IComparisonContext comparisonContext) : base(comparisonContext) + { + } + } + + internal class ComparisonContextInfo : ComparisonContextInfoBase + { + public ComparisonContextInfo(IComparisonContext comparisonContext) : base(comparisonContext) + { + } + } + + internal class ComparisonContextInfoBase : IComparisonContextInfo { readonly IComparisonContext _comparisonContext; readonly IListComparisonContextInfo _ancestor; - public ListComparisonContextInfo(IComparisonContext comparisonContext) + public ComparisonContextInfoBase(IComparisonContext comparisonContext) { _comparisonContext = comparisonContext ?? throw new ArgumentNullException(nameof(comparisonContext)); _ancestor = _comparisonContext.Ancestor == null ? null : new ListComparisonContextInfo(_comparisonContext.Ancestor); diff --git a/ObjectsComparer/ObjectsComparer/Context/NullComparisonContext.cs b/ObjectsComparer/ObjectsComparer/Context/NullComparisonContext.cs index d7643fb..7afbaad 100644 --- a/ObjectsComparer/ObjectsComparer/Context/NullComparisonContext.cs +++ b/ObjectsComparer/ObjectsComparer/Context/NullComparisonContext.cs @@ -3,6 +3,9 @@ namespace ObjectsComparer { + /// + /// Null context for cases where the consumer does not create his own root context at the beginning of the comparison. No descendants or differences will be builded in the comparison process. + /// internal class NullComparisonContext : ComparisonContextBase { public NullComparisonContext(IComparisonContextMember member = null, IComparisonContext ancestor = null) : base(member, ancestor) diff --git a/ObjectsComparer/ObjectsComparer/Context/NullComparisonContextFactory.cs b/ObjectsComparer/ObjectsComparer/Context/NullComparisonContextFactory.cs index a69722c..d63b5be 100644 --- a/ObjectsComparer/ObjectsComparer/Context/NullComparisonContextFactory.cs +++ b/ObjectsComparer/ObjectsComparer/Context/NullComparisonContextFactory.cs @@ -1,17 +1,17 @@ -using System.Reflection; +//using System.Reflection; -namespace ObjectsComparer -{ - internal class NullComparisonContextFactory : IComparisonContextFactory - { - public IComparisonContext CreateContext(IComparisonContext ancestor = null, string memberName = null) - { - return new NullComparisonContext(DefaultComparisonContextFactory.CreateMember(memberName, null), ancestor); - } +//namespace ObjectsComparer +//{ +// internal class NullComparisonContextFactory : IComparisonContextFactory +// { +// public IComparisonContext CreateContext(IComparisonContext ancestor = null, string memberName = null) +// { +// return new NullComparisonContext(DefaultComparisonContextFactory.CreateMember(memberName, null), ancestor); +// } - public IComparisonContext CreateContext(IComparisonContext ancestor = null, MemberInfo member = null) - { - return new NullComparisonContext(DefaultComparisonContextFactory.CreateMember(null, member), ancestor); - } - } -} +// public IComparisonContext CreateContext(IComparisonContext ancestor = null, MemberInfo member = null) +// { +// return new NullComparisonContext(DefaultComparisonContextFactory.CreateMember(null, member), ancestor); +// } +// } +//} From d3d1ac5fea99f90eae5a7e61c12d1cd8b5b1c1df Mon Sep 17 00:00:00 2001 From: Daniel Nemec Date: Sun, 16 Jan 2022 11:48:29 +0100 Subject: [PATCH 094/181] Replace IComparisonContextFactory with lambda. --- ObjectsComparer/ObjectsComparer/Comparer~1.cs | 2 +- .../Context/ComparisonContext.cs | 3 +- .../Context/ComparisonContextBase.cs | 7 ++-- .../Context/ComparisonContextOptions.cs | 6 +-- .../Context/ComparisonContextProvider.cs | 37 ++++++------------- .../Context/CreateComparisonContextArgs.cs | 23 ++++++++++++ .../Context/IComparisonContextFactory.cs | 20 ---------- .../Context/NullComparisonContext.cs | 2 +- .../Context/NullComparisonContextFactory.cs | 17 --------- .../AbstractDynamicObjectsComprer.cs | 2 +- 10 files changed, 45 insertions(+), 74 deletions(-) create mode 100644 ObjectsComparer/ObjectsComparer/Context/CreateComparisonContextArgs.cs delete mode 100644 ObjectsComparer/ObjectsComparer/Context/IComparisonContextFactory.cs delete mode 100644 ObjectsComparer/ObjectsComparer/Context/NullComparisonContextFactory.cs diff --git a/ObjectsComparer/ObjectsComparer/Comparer~1.cs b/ObjectsComparer/ObjectsComparer/Comparer~1.cs index 48baad4..8460a55 100644 --- a/ObjectsComparer/ObjectsComparer/Comparer~1.cs +++ b/ObjectsComparer/ObjectsComparer/Comparer~1.cs @@ -124,7 +124,7 @@ IEnumerable CalculateDifferences(T obj1, T obj2, MemberInfo memberIn continue; } - var memberContext = new ComparisonContext(new ComparisonContextMember(member), comparisonContext); + var memberContext = new ComparisonContext(comparisonContext, new ComparisonContextMember(member)); var valueComparer = DefaultValueComparer; var hasCustomComparer = false; diff --git a/ObjectsComparer/ObjectsComparer/Context/ComparisonContext.cs b/ObjectsComparer/ObjectsComparer/Context/ComparisonContext.cs index 2333a95..7da8d9c 100644 --- a/ObjectsComparer/ObjectsComparer/Context/ComparisonContext.cs +++ b/ObjectsComparer/ObjectsComparer/Context/ComparisonContext.cs @@ -11,8 +11,9 @@ namespace ObjectsComparer /// public sealed class ComparisonContext : ComparisonContextBase { - public ComparisonContext(IComparisonContextMember member = null, IComparisonContext ancestor = null) : base(member, ancestor) + public ComparisonContext(IComparisonContext ancestor = null, IComparisonContextMember member = null) : base(ancestor, member) { + } } } \ No newline at end of file diff --git a/ObjectsComparer/ObjectsComparer/Context/ComparisonContextBase.cs b/ObjectsComparer/ObjectsComparer/Context/ComparisonContextBase.cs index 2c8e583..217b179 100644 --- a/ObjectsComparer/ObjectsComparer/Context/ComparisonContextBase.cs +++ b/ObjectsComparer/ObjectsComparer/Context/ComparisonContextBase.cs @@ -15,11 +15,10 @@ public abstract class ComparisonContextBase : IComparisonContext readonly List _differences = new List(); - public ComparisonContextBase(IComparisonContextMember member = null, IComparisonContext ancestor = null) + public ComparisonContextBase(IComparisonContext ancestor = null, IComparisonContextMember member = null) { - Ancestor = ancestor; - ancestor?.AddDescendant(this); - Member = member; + ancestor.AddDescendant(this); + Member = member ?? throw new ArgumentNullException(nameof(member)); } public IComparisonContext Ancestor { get; set; } diff --git a/ObjectsComparer/ObjectsComparer/Context/ComparisonContextOptions.cs b/ObjectsComparer/ObjectsComparer/Context/ComparisonContextOptions.cs index 5ad7f97..150ff4c 100644 --- a/ObjectsComparer/ObjectsComparer/Context/ComparisonContextOptions.cs +++ b/ObjectsComparer/ObjectsComparer/Context/ComparisonContextOptions.cs @@ -14,11 +14,11 @@ internal static ComparisonContextOptions Default() return new ComparisonContextOptions(); } - internal IComparisonContextFactory CustomComparisonContextFactory { get; private set; } + internal Func ComparisonContextFactory { get; private set; } - public void UseComparisonContextFactory(IComparisonContextFactory comparisonContextFactory) + public void UseComparisonContextFactory(Func factory) { - CustomComparisonContextFactory = comparisonContextFactory ?? throw new ArgumentNullException(nameof(comparisonContextFactory)); + ComparisonContextFactory = factory ?? throw new ArgumentNullException(nameof(factory)); } } } diff --git a/ObjectsComparer/ObjectsComparer/Context/ComparisonContextProvider.cs b/ObjectsComparer/ObjectsComparer/Context/ComparisonContextProvider.cs index b5e21a7..ed9f316 100644 --- a/ObjectsComparer/ObjectsComparer/Context/ComparisonContextProvider.cs +++ b/ObjectsComparer/ObjectsComparer/Context/ComparisonContextProvider.cs @@ -10,39 +10,24 @@ public static IComparisonContext CreateNullContext() return new NullComparisonContext(); } - /// - /// takes precedence over . - /// - public static IComparisonContext CreateContext(ComparisonContextOptions options, IComparisonContext ancestor, MemberInfo member, string memberName) + public static IComparisonContext CreateContext(ComparisonSettings comparisonSettings, CreateComparisonContextArgs createContextArgs) { - if (options is null) + if (comparisonSettings is null) { - throw new ArgumentNullException(nameof(options)); + throw new ArgumentNullException(nameof(comparisonSettings)); } - if (ShouldCreateNullContext(ancestor)) + ComparisonContextOptions options = ComparisonContextOptions.Default(); + comparisonSettings.ComparisonContextOptionsAction?.Invoke(options); + + if (options.ComparisonContextFactory != null) { - return new NullComparisonContext(null, null); + return options.ComparisonContextFactory(createContextArgs); } - - var ancestorInfo = ancestor != null ? new ComparisonContextInfo(ancestor) : null; - - if (options.CustomComparisonContextFactory != null) + else { - if (member != null) - { - return options.CustomComparisonContextFactory.CreateContext(member, ancestorInfo); - } - - if (string.IsNullOrWhiteSpace(memberName)) - { - return options.CustomComparisonContextFactory.CreateContext(memberName, ancestorInfo); - } - - return options.CustomComparisonContextFactory.CreateContext(ancestorInfo); + return new ComparisonContext(createContextArgs.Ancestor, CreateComparisonContextMember(createContextArgs.Member, createContextArgs.MemberName)); } - - return new ComparisonContext(CreateComparisonContextMember(memberName, member), ancestor); } static bool ShouldCreateNullContext(IComparisonContext ancestor) @@ -61,7 +46,7 @@ static bool ShouldCreateNullContext(IComparisonContext ancestor) return false; } - static IComparisonContextMember CreateComparisonContextMember(string memberName, MemberInfo member) + static IComparisonContextMember CreateComparisonContextMember(MemberInfo member, string memberName) { if (member != null) { diff --git a/ObjectsComparer/ObjectsComparer/Context/CreateComparisonContextArgs.cs b/ObjectsComparer/ObjectsComparer/Context/CreateComparisonContextArgs.cs new file mode 100644 index 0000000..4bf533f --- /dev/null +++ b/ObjectsComparer/ObjectsComparer/Context/CreateComparisonContextArgs.cs @@ -0,0 +1,23 @@ +using System.Reflection; + +namespace ObjectsComparer +{ + /// + /// Arguments for . + /// + public class CreateComparisonContextArgs + { + public CreateComparisonContextArgs(IComparisonContext ancestor = null, MemberInfo member = null, string memberName = null) + { + Ancestor = ancestor; + Member = member; + MemberName = memberName; + } + + public IComparisonContext Ancestor { get; } + + public MemberInfo Member { get; set; } + + public string MemberName { get; set; } + } +} diff --git a/ObjectsComparer/ObjectsComparer/Context/IComparisonContextFactory.cs b/ObjectsComparer/ObjectsComparer/Context/IComparisonContextFactory.cs deleted file mode 100644 index ef64c4c..0000000 --- a/ObjectsComparer/ObjectsComparer/Context/IComparisonContextFactory.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System.Reflection; - -namespace ObjectsComparer -{ - //public interface IComparisonContextFactory - //{ - // IComparisonContext CreateContext(IComparisonContext ancestor = null, string memberName = null); - - // IComparisonContext CreateContext(IComparisonContext ancestor = null, MemberInfo member = null); - //} - - public interface IComparisonContextFactory - { - IComparisonContext CreateContext(IComparisonContextInfo ancestor = null); - - IComparisonContext CreateContext(string memberName, IComparisonContextInfo ancestor = null); - - IComparisonContext CreateContext(MemberInfo member, IComparisonContextInfo ancestor = null); - } -} diff --git a/ObjectsComparer/ObjectsComparer/Context/NullComparisonContext.cs b/ObjectsComparer/ObjectsComparer/Context/NullComparisonContext.cs index 7afbaad..197c689 100644 --- a/ObjectsComparer/ObjectsComparer/Context/NullComparisonContext.cs +++ b/ObjectsComparer/ObjectsComparer/Context/NullComparisonContext.cs @@ -8,7 +8,7 @@ namespace ObjectsComparer /// internal class NullComparisonContext : ComparisonContextBase { - public NullComparisonContext(IComparisonContextMember member = null, IComparisonContext ancestor = null) : base(member, ancestor) + public NullComparisonContext(IComparisonContextMember member = null, IComparisonContext ancestor = null) : base(ancestor, member) { } diff --git a/ObjectsComparer/ObjectsComparer/Context/NullComparisonContextFactory.cs b/ObjectsComparer/ObjectsComparer/Context/NullComparisonContextFactory.cs deleted file mode 100644 index d63b5be..0000000 --- a/ObjectsComparer/ObjectsComparer/Context/NullComparisonContextFactory.cs +++ /dev/null @@ -1,17 +0,0 @@ -//using System.Reflection; - -//namespace ObjectsComparer -//{ -// internal class NullComparisonContextFactory : IComparisonContextFactory -// { -// public IComparisonContext CreateContext(IComparisonContext ancestor = null, string memberName = null) -// { -// return new NullComparisonContext(DefaultComparisonContextFactory.CreateMember(memberName, null), ancestor); -// } - -// public IComparisonContext CreateContext(IComparisonContext ancestor = null, MemberInfo member = null) -// { -// return new NullComparisonContext(DefaultComparisonContextFactory.CreateMember(null, member), ancestor); -// } -// } -//} diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractDynamicObjectsComprer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractDynamicObjectsComprer.cs index a2b350f..b449e42 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractDynamicObjectsComprer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractDynamicObjectsComprer.cs @@ -52,7 +52,7 @@ public virtual IEnumerable CalculateDifferences(Type type, object ob } var keyComparisonContextMember = (member1 ?? member2) != null ? new ComparisonContextMember(member1 ?? member2) : new ComparisonContextMember(propertyKey); - var keyComparisonContext = new ComparisonContext(keyComparisonContextMember, comparisonContext); + var keyComparisonContext = new ComparisonContext(comparisonContext, keyComparisonContextMember); var propertyType = (value1 ?? value2)?.GetType() ?? typeof(object); var customComparer = OverridesCollection.GetComparer(propertyType) ?? From d800562939f5e745cbb1ecf6c6b46831b4004e23 Mon Sep 17 00:00:00 2001 From: Daniel Nemec Date: Sun, 16 Jan 2022 18:25:15 +0100 Subject: [PATCH 095/181] Edit ComparisonContextProvider. --- ObjectsComparer/ObjectsComparer/Comparer~1.cs | 2 +- ObjectsComparer/ObjectsComparer/Context/ComparisonContext.cs | 2 +- .../ObjectsComparer/Context/ComparisonContextProvider.cs | 2 +- .../ObjectsComparer/Context/CreateComparisonContextArgs.cs | 4 ++-- .../CustomComparers/AbstractDynamicObjectsComprer.cs | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/ObjectsComparer/ObjectsComparer/Comparer~1.cs b/ObjectsComparer/ObjectsComparer/Comparer~1.cs index 8460a55..48baad4 100644 --- a/ObjectsComparer/ObjectsComparer/Comparer~1.cs +++ b/ObjectsComparer/ObjectsComparer/Comparer~1.cs @@ -124,7 +124,7 @@ IEnumerable CalculateDifferences(T obj1, T obj2, MemberInfo memberIn continue; } - var memberContext = new ComparisonContext(comparisonContext, new ComparisonContextMember(member)); + var memberContext = new ComparisonContext(new ComparisonContextMember(member), comparisonContext); var valueComparer = DefaultValueComparer; var hasCustomComparer = false; diff --git a/ObjectsComparer/ObjectsComparer/Context/ComparisonContext.cs b/ObjectsComparer/ObjectsComparer/Context/ComparisonContext.cs index 7da8d9c..b85fdc3 100644 --- a/ObjectsComparer/ObjectsComparer/Context/ComparisonContext.cs +++ b/ObjectsComparer/ObjectsComparer/Context/ComparisonContext.cs @@ -11,7 +11,7 @@ namespace ObjectsComparer /// public sealed class ComparisonContext : ComparisonContextBase { - public ComparisonContext(IComparisonContext ancestor = null, IComparisonContextMember member = null) : base(ancestor, member) + public ComparisonContext(IComparisonContextMember member = null, IComparisonContext ancestor = null) : base(ancestor, member) { } diff --git a/ObjectsComparer/ObjectsComparer/Context/ComparisonContextProvider.cs b/ObjectsComparer/ObjectsComparer/Context/ComparisonContextProvider.cs index ed9f316..83ff2d6 100644 --- a/ObjectsComparer/ObjectsComparer/Context/ComparisonContextProvider.cs +++ b/ObjectsComparer/ObjectsComparer/Context/ComparisonContextProvider.cs @@ -26,7 +26,7 @@ public static IComparisonContext CreateContext(ComparisonSettings comparisonSett } else { - return new ComparisonContext(createContextArgs.Ancestor, CreateComparisonContextMember(createContextArgs.Member, createContextArgs.MemberName)); + return new ComparisonContext(CreateComparisonContextMember(createContextArgs.Member, createContextArgs.MemberName), createContextArgs.Ancestor); } } diff --git a/ObjectsComparer/ObjectsComparer/Context/CreateComparisonContextArgs.cs b/ObjectsComparer/ObjectsComparer/Context/CreateComparisonContextArgs.cs index 4bf533f..ce7089f 100644 --- a/ObjectsComparer/ObjectsComparer/Context/CreateComparisonContextArgs.cs +++ b/ObjectsComparer/ObjectsComparer/Context/CreateComparisonContextArgs.cs @@ -16,8 +16,8 @@ public CreateComparisonContextArgs(IComparisonContext ancestor = null, MemberInf public IComparisonContext Ancestor { get; } - public MemberInfo Member { get; set; } + public MemberInfo Member { get; } - public string MemberName { get; set; } + public string MemberName { get; } } } diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractDynamicObjectsComprer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractDynamicObjectsComprer.cs index b449e42..a2b350f 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractDynamicObjectsComprer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractDynamicObjectsComprer.cs @@ -52,7 +52,7 @@ public virtual IEnumerable CalculateDifferences(Type type, object ob } var keyComparisonContextMember = (member1 ?? member2) != null ? new ComparisonContextMember(member1 ?? member2) : new ComparisonContextMember(propertyKey); - var keyComparisonContext = new ComparisonContext(comparisonContext, keyComparisonContextMember); + var keyComparisonContext = new ComparisonContext(keyComparisonContextMember, comparisonContext); var propertyType = (value1 ?? value2)?.GetType() ?? typeof(object); var customComparer = OverridesCollection.GetComparer(propertyType) ?? From d20db1a80b2caaa77eb99c30a54628143798ccb1 Mon Sep 17 00:00:00 2001 From: nemec Date: Fri, 21 Jan 2022 15:13:43 +0100 Subject: [PATCH 096/181] Replace ComparisonContext with IComparisonContext. --- .../ObjectsComparer/BaseComparer.cs | 2 +- ObjectsComparer/ObjectsComparer/Comparer.cs | 6 +- ObjectsComparer/ObjectsComparer/Comparer~1.cs | 9 ++- .../ObjectsComparer/ComparisonSettings.cs | 7 +- .../Context/ComparisonContext.cs | 2 +- .../Context/ComparisonContextBase.cs | 2 +- .../Context/ComparisonContextOptions.cs | 5 ++ .../Context/ComparisonContextProvider.cs | 79 ++++++++++++++++--- .../Context/CreateComparisonContextArgs.cs | 49 +++++++++++- .../Context/IComparerExtensions.cs | 4 +- .../Context/IContextableComparer.cs | 2 +- .../Context/IContextableComparer~1.cs | 2 +- .../Context/NullComparisonContext.cs | 2 +- .../AbstractDynamicObjectsComprer.cs | 13 +-- .../AbstractEnumerablesComparer.cs | 2 +- .../CustomComparers/EnumerablesComparer.cs | 4 +- .../EnumerablesComparerBase.cs | 12 +-- .../CustomComparers/EnumerablesComparer~1.cs | 6 +- .../GenericEnumerablesComparer.cs | 2 +- .../CustomComparers/HashSetsComparer.cs | 2 +- .../CustomComparers/HashSetsComparer~1.cs | 4 +- .../MultidimensionalArrayComparer~1.cs | 4 +- .../MultidimensionalArraysComparer.cs | 2 +- .../CustomComparers/TypesComparer.cs | 2 +- .../Exceptions/ElementKeyNotFoundException.cs | 4 +- 25 files changed, 167 insertions(+), 61 deletions(-) diff --git a/ObjectsComparer/ObjectsComparer/BaseComparer.cs b/ObjectsComparer/ObjectsComparer/BaseComparer.cs index 496ddbe..c125826 100644 --- a/ObjectsComparer/ObjectsComparer/BaseComparer.cs +++ b/ObjectsComparer/ObjectsComparer/BaseComparer.cs @@ -188,7 +188,7 @@ public void IgnoreMember(Func filter) /// Adds an to the end of the 's . /// /// The argument. - protected virtual Difference AddDifferenceToComparisonContext(Difference difference, ComparisonContext comparisonContext) + protected virtual Difference AddDifferenceToComparisonContext(Difference difference, IComparisonContext comparisonContext) { if (difference is null) { diff --git a/ObjectsComparer/ObjectsComparer/Comparer.cs b/ObjectsComparer/ObjectsComparer/Comparer.cs index cb6c85b..e82d45c 100644 --- a/ObjectsComparer/ObjectsComparer/Comparer.cs +++ b/ObjectsComparer/ObjectsComparer/Comparer.cs @@ -29,10 +29,10 @@ public Comparer(ComparisonSettings settings = null, BaseComparer parentComparer public override IEnumerable CalculateDifferences(Type type, object obj1, object obj2) { - return CalculateDifferences(type, obj1, obj2, ComparisonContextProvider.CreateNullContext()); + return CalculateDifferences(type, obj1, obj2, ComparisonContextProvider.CreateImplicitRootContext(Settings)); } - public IEnumerable CalculateDifferences(Type type, object obj1, object obj2, ComparisonContext comparisonContext) + public IEnumerable CalculateDifferences(Type type, object obj1, object obj2, IComparisonContext comparisonContext) { if (comparisonContext is null) { @@ -55,7 +55,7 @@ public IEnumerable CalculateDifferences(Type type, object obj1, obje } var genericType = comparerIsIContextableComparerT ? typeof(IContextableComparer<>).MakeGenericType(type) : typeof(IComparer<>).MakeGenericType(type); - var genericMethodParameterTypes = comparerIsIContextableComparerT ? new[] { type, type, typeof(ComparisonContext) } : new[] { type, type }; + var genericMethodParameterTypes = comparerIsIContextableComparerT ? new[] { type, type, typeof(IComparisonContext) } : new[] { type, type }; var genericMethod = genericType.GetTypeInfo().GetMethod(CalculateDifferencesMethodName, genericMethodParameterTypes); var genericMethodParameters = comparerIsIContextableComparerT ? new[] { obj1, obj2, comparisonContext } : new[] { obj1, obj2 }; diff --git a/ObjectsComparer/ObjectsComparer/Comparer~1.cs b/ObjectsComparer/ObjectsComparer/Comparer~1.cs index 48baad4..b74632d 100644 --- a/ObjectsComparer/ObjectsComparer/Comparer~1.cs +++ b/ObjectsComparer/ObjectsComparer/Comparer~1.cs @@ -56,17 +56,17 @@ public override IEnumerable CalculateDifferences(T obj1, T obj2) return CalculateDifferences(obj1, obj2, memberInfo: null); } - public IEnumerable CalculateDifferences(T obj1, T obj2, ComparisonContext comparisonContext) + public IEnumerable CalculateDifferences(T obj1, T obj2, IComparisonContext comparisonContext) { return CalculateDifferences(obj1, obj2, memberInfo: null, comparisonContext); } internal IEnumerable CalculateDifferences(T obj1, T obj2, MemberInfo memberInfo) { - return CalculateDifferences(obj1, obj2, memberInfo, new ComparisonContext()); + return CalculateDifferences(obj1, obj2, memberInfo, ComparisonContextProvider.CreateImplicitRootContext(Settings)); } - IEnumerable CalculateDifferences(T obj1, T obj2, MemberInfo memberInfo, ComparisonContext comparisonContext) + IEnumerable CalculateDifferences(T obj1, T obj2, MemberInfo memberInfo, IComparisonContext comparisonContext) { var comparer = memberInfo != null ? OverridesCollection.GetComparer(memberInfo) @@ -124,7 +124,8 @@ IEnumerable CalculateDifferences(T obj1, T obj2, MemberInfo memberIn continue; } - var memberContext = new ComparisonContext(new ComparisonContextMember(member), comparisonContext); + var memberContext = ComparisonContextProvider.CreateMemberContext(Settings, comparisonContext, member); + //var memberContext = new ComparisonContext(new ComparisonContextMember(member), comparisonContext); var valueComparer = DefaultValueComparer; var hasCustomComparer = false; diff --git a/ObjectsComparer/ObjectsComparer/ComparisonSettings.cs b/ObjectsComparer/ObjectsComparer/ComparisonSettings.cs index ad0dc6b..294dc7c 100644 --- a/ObjectsComparer/ObjectsComparer/ComparisonSettings.cs +++ b/ObjectsComparer/ObjectsComparer/ComparisonSettings.cs @@ -121,12 +121,7 @@ public void ConfigureListComparison(bool compareElementsByKey = false, bool comp public void ConfigureComparisonContext(Action comparisonContextOptions) { - if (comparisonContextOptions is null) - { - throw new ArgumentNullException(nameof(comparisonContextOptions)); - } - - ComparisonContextOptionsAction = comparisonContextOptions; + ComparisonContextOptionsAction = comparisonContextOptions ?? throw new ArgumentNullException(nameof(comparisonContextOptions)); } } } diff --git a/ObjectsComparer/ObjectsComparer/Context/ComparisonContext.cs b/ObjectsComparer/ObjectsComparer/Context/ComparisonContext.cs index b85fdc3..cb9b821 100644 --- a/ObjectsComparer/ObjectsComparer/Context/ComparisonContext.cs +++ b/ObjectsComparer/ObjectsComparer/Context/ComparisonContext.cs @@ -11,7 +11,7 @@ namespace ObjectsComparer /// public sealed class ComparisonContext : ComparisonContextBase { - public ComparisonContext(IComparisonContextMember member = null, IComparisonContext ancestor = null) : base(ancestor, member) + public ComparisonContext(IComparisonContextMember member = null, IComparisonContext ancestor = null) : base(member, ancestor) { } diff --git a/ObjectsComparer/ObjectsComparer/Context/ComparisonContextBase.cs b/ObjectsComparer/ObjectsComparer/Context/ComparisonContextBase.cs index 217b179..0018c41 100644 --- a/ObjectsComparer/ObjectsComparer/Context/ComparisonContextBase.cs +++ b/ObjectsComparer/ObjectsComparer/Context/ComparisonContextBase.cs @@ -15,7 +15,7 @@ public abstract class ComparisonContextBase : IComparisonContext readonly List _differences = new List(); - public ComparisonContextBase(IComparisonContext ancestor = null, IComparisonContextMember member = null) + public ComparisonContextBase(IComparisonContextMember member = null, IComparisonContext ancestor = null) { ancestor.AddDescendant(this); Member = member ?? throw new ArgumentNullException(nameof(member)); diff --git a/ObjectsComparer/ObjectsComparer/Context/ComparisonContextOptions.cs b/ObjectsComparer/ObjectsComparer/Context/ComparisonContextOptions.cs index 150ff4c..e4a5071 100644 --- a/ObjectsComparer/ObjectsComparer/Context/ComparisonContextOptions.cs +++ b/ObjectsComparer/ObjectsComparer/Context/ComparisonContextOptions.cs @@ -16,6 +16,11 @@ internal static ComparisonContextOptions Default() internal Func ComparisonContextFactory { get; private set; } + /// + /// + /// + /// If factory returns null, the default comparison context will be used. + /// public void UseComparisonContextFactory(Func factory) { ComparisonContextFactory = factory ?? throw new ArgumentNullException(nameof(factory)); diff --git a/ObjectsComparer/ObjectsComparer/Context/ComparisonContextProvider.cs b/ObjectsComparer/ObjectsComparer/Context/ComparisonContextProvider.cs index 83ff2d6..df9c981 100644 --- a/ObjectsComparer/ObjectsComparer/Context/ComparisonContextProvider.cs +++ b/ObjectsComparer/ObjectsComparer/Context/ComparisonContextProvider.cs @@ -5,29 +5,90 @@ namespace ObjectsComparer { internal static class ComparisonContextProvider { - public static IComparisonContext CreateNullContext() + internal static IComparisonContext CreateImplicitRootContext(ComparisonSettings comparisonSettings) { + _ = comparisonSettings ?? throw new ArgumentNullException(nameof(comparisonSettings)); //For the future. + return new NullComparisonContext(); + } + + /// + /// Context without ancestor and without member. + /// + public static IComparisonContext CreateRootContext(ComparisonSettings comparisonSettings) + { + _ = comparisonSettings ?? throw new ArgumentNullException(nameof(comparisonSettings)); + + return CreateContext(comparisonSettings, new CreateComparisonContextArgs()); } - public static IComparisonContext CreateContext(ComparisonSettings comparisonSettings, CreateComparisonContextArgs createContextArgs) + /// + /// Context with ancestor but without a member. + /// + public static IComparisonContext CreateListElementContext(ComparisonSettings comparisonSettings, IComparisonContext ancestor) { - if (comparisonSettings is null) + return CreateContext(comparisonSettings, new CreateComparisonContextArgs(ancestor)); + } + + /// + /// Context with ancestor and member. + /// + public static IComparisonContext CreateMemberContext(ComparisonSettings comparisonSettings, IComparisonContext ancestor, MemberInfo member) + { + return CreateContext(comparisonSettings, new CreateComparisonContextArgs(ancestor, member)); + } + + /// + /// Context with ancestor and member. + /// + public static IComparisonContext CreateMemberNameContext(ComparisonSettings comparisonSettings, IComparisonContext ancestor, string memberName) + { + return CreateContext(comparisonSettings, new CreateComparisonContextArgs(ancestor, memberName)); + } + + /// + /// Context with ancestor and member. The takes precedence over . + /// + internal static IComparisonContext CreateMemberOrMemberNameContext(ComparisonSettings comparisonSettings, IComparisonContext ancestor, MemberInfo member, string memberName) + { + _ = comparisonSettings ?? throw new ArgumentNullException(nameof(comparisonSettings)); + + if (member != null) { - throw new ArgumentNullException(nameof(comparisonSettings)); + return CreateMemberContext(comparisonSettings, ancestor, member); } + if (memberName != null) + { + return CreateMemberNameContext(comparisonSettings, ancestor, memberName); + } + + if (ancestor != null) + { + return CreateListElementContext(comparisonSettings, ancestor); + } + + return CreateRootContext(comparisonSettings); + } + + static IComparisonContext CreateContext(ComparisonSettings comparisonSettings, CreateComparisonContextArgs createContextArgs) + { + _ = comparisonSettings ?? throw new ArgumentNullException(nameof(comparisonSettings)); + _ = createContextArgs ?? throw new ArgumentNullException(nameof(createContextArgs)); + ComparisonContextOptions options = ComparisonContextOptions.Default(); comparisonSettings.ComparisonContextOptionsAction?.Invoke(options); if (options.ComparisonContextFactory != null) { - return options.ComparisonContextFactory(createContextArgs); - } - else - { - return new ComparisonContext(CreateComparisonContextMember(createContextArgs.Member, createContextArgs.MemberName), createContextArgs.Ancestor); + var context = options.ComparisonContextFactory(createContextArgs); + if (context != null) + { + return context; + } } + + return new ComparisonContext(CreateComparisonContextMember(createContextArgs.Member, createContextArgs.MemberName), createContextArgs.Ancestor); } static bool ShouldCreateNullContext(IComparisonContext ancestor) diff --git a/ObjectsComparer/ObjectsComparer/Context/CreateComparisonContextArgs.cs b/ObjectsComparer/ObjectsComparer/Context/CreateComparisonContextArgs.cs index ce7089f..1c09d8e 100644 --- a/ObjectsComparer/ObjectsComparer/Context/CreateComparisonContextArgs.cs +++ b/ObjectsComparer/ObjectsComparer/Context/CreateComparisonContextArgs.cs @@ -3,21 +3,62 @@ namespace ObjectsComparer { /// - /// Arguments for . + /// Arguments for factory method. See . + /// If all properties are null, the instance is probably intended to create a root context. /// public class CreateComparisonContextArgs { - public CreateComparisonContextArgs(IComparisonContext ancestor = null, MemberInfo member = null, string memberName = null) + /// + /// Context without ancestor and without member. + /// + internal CreateComparisonContextArgs() { - Ancestor = ancestor; - Member = member; + } + + /// + /// Context with ancestor but without a member. + /// + internal CreateComparisonContextArgs(IComparisonContext ancestor) + { + Ancestor = ancestor ?? throw new System.ArgumentNullException(nameof(ancestor)); + } + + /// + /// Context with ancestor and member. + /// + internal CreateComparisonContextArgs(IComparisonContext ancestor, MemberInfo member) + { + Ancestor = ancestor ?? throw new System.ArgumentNullException(nameof(ancestor)); + Member = member ?? throw new System.ArgumentNullException(nameof(member)); + } + + /// + /// Context with ancestor and member. + /// + internal CreateComparisonContextArgs(IComparisonContext ancestor, string memberName) + { + if (string.IsNullOrEmpty(memberName)) + { + throw new System.ArgumentException($"'{nameof(memberName)}' cannot be null or empty.", nameof(memberName)); + } + + Ancestor = ancestor ?? throw new System.ArgumentNullException(nameof(ancestor)); MemberName = memberName; } + /// + /// Nullable. + /// public IComparisonContext Ancestor { get; } + /// + /// Nullable. + /// public MemberInfo Member { get; } + /// + /// Nullable. + /// public string MemberName { get; } } } diff --git a/ObjectsComparer/ObjectsComparer/Context/IComparerExtensions.cs b/ObjectsComparer/ObjectsComparer/Context/IComparerExtensions.cs index 27d151c..8b51f95 100644 --- a/ObjectsComparer/ObjectsComparer/Context/IComparerExtensions.cs +++ b/ObjectsComparer/ObjectsComparer/Context/IComparerExtensions.cs @@ -20,7 +20,7 @@ public static class IComparerExtensions /// Current comparison context. For more info see class. /// List of differences between objects. /// If does not implement . - public static IEnumerable CalculateDifferences(this IComparer comparer, Type type, object obj1, object obj2, ComparisonContext comparisonContext) + public static IEnumerable CalculateDifferences(this IComparer comparer, Type type, object obj1, object obj2, IComparisonContext comparisonContext) { if (comparer is null) { @@ -46,7 +46,7 @@ public static IEnumerable CalculateDifferences(this IComparer compar //return comparer.CalculateDifferences(type, obj1, obj2); } - public static IEnumerable CalculateDifferences(this IComparer comparer, T obj1, T obj2, ComparisonContext comparisonContext) + public static IEnumerable CalculateDifferences(this IComparer comparer, T obj1, T obj2, IComparisonContext comparisonContext) { if (comparer is null) { diff --git a/ObjectsComparer/ObjectsComparer/Context/IContextableComparer.cs b/ObjectsComparer/ObjectsComparer/Context/IContextableComparer.cs index 2d0c4ba..220c7d7 100644 --- a/ObjectsComparer/ObjectsComparer/Context/IContextableComparer.cs +++ b/ObjectsComparer/ObjectsComparer/Context/IContextableComparer.cs @@ -8,6 +8,6 @@ namespace ObjectsComparer /// public interface IContextableComparer { - IEnumerable CalculateDifferences(Type type, object obj1, object obj2, ComparisonContext comparisonContext); + IEnumerable CalculateDifferences(Type type, object obj1, object obj2, IComparisonContext comparisonContext); } } \ No newline at end of file diff --git a/ObjectsComparer/ObjectsComparer/Context/IContextableComparer~1.cs b/ObjectsComparer/ObjectsComparer/Context/IContextableComparer~1.cs index cdbc6d0..faffee7 100644 --- a/ObjectsComparer/ObjectsComparer/Context/IContextableComparer~1.cs +++ b/ObjectsComparer/ObjectsComparer/Context/IContextableComparer~1.cs @@ -8,6 +8,6 @@ namespace ObjectsComparer /// public interface IContextableComparer { - IEnumerable CalculateDifferences(T obj1, T obj2, ComparisonContext comparisonContext); + IEnumerable CalculateDifferences(T obj1, T obj2, IComparisonContext comparisonContext); } } diff --git a/ObjectsComparer/ObjectsComparer/Context/NullComparisonContext.cs b/ObjectsComparer/ObjectsComparer/Context/NullComparisonContext.cs index 197c689..7afbaad 100644 --- a/ObjectsComparer/ObjectsComparer/Context/NullComparisonContext.cs +++ b/ObjectsComparer/ObjectsComparer/Context/NullComparisonContext.cs @@ -8,7 +8,7 @@ namespace ObjectsComparer /// internal class NullComparisonContext : ComparisonContextBase { - public NullComparisonContext(IComparisonContextMember member = null, IComparisonContext ancestor = null) : base(ancestor, member) + public NullComparisonContext(IComparisonContextMember member = null, IComparisonContext ancestor = null) : base(member, ancestor) { } diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractDynamicObjectsComprer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractDynamicObjectsComprer.cs index a2b350f..e2179ff 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractDynamicObjectsComprer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractDynamicObjectsComprer.cs @@ -14,15 +14,15 @@ protected AbstractDynamicObjectsComprer(ComparisonSettings settings, BaseCompare public override IEnumerable CalculateDifferences(Type type, object obj1, object obj2) { - return CalculateDifferences(type, obj1, obj2, new ComparisonContext()); + return CalculateDifferences(type, obj1, obj2, ComparisonContextProvider.CreateImplicitRootContext(Settings)); } - public virtual IEnumerable CalculateDifferences(T obj1, T obj2, ComparisonContext comparisonContext) + public virtual IEnumerable CalculateDifferences(T obj1, T obj2, IComparisonContext comparisonContext) { - return CalculateDifferences(typeof(T), obj1, obj2, new ComparisonContext()); + return CalculateDifferences(typeof(T), obj1, obj2, ComparisonContextProvider.CreateImplicitRootContext(Settings)); } - public virtual IEnumerable CalculateDifferences(Type type, object obj1, object obj2, ComparisonContext comparisonContext) + public virtual IEnumerable CalculateDifferences(Type type, object obj1, object obj2, IComparisonContext comparisonContext) { var castedObject1 = (T)obj1; var castedObject2 = (T)obj2; @@ -51,8 +51,9 @@ public virtual IEnumerable CalculateDifferences(Type type, object ob TryGetMember(castedObject1, propertyKey, out member2); } - var keyComparisonContextMember = (member1 ?? member2) != null ? new ComparisonContextMember(member1 ?? member2) : new ComparisonContextMember(propertyKey); - var keyComparisonContext = new ComparisonContext(keyComparisonContextMember, comparisonContext); + //var keyComparisonContextMember = (member1 ?? member2) != null ? new ComparisonContextMember(member1 ?? member2) : new ComparisonContextMember(propertyKey); + //var keyComparisonContext = new ComparisonContext(keyComparisonContextMember, comparisonContext); + var keyComparisonContext = ComparisonContextProvider.CreateMemberOrMemberNameContext(Settings, comparisonContext, member1 ?? member2, propertyKey); var propertyType = (value1 ?? value2)?.GetType() ?? typeof(object); var customComparer = OverridesCollection.GetComparer(propertyType) ?? diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractEnumerablesComparer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractEnumerablesComparer.cs index 88a7608..849607a 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractEnumerablesComparer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractEnumerablesComparer.cs @@ -59,6 +59,6 @@ public virtual bool SkipMember(Type type, MemberInfo member) public abstract bool IsMatch(Type type, object obj1, object obj2); - public abstract IEnumerable CalculateDifferences(Type type, object obj1, object obj2, ComparisonContext comparisonContext); + public abstract IEnumerable CalculateDifferences(Type type, object obj1, object obj2, IComparisonContext comparisonContext); } } \ No newline at end of file diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs index d803bff..e1ee04e 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs @@ -17,10 +17,10 @@ public EnumerablesComparer(ComparisonSettings settings, BaseComparer parentCompa public override IEnumerable CalculateDifferences(Type type, object obj1, object obj2) { - return CalculateDifferences(type, obj1, obj2, new ComparisonContext()); + return CalculateDifferences(type, obj1, obj2, ComparisonContextProvider.CreateImplicitRootContext(Settings)); } - public IEnumerable CalculateDifferences(Type type, object obj1, object obj2, ComparisonContext listComparisonContext) + public IEnumerable CalculateDifferences(Type type, object obj1, object obj2, IComparisonContext listComparisonContext) { Debug.WriteLine($"{GetType().Name}.{nameof(CalculateDifferences)}: {type.Name}"); diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparerBase.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparerBase.cs index 05a53db..913c4ff 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparerBase.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparerBase.cs @@ -15,7 +15,7 @@ public EnumerablesComparerBase(ComparisonSettings settings, BaseComparer parentC /// /// Selects calculation operation based on the current value of the property. /// - protected virtual IEnumerable CalculateDifferences(IList list1, IList list2, ComparisonContext listComparisonContext, ListComparisonOptions listComparisonOptions) + protected virtual IEnumerable CalculateDifferences(IList list1, IList list2, IComparisonContext listComparisonContext, ListComparisonOptions listComparisonOptions) { if (listComparisonOptions.ElementSearchMode == ListElementSearchMode.Key) { @@ -34,7 +34,7 @@ protected virtual IEnumerable CalculateDifferences(IList list1 /// /// Calculates differences using comparison mode. /// - protected virtual IEnumerable CalculateDifferencesByKey(IList array1, IList array2, ComparisonContext listComparisonContext, ListComparisonOptions listComparisonOptions) + protected virtual IEnumerable CalculateDifferencesByKey(IList array1, IList array2, IComparisonContext listComparisonContext, ListComparisonOptions listComparisonOptions) { Debug.WriteLine($"{GetType().Name}.{nameof(CalculateDifferencesByKey)}: {array1?.GetType().Name}"); @@ -44,7 +44,8 @@ protected virtual IEnumerable CalculateDifferencesByKey(IList for (int element1Index = 0; element1Index < array1.Count(); element1Index++) { var element1 = array1[element1Index]; - var elementComparisonContext = new ComparisonContext(new ComparisonContextMember(), listComparisonContext); + //var elementComparisonContext = new ComparisonContext(new ComparisonContextMember(), listComparisonContext); + var elementComparisonContext = ComparisonContextProvider.CreateListElementContext(Settings, listComparisonContext); if (element1 == null) { @@ -93,7 +94,8 @@ protected virtual IEnumerable CalculateDifferencesByKey(IList for (int element2Index = 0; element2Index < array2.Count(); element2Index++) { var element2 = array2[element2Index]; - var elementComparisonContext = new ComparisonContext(new ComparisonContextMember(), listComparisonContext); + //var elementComparisonContext = new ComparisonContext(new ComparisonContextMember(), listComparisonContext); + var elementComparisonContext = ComparisonContextProvider.CreateListElementContext(Settings, listComparisonContext); if (element2 == null) { @@ -132,7 +134,7 @@ protected virtual IEnumerable CalculateDifferencesByKey(IList /// /// Calculates differences using comparison mode. /// - protected virtual IEnumerable CalculateDifferencesByIndex(IList array1, IList array2, ComparisonContext listComparisonContext, ListComparisonOptions listComparisonOptions) + protected virtual IEnumerable CalculateDifferencesByIndex(IList array1, IList array2, IComparisonContext listComparisonContext, ListComparisonOptions listComparisonOptions) { Debug.WriteLine($"{GetType().Name}.{nameof(CalculateDifferencesByIndex)}: {array1?.GetType().Name}"); diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer~1.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer~1.cs index 10d83b5..0eda6fc 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer~1.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer~1.cs @@ -18,10 +18,10 @@ public EnumerablesComparer(ComparisonSettings settings, BaseComparer parentCompa public override IEnumerable CalculateDifferences(Type type, object obj1, object obj2) { - return CalculateDifferences(type, obj1, obj2, new ComparisonContext()); + return CalculateDifferences(type, obj1, obj2, ComparisonContextProvider.CreateImplicitRootContext(Settings)); } - public IEnumerable CalculateDifferences(Type type, object obj1, object obj2, ComparisonContext listComparisonContext) + public IEnumerable CalculateDifferences(Type type, object obj1, object obj2, IComparisonContext listComparisonContext) { Debug.WriteLine($"{GetType().Name}.{nameof(CalculateDifferences)}: {type.Name}"); @@ -82,7 +82,7 @@ public IEnumerable CalculateDifferences(Type type, object obj1, obje } } - public IEnumerable CalculateDifferences(T obj1, T obj2, ComparisonContext listComparisonContext) + public IEnumerable CalculateDifferences(T obj1, T obj2, IComparisonContext listComparisonContext) { return CalculateDifferences(((object)obj1 ?? obj2).GetType(), obj1, obj2, listComparisonContext); } diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/GenericEnumerablesComparer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/GenericEnumerablesComparer.cs index daf9c2e..99a302f 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/GenericEnumerablesComparer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/GenericEnumerablesComparer.cs @@ -20,7 +20,7 @@ public override IEnumerable CalculateDifferences(Type type, object o return CalculateDifferences(type, obj1, obj2, new ComparisonContext()); } - public override IEnumerable CalculateDifferences(Type type, object obj1, object obj2, ComparisonContext comparisonContext) + public override IEnumerable CalculateDifferences(Type type, object obj1, object obj2, IComparisonContext comparisonContext) { if (obj1 == null && obj2 == null) { diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/HashSetsComparer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/HashSetsComparer.cs index 2a84ff3..8a03ce3 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/HashSetsComparer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/HashSetsComparer.cs @@ -18,7 +18,7 @@ public override IEnumerable CalculateDifferences(Type type, object o return CalculateDifferences(type, obj1, obj2, new ComparisonContext()); } - public override IEnumerable CalculateDifferences(Type type, object obj1, object obj2, ComparisonContext comparisonContext) + public override IEnumerable CalculateDifferences(Type type, object obj1, object obj2, IComparisonContext comparisonContext) { if (obj1 == null && obj2 == null) { diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/HashSetsComparer~1.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/HashSetsComparer~1.cs index e656871..a989dd2 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/HashSetsComparer~1.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/HashSetsComparer~1.cs @@ -12,7 +12,7 @@ public HashSetsComparer(ComparisonSettings settings, BaseComparer parentComparer { } - public IEnumerable CalculateDifferences(T obj1, T obj2, ComparisonContext comparisonContext) + public IEnumerable CalculateDifferences(T obj1, T obj2, IComparisonContext comparisonContext) { return CalculateDifferences(typeof(T), obj1, obj2, comparisonContext); } @@ -22,7 +22,7 @@ public override IEnumerable CalculateDifferences(Type type, object o return CalculateDifferences(type, obj1, obj2, new ComparisonContext()); } - public IEnumerable CalculateDifferences(Type type, object obj1, object obj2, ComparisonContext comparisonContext) + public IEnumerable CalculateDifferences(Type type, object obj1, object obj2, IComparisonContext comparisonContext) { if (comparisonContext is null) { diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/MultidimensionalArrayComparer~1.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/MultidimensionalArrayComparer~1.cs index cf73d4a..b7b2fba 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/MultidimensionalArrayComparer~1.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/MultidimensionalArrayComparer~1.cs @@ -20,12 +20,12 @@ public override IEnumerable CalculateDifferences(Type type, object o return CalculateDifferences(type, obj1, obj2, new ComparisonContext()); } - public IEnumerable CalculateDifferences(T obj1, T obj2, ComparisonContext comparisonContext) + public IEnumerable CalculateDifferences(T obj1, T obj2, IComparisonContext comparisonContext) { return CalculateDifferences(typeof(T), obj1, obj2, comparisonContext); } - public IEnumerable CalculateDifferences(Type type, object obj1, object obj2, ComparisonContext comparisonContext) + public IEnumerable CalculateDifferences(Type type, object obj1, object obj2, IComparisonContext comparisonContext) { if (comparisonContext is null) { diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/MultidimensionalArraysComparer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/MultidimensionalArraysComparer.cs index 30c6e5e..dd09ca3 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/MultidimensionalArraysComparer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/MultidimensionalArraysComparer.cs @@ -18,7 +18,7 @@ public override IEnumerable CalculateDifferences(Type type, object o return CalculateDifferences(type, obj1, obj2, new ComparisonContext()); } - public override IEnumerable CalculateDifferences(Type type, object obj1, object obj2, ComparisonContext comparisonContext) + public override IEnumerable CalculateDifferences(Type type, object obj1, object obj2, IComparisonContext comparisonContext) { if (obj1 == null && obj2 == null) { diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/TypesComparer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/TypesComparer.cs index aafeb88..40bafa3 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/TypesComparer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/TypesComparer.cs @@ -18,7 +18,7 @@ public override IEnumerable CalculateDifferences(Type type, object o return CalculateDifferences(type, obj1, obj2, new ComparisonContext()); } - public IEnumerable CalculateDifferences(Type type, object obj1, object obj2, ComparisonContext comparisonContext) + public IEnumerable CalculateDifferences(Type type, object obj1, object obj2, IComparisonContext comparisonContext) { if (comparisonContext is null) { diff --git a/ObjectsComparer/ObjectsComparer/Exceptions/ElementKeyNotFoundException.cs b/ObjectsComparer/ObjectsComparer/Exceptions/ElementKeyNotFoundException.cs index 7978843..a059219 100644 --- a/ObjectsComparer/ObjectsComparer/Exceptions/ElementKeyNotFoundException.cs +++ b/ObjectsComparer/ObjectsComparer/Exceptions/ElementKeyNotFoundException.cs @@ -16,7 +16,7 @@ public class ElementKeyNotFoundException : Exception /// /// An element that is missing a key. /// - internal ElementKeyNotFoundException(object keylessElement, ComparisonContext keylessElementComparisonContext, string message = ElementKeyNotFoundExceptionMsg) : base(message) + internal ElementKeyNotFoundException(object keylessElement, IComparisonContext keylessElementComparisonContext, string message = ElementKeyNotFoundExceptionMsg) : base(message) { KeylessElement = keylessElement ?? throw new ArgumentNullException(nameof(keylessElement)); KeylessElementComparisonContext = keylessElementComparisonContext ?? throw new ArgumentNullException(nameof(keylessElementComparisonContext)); @@ -30,6 +30,6 @@ internal ElementKeyNotFoundException(object keylessElement, ComparisonContext ke /// /// The current in which the exception occurred. /// - public ComparisonContext KeylessElementComparisonContext { get; } + public IComparisonContext KeylessElementComparisonContext { get; } } } From 9b42c7c981375b0308cc56bc7b1058c4ce789588 Mon Sep 17 00:00:00 2001 From: Daniel Nemec Date: Sun, 23 Jan 2022 18:04:41 +0100 Subject: [PATCH 097/181] Edit IComparisonContext. --- .../ObjectsComparer/Context/ComparisonContext.cs | 2 +- .../Context/ComparisonContextOptions.cs | 2 +- .../Context/ComparisonContextProvider.cs | 12 ++++++------ .../ObjectsComparer/Context/IComparisonContext.cs | 4 ++-- .../ObjectsComparer/Context/IContextableComparer.cs | 2 +- .../CustomComparers/EnumerablesComparerBase.cs | 3 ++- .../MultidimensionalArrayComparer~1.cs | 2 +- 7 files changed, 14 insertions(+), 13 deletions(-) diff --git a/ObjectsComparer/ObjectsComparer/Context/ComparisonContext.cs b/ObjectsComparer/ObjectsComparer/Context/ComparisonContext.cs index cb9b821..dc43fe7 100644 --- a/ObjectsComparer/ObjectsComparer/Context/ComparisonContext.cs +++ b/ObjectsComparer/ObjectsComparer/Context/ComparisonContext.cs @@ -11,7 +11,7 @@ namespace ObjectsComparer /// public sealed class ComparisonContext : ComparisonContextBase { - public ComparisonContext(IComparisonContextMember member = null, IComparisonContext ancestor = null) : base(member, ancestor) + private ComparisonContext(IComparisonContextMember member = null, IComparisonContext ancestor = null) : base(member, ancestor) { } diff --git a/ObjectsComparer/ObjectsComparer/Context/ComparisonContextOptions.cs b/ObjectsComparer/ObjectsComparer/Context/ComparisonContextOptions.cs index e4a5071..b735c83 100644 --- a/ObjectsComparer/ObjectsComparer/Context/ComparisonContextOptions.cs +++ b/ObjectsComparer/ObjectsComparer/Context/ComparisonContextOptions.cs @@ -17,7 +17,7 @@ internal static ComparisonContextOptions Default() internal Func ComparisonContextFactory { get; private set; } /// - /// + /// Creates . /// /// If factory returns null, the default comparison context will be used. /// diff --git a/ObjectsComparer/ObjectsComparer/Context/ComparisonContextProvider.cs b/ObjectsComparer/ObjectsComparer/Context/ComparisonContextProvider.cs index df9c981..556dd1d 100644 --- a/ObjectsComparer/ObjectsComparer/Context/ComparisonContextProvider.cs +++ b/ObjectsComparer/ObjectsComparer/Context/ComparisonContextProvider.cs @@ -15,12 +15,12 @@ internal static IComparisonContext CreateImplicitRootContext(ComparisonSettings /// /// Context without ancestor and without member. /// - public static IComparisonContext CreateRootContext(ComparisonSettings comparisonSettings) - { - _ = comparisonSettings ?? throw new ArgumentNullException(nameof(comparisonSettings)); + //public static IComparisonContext CreateRootContext(ComparisonSettings comparisonSettings) + //{ + // _ = comparisonSettings ?? throw new ArgumentNullException(nameof(comparisonSettings)); - return CreateContext(comparisonSettings, new CreateComparisonContextArgs()); - } + // return CreateContext(comparisonSettings, new CreateComparisonContextArgs()); + //} /// /// Context with ancestor but without a member. @@ -68,7 +68,7 @@ internal static IComparisonContext CreateMemberOrMemberNameContext(ComparisonSet return CreateListElementContext(comparisonSettings, ancestor); } - return CreateRootContext(comparisonSettings); + return CreateImplicitRootContext(comparisonSettings); } static IComparisonContext CreateContext(ComparisonSettings comparisonSettings, CreateComparisonContextArgs createContextArgs) diff --git a/ObjectsComparer/ObjectsComparer/Context/IComparisonContext.cs b/ObjectsComparer/ObjectsComparer/Context/IComparisonContext.cs index 16a914d..bcb6aa8 100644 --- a/ObjectsComparer/ObjectsComparer/Context/IComparisonContext.cs +++ b/ObjectsComparer/ObjectsComparer/Context/IComparisonContext.cs @@ -36,8 +36,8 @@ public interface IComparisonContext /// /// Adds descendant to the context. /// - /// - void AddDescendant(IComparisonContext comparisonContext); + /// + void AddDescendant(IComparisonContext descendant); /// /// Adds the difference to the context. diff --git a/ObjectsComparer/ObjectsComparer/Context/IContextableComparer.cs b/ObjectsComparer/ObjectsComparer/Context/IContextableComparer.cs index 220c7d7..648bb2d 100644 --- a/ObjectsComparer/ObjectsComparer/Context/IContextableComparer.cs +++ b/ObjectsComparer/ObjectsComparer/Context/IContextableComparer.cs @@ -4,7 +4,7 @@ namespace ObjectsComparer { /// - /// Comparer accepting . + /// Comparer accepting . /// public interface IContextableComparer { diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparerBase.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparerBase.cs index 913c4ff..be10f60 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparerBase.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparerBase.cs @@ -145,7 +145,8 @@ protected virtual IEnumerable CalculateDifferencesByIndex(IList CalculateDifferences(Type type, object obj1, object obj2) { - return CalculateDifferences(type, obj1, obj2, new ComparisonContext()); + return CalculateDifferences(type, obj1, obj2, ComparisonContextProvider.CreateImplicitRootContext(Settings)); } public IEnumerable CalculateDifferences(T obj1, T obj2, IComparisonContext comparisonContext) From 6fb1d12ec578377f3a8f98c5c22160c5a67df618 Mon Sep 17 00:00:00 2001 From: nemec Date: Tue, 25 Jan 2022 17:29:37 +0100 Subject: [PATCH 098/181] Replace ComparisonContext with IComparisonContext, --- ObjectsComparer/ObjectsComparer/BaseComparer.cs | 2 +- .../ObjectsComparer/Context/ComparisonContext.cs | 2 +- .../ObjectsComparer/Context/IComparerExtensions.cs | 8 ++++---- .../ObjectsComparer/Context/IContextableComparer~1.cs | 2 +- .../CustomComparers/EnumerablesComparerBase.cs | 3 ++- .../CustomComparers/GenericEnumerablesComparer.cs | 2 +- .../ObjectsComparer/CustomComparers/HashSetsComparer.cs | 2 +- .../ObjectsComparer/CustomComparers/HashSetsComparer~1.cs | 2 +- .../CustomComparers/MultidimensionalArraysComparer.cs | 2 +- .../ObjectsComparer/CustomComparers/TypesComparer.cs | 2 +- .../Exceptions/ElementKeyNotFoundException.cs | 2 +- 11 files changed, 15 insertions(+), 14 deletions(-) diff --git a/ObjectsComparer/ObjectsComparer/BaseComparer.cs b/ObjectsComparer/ObjectsComparer/BaseComparer.cs index c125826..454b5f4 100644 --- a/ObjectsComparer/ObjectsComparer/BaseComparer.cs +++ b/ObjectsComparer/ObjectsComparer/BaseComparer.cs @@ -185,7 +185,7 @@ public void IgnoreMember(Func filter) } /// - /// Adds an to the end of the 's . + /// Adds an to the end of the 's . /// /// The argument. protected virtual Difference AddDifferenceToComparisonContext(Difference difference, IComparisonContext comparisonContext) diff --git a/ObjectsComparer/ObjectsComparer/Context/ComparisonContext.cs b/ObjectsComparer/ObjectsComparer/Context/ComparisonContext.cs index dc43fe7..cb9b821 100644 --- a/ObjectsComparer/ObjectsComparer/Context/ComparisonContext.cs +++ b/ObjectsComparer/ObjectsComparer/Context/ComparisonContext.cs @@ -11,7 +11,7 @@ namespace ObjectsComparer /// public sealed class ComparisonContext : ComparisonContextBase { - private ComparisonContext(IComparisonContextMember member = null, IComparisonContext ancestor = null) : base(member, ancestor) + public ComparisonContext(IComparisonContextMember member = null, IComparisonContext ancestor = null) : base(member, ancestor) { } diff --git a/ObjectsComparer/ObjectsComparer/Context/IComparerExtensions.cs b/ObjectsComparer/ObjectsComparer/Context/IComparerExtensions.cs index 8b51f95..b0f20f3 100644 --- a/ObjectsComparer/ObjectsComparer/Context/IComparerExtensions.cs +++ b/ObjectsComparer/ObjectsComparer/Context/IComparerExtensions.cs @@ -5,19 +5,19 @@ namespace ObjectsComparer { /// - /// Extends interface with an overloaded operation CalculateDifferences, that accepts parameter. + /// Extends interface . /// public static class IComparerExtensions { /// /// Calculates list of differences between objects. Accepts comparison context. - /// At the beginning of the comparison you can create instance using the operation and pass it as a parameter. - /// For more info about comparison context see class. + /// At the beginning of the comparison you can create instance using the operation and pass it as a parameter. + /// For more info about comparison context see class. /// /// Type. /// Object 1. /// Object 2. - /// Current comparison context. For more info see class. + /// Current comparison context. For more info see class. /// List of differences between objects. /// If does not implement . public static IEnumerable CalculateDifferences(this IComparer comparer, Type type, object obj1, object obj2, IComparisonContext comparisonContext) diff --git a/ObjectsComparer/ObjectsComparer/Context/IContextableComparer~1.cs b/ObjectsComparer/ObjectsComparer/Context/IContextableComparer~1.cs index faffee7..eddfa04 100644 --- a/ObjectsComparer/ObjectsComparer/Context/IContextableComparer~1.cs +++ b/ObjectsComparer/ObjectsComparer/Context/IContextableComparer~1.cs @@ -4,7 +4,7 @@ namespace ObjectsComparer { /// - /// Comparer accepting . + /// Comparer accepting . /// public interface IContextableComparer { diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparerBase.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparerBase.cs index be10f60..ecaed8f 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparerBase.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparerBase.cs @@ -197,7 +197,8 @@ protected virtual IEnumerable CalculateDifferencesByIndex(IList array1Count ? valueComparer.ToString(largerArray[i]) : string.Empty, differenceType: array1Count > array2Count ? DifferenceTypes.MissedElementInSecondObject : DifferenceTypes.MissedElementInFirstObject); - yield return AddDifferenceToComparisonContext(difference, new ComparisonContext(new ComparisonContextMember(), listComparisonContext)); + //yield return AddDifferenceToComparisonContext(difference, new ComparisonContext(new ComparisonContextMember(), listComparisonContext)); + yield return AddDifferenceToComparisonContext(difference, ComparisonContextProvider.CreateListElementContext(Settings, listComparisonContext)); } } } diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/GenericEnumerablesComparer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/GenericEnumerablesComparer.cs index 99a302f..f7dfa20 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/GenericEnumerablesComparer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/GenericEnumerablesComparer.cs @@ -17,7 +17,7 @@ public GenericEnumerablesComparer(ComparisonSettings settings, BaseComparer pare public override IEnumerable CalculateDifferences(Type type, object obj1, object obj2) { - return CalculateDifferences(type, obj1, obj2, new ComparisonContext()); + return CalculateDifferences(type, obj1, obj2, ComparisonContextProvider.CreateImplicitRootContext(Settings)); } public override IEnumerable CalculateDifferences(Type type, object obj1, object obj2, IComparisonContext comparisonContext) diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/HashSetsComparer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/HashSetsComparer.cs index 8a03ce3..f011ed7 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/HashSetsComparer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/HashSetsComparer.cs @@ -15,7 +15,7 @@ public HashSetsComparer(ComparisonSettings settings, BaseComparer parentComparer public override IEnumerable CalculateDifferences(Type type, object obj1, object obj2) { - return CalculateDifferences(type, obj1, obj2, new ComparisonContext()); + return CalculateDifferences(type, obj1, obj2, ComparisonContextProvider.CreateImplicitRootContext(Settings)); } public override IEnumerable CalculateDifferences(Type type, object obj1, object obj2, IComparisonContext comparisonContext) diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/HashSetsComparer~1.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/HashSetsComparer~1.cs index a989dd2..f415964 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/HashSetsComparer~1.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/HashSetsComparer~1.cs @@ -19,7 +19,7 @@ public IEnumerable CalculateDifferences(T obj1, T obj2, IComparisonC public override IEnumerable CalculateDifferences(Type type, object obj1, object obj2) { - return CalculateDifferences(type, obj1, obj2, new ComparisonContext()); + return CalculateDifferences(type, obj1, obj2, ComparisonContextProvider.CreateImplicitRootContext(Settings)); } public IEnumerable CalculateDifferences(Type type, object obj1, object obj2, IComparisonContext comparisonContext) diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/MultidimensionalArraysComparer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/MultidimensionalArraysComparer.cs index dd09ca3..5aff3e2 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/MultidimensionalArraysComparer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/MultidimensionalArraysComparer.cs @@ -15,7 +15,7 @@ public MultidimensionalArraysComparer(ComparisonSettings settings, BaseComparer public override IEnumerable CalculateDifferences(Type type, object obj1, object obj2) { - return CalculateDifferences(type, obj1, obj2, new ComparisonContext()); + return CalculateDifferences(type, obj1, obj2, ComparisonContextProvider.CreateImplicitRootContext(Settings)); } public override IEnumerable CalculateDifferences(Type type, object obj1, object obj2, IComparisonContext comparisonContext) diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/TypesComparer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/TypesComparer.cs index 40bafa3..ca40342 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/TypesComparer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/TypesComparer.cs @@ -15,7 +15,7 @@ public TypesComparer(ComparisonSettings settings, BaseComparer parentComparer, public override IEnumerable CalculateDifferences(Type type, object obj1, object obj2) { - return CalculateDifferences(type, obj1, obj2, new ComparisonContext()); + return CalculateDifferences(type, obj1, obj2, ComparisonContextProvider.CreateImplicitRootContext(Settings)); } public IEnumerable CalculateDifferences(Type type, object obj1, object obj2, IComparisonContext comparisonContext) diff --git a/ObjectsComparer/ObjectsComparer/Exceptions/ElementKeyNotFoundException.cs b/ObjectsComparer/ObjectsComparer/Exceptions/ElementKeyNotFoundException.cs index a059219..a9b8f34 100644 --- a/ObjectsComparer/ObjectsComparer/Exceptions/ElementKeyNotFoundException.cs +++ b/ObjectsComparer/ObjectsComparer/Exceptions/ElementKeyNotFoundException.cs @@ -28,7 +28,7 @@ internal ElementKeyNotFoundException(object keylessElement, IComparisonContext k public object KeylessElement { get; } /// - /// The current in which the exception occurred. + /// The current in which the exception occurred. /// public IComparisonContext KeylessElementComparisonContext { get; } } From 6e1f87f669d3f9f90d092688358d27a6b7d971e1 Mon Sep 17 00:00:00 2001 From: nemec Date: Thu, 27 Jan 2022 22:19:48 +0100 Subject: [PATCH 099/181] Add HasComparisonContextImplicitRoot method. --- .../Comparer_GenericEnumerableTests.cs | 8 ++++ .../Context/ComparisonContextBase.cs | 4 +- .../Context/IComparerExtensions.cs | 42 +++++++++++++++---- 3 files changed, 43 insertions(+), 11 deletions(-) diff --git a/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs b/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs index cf78208..a2fc2d8 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs @@ -310,6 +310,14 @@ public void ClassArrayInequalityCount_CompareByKey_DoesNotThrow_ElementKeyNotFou .CompareUnequalLists(true) .CompareElementsByKey(keyOptions => keyOptions.ThrowKeyNotFound(false))); + settings.ConfigureListComparison((ctx, options) => + { + if (ctx.Member.Name == "TrvaleAdresy") + { + options.CompareElementsByKey(); + } + }); + var comparer = new Comparer(settings); List differences = null; diff --git a/ObjectsComparer/ObjectsComparer/Context/ComparisonContextBase.cs b/ObjectsComparer/ObjectsComparer/Context/ComparisonContextBase.cs index 0018c41..02439b3 100644 --- a/ObjectsComparer/ObjectsComparer/Context/ComparisonContextBase.cs +++ b/ObjectsComparer/ObjectsComparer/Context/ComparisonContextBase.cs @@ -17,8 +17,8 @@ public abstract class ComparisonContextBase : IComparisonContext public ComparisonContextBase(IComparisonContextMember member = null, IComparisonContext ancestor = null) { - ancestor.AddDescendant(this); - Member = member ?? throw new ArgumentNullException(nameof(member)); + ancestor?.AddDescendant(this); + Member = member; } public IComparisonContext Ancestor { get; set; } diff --git a/ObjectsComparer/ObjectsComparer/Context/IComparerExtensions.cs b/ObjectsComparer/ObjectsComparer/Context/IComparerExtensions.cs index b0f20f3..5c4f795 100644 --- a/ObjectsComparer/ObjectsComparer/Context/IComparerExtensions.cs +++ b/ObjectsComparer/ObjectsComparer/Context/IComparerExtensions.cs @@ -11,14 +11,7 @@ public static class IComparerExtensions { /// /// Calculates list of differences between objects. Accepts comparison context. - /// At the beginning of the comparison you can create instance using the operation and pass it as a parameter. - /// For more info about comparison context see class. /// - /// Type. - /// Object 1. - /// Object 2. - /// Current comparison context. For more info see class. - /// List of differences between objects. /// If does not implement . public static IEnumerable CalculateDifferences(this IComparer comparer, Type type, object obj1, object obj2, IComparisonContext comparisonContext) { @@ -42,8 +35,12 @@ public static IEnumerable CalculateDifferences(this IComparer compar return contextableComparer.CalculateDifferences(type, obj1, obj2, comparisonContext); } + if (HasComparisonContextImplicitRoot(comparisonContext)) + { + return comparer.CalculateDifferences(type, obj1, obj2); + } + throw new ContextableComparerNotImplementedException(comparer); - //return comparer.CalculateDifferences(type, obj1, obj2); } public static IEnumerable CalculateDifferences(this IComparer comparer, T obj1, T obj2, IComparisonContext comparisonContext) @@ -63,8 +60,35 @@ public static IEnumerable CalculateDifferences(this IComparer return contextableComparer.CalculateDifferences(obj1, obj2, comparisonContext); } + if (HasComparisonContextImplicitRoot(comparisonContext)) + { + return comparer.CalculateDifferences(obj1, obj2); + } + throw new ContextableComparerNotImplementedException(comparer); - //return comparer.CalculateDifferences(obj1, obj2); + } + + static bool HasComparisonContextImplicitRoot(IComparisonContext comparisonContext) + { + if (comparisonContext is null) + { + throw new ArgumentNullException(nameof(comparisonContext)); + } + + do + { + if (comparisonContext.Ancestor == null && comparisonContext is NullComparisonContext) + { + return true; + } + else + { + comparisonContext = comparisonContext.Ancestor; + } + + } while (comparisonContext != null); + + return false; } } } \ No newline at end of file From 167250ecb1b8965d8098299a0415584ebd98624f Mon Sep 17 00:00:00 2001 From: "ASD\\nemec" Date: Mon, 31 Jan 2022 13:16:43 +0100 Subject: [PATCH 100/181] Add ContextableComparerNotImplementedException class. --- .../Context/ComparisonContextBase.cs | 19 ++++++++++++++++++- .../Context/IComparerExtensions.cs | 8 ++++---- ...textableComparerNotImplementedException.cs | 10 ++++++++++ 3 files changed, 32 insertions(+), 5 deletions(-) diff --git a/ObjectsComparer/ObjectsComparer/Context/ComparisonContextBase.cs b/ObjectsComparer/ObjectsComparer/Context/ComparisonContextBase.cs index 02439b3..6d84368 100644 --- a/ObjectsComparer/ObjectsComparer/Context/ComparisonContextBase.cs +++ b/ObjectsComparer/ObjectsComparer/Context/ComparisonContextBase.cs @@ -21,7 +21,24 @@ public ComparisonContextBase(IComparisonContextMember member = null, IComparison Member = member; } - public IComparisonContext Ancestor { get; set; } + IComparisonContext _ancestor; + + public virtual IComparisonContext Ancestor + { + get + { + return _ancestor; + } + set + { + if (_ancestor != null) + { + throw new InvalidOperationException("The ancestor already exists."); + } + + _ancestor = value; + } + } public IEnumerable Descendants => _descendants.AsReadOnly(); diff --git a/ObjectsComparer/ObjectsComparer/Context/IComparerExtensions.cs b/ObjectsComparer/ObjectsComparer/Context/IComparerExtensions.cs index 5c4f795..3a89161 100644 --- a/ObjectsComparer/ObjectsComparer/Context/IComparerExtensions.cs +++ b/ObjectsComparer/ObjectsComparer/Context/IComparerExtensions.cs @@ -40,6 +40,7 @@ public static IEnumerable CalculateDifferences(this IComparer compar return comparer.CalculateDifferences(type, obj1, obj2); } + //The caller passed on the root context, but did not provide an contextable comparer. The component guarantees that all its own comparers are contextable. throw new ContextableComparerNotImplementedException(comparer); } @@ -65,6 +66,7 @@ public static IEnumerable CalculateDifferences(this IComparer return comparer.CalculateDifferences(obj1, obj2); } + //The caller passed on the root context, but did not provide an contextable comparer. The component guarantees that all its own comparers are contextable. throw new ContextableComparerNotImplementedException(comparer); } @@ -81,10 +83,8 @@ static bool HasComparisonContextImplicitRoot(IComparisonContext comparisonContex { return true; } - else - { - comparisonContext = comparisonContext.Ancestor; - } + + comparisonContext = comparisonContext.Ancestor; } while (comparisonContext != null); diff --git a/ObjectsComparer/ObjectsComparer/Exceptions/ContextableComparerNotImplementedException.cs b/ObjectsComparer/ObjectsComparer/Exceptions/ContextableComparerNotImplementedException.cs index 01c224f..f3b48ef 100644 --- a/ObjectsComparer/ObjectsComparer/Exceptions/ContextableComparerNotImplementedException.cs +++ b/ObjectsComparer/ObjectsComparer/Exceptions/ContextableComparerNotImplementedException.cs @@ -11,4 +11,14 @@ internal ContextableComparerNotImplementedException(object comparer) : base(mess public object Comparer { get; } } + + public class ContextableComparerNotImplementedException : NotImplementedException + { + internal ContextableComparerNotImplementedException(IComparer comparer) : base(message: $"The comparer argument of type {comparer?.GetType()?.FullName} does not implement IContextableComparer interface.") + { + Comparer = comparer ?? throw new ArgumentNullException(nameof(comparer)); + } + + public IComparer Comparer { get; } + } } From ea3fe6bb35d39ce6a178e8db8f04b5a0912cc31b Mon Sep 17 00:00:00 2001 From: "ASD\\nemec" Date: Tue, 1 Feb 2022 16:08:11 +0100 Subject: [PATCH 101/181] Edit ComparisonSettings.ConfigureComparisonContext operation. Refactor ComparisonContextProvider. --- .../Example4/Example4Tests.cs | 44 +++++++++ .../Comparer_GenericEnumerableTests.cs | 2 +- .../ComparisonSettingsTests.cs | 7 +- .../ObjectsComparer/ComparisonSettings.cs | 6 +- .../Context/ComparisonContextMember.cs | 39 +++++--- .../Context/ComparisonContextOptions.cs | 18 ++-- .../Context/ComparisonContextProvider.cs | 91 ++++++++----------- .../Context/IComparisonContextMember.cs | 10 +- 8 files changed, 131 insertions(+), 86 deletions(-) diff --git a/ObjectsComparer/ObjectsComparer.Examples/Example4/Example4Tests.cs b/ObjectsComparer/ObjectsComparer.Examples/Example4/Example4Tests.cs index 0d7125e..3f7b07d 100644 --- a/ObjectsComparer/ObjectsComparer.Examples/Example4/Example4Tests.cs +++ b/ObjectsComparer/ObjectsComparer.Examples/Example4/Example4Tests.cs @@ -65,6 +65,50 @@ public void List_Of_Equal_Sizes_But_Is_Inequality() Assert.IsTrue(differences.Any(d => d.MemberPath == "Items[Id=1].Instruction" && d.Value1 == "Instruction 1" && d.Value2 == "Instruction One")); } + [Test] + public void List_Of_Equal_Sizes_But_Is_Inequality_Test_Ctx() + { + var formula1 = new Formula + { + Id = 1, + Name = "Formula 1", + Items = new List + { + new FormulaItem + { + Id = 1, + Delay = 60, + Name = "Item 1", + Instruction = "Instruction 1" + } + } + }; + + var formula2 = new Formula + { + Id = 1, + Name = "Formula 1", + Items = new List + { + new FormulaItem + { + Id = 1, + Delay = 80, + Name = "Item One", + Instruction = "Instruction One" + } + } + }; + + var ctx = new ComparisonContext(); + var differences = _comparer.CalculateDifferences(formula1, formula2, ctx).ToArray(); + + Assert.AreEqual(3, differences.Count()); + Assert.IsTrue(differences.Any(d => d.MemberPath == "Items[Id=1].Delay" && d.Value1 == "60" && d.Value2 == "80")); + Assert.IsTrue(differences.Any(d => d.MemberPath == "Items[Id=1].Name" && d.Value1 == "Item 1" && d.Value2 == "Item One")); + Assert.IsTrue(differences.Any(d => d.MemberPath == "Items[Id=1].Instruction" && d.Value1 == "Instruction 1" && d.Value2 == "Instruction One")); + } + [Test] public void List_Of_Different_Sizes_But_Is_Inequality() { diff --git a/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs b/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs index a2fc2d8..d6546bf 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs @@ -312,7 +312,7 @@ public void ClassArrayInequalityCount_CompareByKey_DoesNotThrow_ElementKeyNotFou settings.ConfigureListComparison((ctx, options) => { - if (ctx.Member.Name == "TrvaleAdresy") + if (ctx.Member.MemberName == "TrvaleAdresy") { options.CompareElementsByKey(); } diff --git a/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs b/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs index 748f675..012a753 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs @@ -5,6 +5,7 @@ using NUnit.Framework; using ObjectsComparer.Tests.TestClasses; using ObjectsComparer.Tests.Utils; +using System.Reflection; namespace ObjectsComparer.Tests { @@ -319,12 +320,12 @@ public static void LambdaTest() [Test] public void TestListComparisonContextInfo() { - var ancestorMember = new ComparisonContextMember("Property1"); + var ancestorMember = ComparisonContextMember.Create(memberName: "Property1"); var ancestorCtx = new ComparisonContext(ancestorMember); - var member = new ComparisonContextMember("Property2"); + var member = ComparisonContextMember.Create(memberName: "Property2"); var ctx = new ComparisonContext(member, ancestorCtx); var listCtxInfo = new ListComparisonContextInfo(ctx); - Assert.AreEqual("Property1.Property2", $"{listCtxInfo.Ancestor.Member.Name}.{listCtxInfo.Member.Name}"); + Assert.AreEqual("Property1.Property2", $"{listCtxInfo.Ancestor.Member.MemberName}.{listCtxInfo.Member.MemberName}"); } } diff --git a/ObjectsComparer/ObjectsComparer/ComparisonSettings.cs b/ObjectsComparer/ObjectsComparer/ComparisonSettings.cs index 294dc7c..142b7e5 100644 --- a/ObjectsComparer/ObjectsComparer/ComparisonSettings.cs +++ b/ObjectsComparer/ObjectsComparer/ComparisonSettings.cs @@ -117,11 +117,11 @@ public void ConfigureListComparison(bool compareElementsByKey = false, bool comp }); } - internal Action ComparisonContextOptionsAction { get; private set; } + internal Action ComparisonContextOptionsAction { get; private set; } - public void ConfigureComparisonContext(Action comparisonContextOptions) + public void ConfigureComparisonContext(Action options) { - ComparisonContextOptionsAction = comparisonContextOptions ?? throw new ArgumentNullException(nameof(comparisonContextOptions)); + ComparisonContextOptionsAction = options ?? throw new ArgumentNullException(nameof(options)); } } } diff --git a/ObjectsComparer/ObjectsComparer/Context/ComparisonContextMember.cs b/ObjectsComparer/ObjectsComparer/Context/ComparisonContextMember.cs index 5fe388f..790cebe 100644 --- a/ObjectsComparer/ObjectsComparer/Context/ComparisonContextMember.cs +++ b/ObjectsComparer/ObjectsComparer/Context/ComparisonContextMember.cs @@ -3,31 +3,40 @@ namespace ObjectsComparer { - internal class ComparisonContextMember : IComparisonContextMember + public class ComparisonContextMember : IComparisonContextMember { - readonly string _name; - - public ComparisonContextMember() + ComparisonContextMember() { } - public ComparisonContextMember(string name) + public static ComparisonContextMember Create() { - if (string.IsNullOrWhiteSpace(name)) - { - throw new System.ArgumentException($"'{nameof(name)}' cannot be null or whitespace.", nameof(name)); - } - - _name = name; + return new ComparisonContextMember(); } - public ComparisonContextMember(MemberInfo info) + public static ComparisonContextMember Create(MemberInfo member) + { + return new ComparisonContextMember { Member = member ?? throw new ArgumentNullException(nameof(member)) }; + } + public static ComparisonContextMember Create(string memberName) { - Info = info ?? throw new ArgumentNullException(nameof(info)); + return new ComparisonContextMember { MemberName = memberName ?? throw new ArgumentNullException(nameof(memberName)) }; } - public string Name => _name ?? Info?.Name; + string _memberName; + + public string MemberName + { + get + { + return Member?.Name ?? _memberName; + } + private set + { + _memberName = value; + } + } - public MemberInfo Info { get; } + public MemberInfo Member { get; private set; } } } \ No newline at end of file diff --git a/ObjectsComparer/ObjectsComparer/Context/ComparisonContextOptions.cs b/ObjectsComparer/ObjectsComparer/Context/ComparisonContextOptions.cs index b735c83..f7779cb 100644 --- a/ObjectsComparer/ObjectsComparer/Context/ComparisonContextOptions.cs +++ b/ObjectsComparer/ObjectsComparer/Context/ComparisonContextOptions.cs @@ -14,16 +14,22 @@ internal static ComparisonContextOptions Default() return new ComparisonContextOptions(); } - internal Func ComparisonContextFactory { get; private set; } + internal Func ComparisonContextFactory { get; private set; } + + internal Func ComparisonContextMemberFactory { get; private set; } + + + public void UseComparisonContextFactory(Func factory) + { + ComparisonContextFactory = factory ?? throw new ArgumentNullException(nameof(factory)); + } /// - /// Creates . /// - /// If factory returns null, the default comparison context will be used. - /// - public void UseComparisonContextFactory(Func factory) + /// First parameter type: Default member. + public void UseComparisonContextMemberFactory(Func factory) { - ComparisonContextFactory = factory ?? throw new ArgumentNullException(nameof(factory)); + ComparisonContextMemberFactory = factory ?? throw new ArgumentNullException(nameof(factory)); } } } diff --git a/ObjectsComparer/ObjectsComparer/Context/ComparisonContextProvider.cs b/ObjectsComparer/ObjectsComparer/Context/ComparisonContextProvider.cs index 556dd1d..f0d3508 100644 --- a/ObjectsComparer/ObjectsComparer/Context/ComparisonContextProvider.cs +++ b/ObjectsComparer/ObjectsComparer/Context/ComparisonContextProvider.cs @@ -9,25 +9,18 @@ internal static IComparisonContext CreateImplicitRootContext(ComparisonSettings { _ = comparisonSettings ?? throw new ArgumentNullException(nameof(comparisonSettings)); //For the future. - return new NullComparisonContext(); + return new NullComparisonContext(ComparisonContextMember.Create()); } - /// - /// Context without ancestor and without member. - /// - //public static IComparisonContext CreateRootContext(ComparisonSettings comparisonSettings) - //{ - // _ = comparisonSettings ?? throw new ArgumentNullException(nameof(comparisonSettings)); - - // return CreateContext(comparisonSettings, new CreateComparisonContextArgs()); - //} - /// /// Context with ancestor but without a member. /// public static IComparisonContext CreateListElementContext(ComparisonSettings comparisonSettings, IComparisonContext ancestor) { - return CreateContext(comparisonSettings, new CreateComparisonContextArgs(ancestor)); + _ = comparisonSettings ?? throw new ArgumentNullException(nameof(comparisonSettings)); + _ = ancestor ?? throw new ArgumentNullException(nameof(ancestor)); + + return CreateContext(comparisonSettings, ComparisonContextMember.Create(), ancestor); } /// @@ -35,7 +28,11 @@ public static IComparisonContext CreateListElementContext(ComparisonSettings com /// public static IComparisonContext CreateMemberContext(ComparisonSettings comparisonSettings, IComparisonContext ancestor, MemberInfo member) { - return CreateContext(comparisonSettings, new CreateComparisonContextArgs(ancestor, member)); + _ = comparisonSettings ?? throw new ArgumentNullException(nameof(comparisonSettings)); + _ = ancestor ?? throw new ArgumentNullException(nameof(ancestor)); + _ = member ?? throw new ArgumentNullException(nameof(member)); + + return CreateContext(comparisonSettings, ComparisonContextMember.Create(member), ancestor); } /// @@ -43,7 +40,11 @@ public static IComparisonContext CreateMemberContext(ComparisonSettings comparis /// public static IComparisonContext CreateMemberNameContext(ComparisonSettings comparisonSettings, IComparisonContext ancestor, string memberName) { - return CreateContext(comparisonSettings, new CreateComparisonContextArgs(ancestor, memberName)); + _ = comparisonSettings ?? throw new ArgumentNullException(nameof(comparisonSettings)); + _ = ancestor ?? throw new ArgumentNullException(nameof(ancestor)); + _ = memberName ?? throw new ArgumentNullException(nameof(memberName)); + + return CreateContext(comparisonSettings, ComparisonContextMember.Create(memberName), ancestor); } /// @@ -52,6 +53,7 @@ public static IComparisonContext CreateMemberNameContext(ComparisonSettings comp internal static IComparisonContext CreateMemberOrMemberNameContext(ComparisonSettings comparisonSettings, IComparisonContext ancestor, MemberInfo member, string memberName) { _ = comparisonSettings ?? throw new ArgumentNullException(nameof(comparisonSettings)); + _ = ancestor ?? throw new ArgumentNullException(nameof(ancestor)); if (member != null) { @@ -63,63 +65,46 @@ internal static IComparisonContext CreateMemberOrMemberNameContext(ComparisonSet return CreateMemberNameContext(comparisonSettings, ancestor, memberName); } - if (ancestor != null) - { - return CreateListElementContext(comparisonSettings, ancestor); - } - - return CreateImplicitRootContext(comparisonSettings); + throw new ArgumentException(); } - static IComparisonContext CreateContext(ComparisonSettings comparisonSettings, CreateComparisonContextArgs createContextArgs) + static IComparisonContext CreateContext(ComparisonSettings comparisonSettings, IComparisonContextMember comparisonContextMember, IComparisonContext ancestor) { _ = comparisonSettings ?? throw new ArgumentNullException(nameof(comparisonSettings)); - _ = createContextArgs ?? throw new ArgumentNullException(nameof(createContextArgs)); + _ = comparisonContextMember ?? throw new ArgumentNullException(nameof(comparisonContextMember)); + _ = ancestor ?? throw new ArgumentNullException(nameof(ancestor)); ComparisonContextOptions options = ComparisonContextOptions.Default(); - comparisonSettings.ComparisonContextOptionsAction?.Invoke(options); + comparisonSettings.ComparisonContextOptionsAction?.Invoke(ancestor, options); - if (options.ComparisonContextFactory != null) + if (options.ComparisonContextMemberFactory != null) { - var context = options.ComparisonContextFactory(createContextArgs); - if (context != null) + var customComparisonContextMember = options.ComparisonContextMemberFactory.Invoke(comparisonContextMember); + + if (customComparisonContextMember == null) { - return context; + throw new InvalidOperationException("Comparison context member factory returned null member."); } - } - return new ComparisonContext(CreateComparisonContextMember(createContextArgs.Member, createContextArgs.MemberName), createContextArgs.Ancestor); - } + comparisonContextMember = customComparisonContextMember; + } - static bool ShouldCreateNullContext(IComparisonContext ancestor) - { - do + if (options.ComparisonContextFactory != null) { - if (ancestor is NullComparisonContext) + var customContext = options.ComparisonContextFactory(comparisonContextMember); + + if (customContext != null) { - return true; + return customContext; } - ancestor = ancestor.Ancestor; - - } while (ancestor != null); - - return false; - } - - static IComparisonContextMember CreateComparisonContextMember(MemberInfo member, string memberName) - { - if (member != null) - { - return new ComparisonContextMember(member); - } - - if (string.IsNullOrWhiteSpace(memberName)) - { - return new ComparisonContextMember(); + if (customContext == null) + { + throw new InvalidOperationException("Comparison context factory returned null context."); + } } - return new ComparisonContextMember(memberName); + return new ComparisonContext(comparisonContextMember, ancestor); } } } diff --git a/ObjectsComparer/ObjectsComparer/Context/IComparisonContextMember.cs b/ObjectsComparer/ObjectsComparer/Context/IComparisonContextMember.cs index 683948f..83e61a1 100644 --- a/ObjectsComparer/ObjectsComparer/Context/IComparisonContextMember.cs +++ b/ObjectsComparer/ObjectsComparer/Context/IComparisonContextMember.cs @@ -3,18 +3,18 @@ namespace ObjectsComparer { /// - /// Compared member in comparison process, typically the property. + /// The member being compared in the comparison process, usually a property. /// public interface IComparisonContextMember { /// - /// Compared member name. + /// Member. /// - string Name { get; } + string MemberName { get; } /// - /// Compared member. May be null for dynamic properties unknown at compile time. + /// Member. May be null for dynamic properties unknown at compile time. /// - MemberInfo Info { get; } + MemberInfo Member { get; } } } \ No newline at end of file From 1657536fe9464c4909f5f12c58dc2f912aaf2569 Mon Sep 17 00:00:00 2001 From: nemec Date: Fri, 4 Feb 2022 14:09:49 +0100 Subject: [PATCH 102/181] Edit ComparisonContextProvider (TODO). --- .../Comparer_GenericEnumerableTests.cs | 2 +- .../ComparisonContextTests.cs | 88 +++++++++++++++++++ .../ComparisonSettingsTests.cs | 2 +- ObjectsComparer/ObjectsComparer/Comparer~1.cs | 2 +- .../Context/ComparisonContextMember.cs | 10 +-- .../Context/ComparisonContextProvider.cs | 51 +++-------- .../Context/IComparisonContextMember.cs | 4 +- .../AbstractDynamicObjectsComprer.cs | 26 +++++- .../EnumerablesComparerBase.cs | 8 +- 9 files changed, 136 insertions(+), 57 deletions(-) create mode 100644 ObjectsComparer/ObjectsComparer.Tests/ComparisonContextTests.cs diff --git a/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs b/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs index d6546bf..a2fc2d8 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs @@ -312,7 +312,7 @@ public void ClassArrayInequalityCount_CompareByKey_DoesNotThrow_ElementKeyNotFou settings.ConfigureListComparison((ctx, options) => { - if (ctx.Member.MemberName == "TrvaleAdresy") + if (ctx.Member.Name == "TrvaleAdresy") { options.CompareElementsByKey(); } diff --git a/ObjectsComparer/ObjectsComparer.Tests/ComparisonContextTests.cs b/ObjectsComparer/ObjectsComparer.Tests/ComparisonContextTests.cs new file mode 100644 index 0000000..d77c6a5 --- /dev/null +++ b/ObjectsComparer/ObjectsComparer.Tests/ComparisonContextTests.cs @@ -0,0 +1,88 @@ +using System; +using System.Collections; +using System.Linq; +using System.Collections.Generic; +using NUnit.Framework; +using ObjectsComparer.Tests.TestClasses; +using ObjectsComparer.Tests.Utils; +using System.Reflection; + +namespace ObjectsComparer.Tests +{ + [TestFixture] + internal class ComparisonContextTests + { + [Test] + public void ComparisonContextMember_Member_Correct_MemberName() + { + var ctxMember = ComparisonContextMember.Create("Property1"); + Assert.AreEqual("Property1", ctxMember.Name); + Assert.AreEqual(null, ctxMember.Info); + } + + [Test] + public void ComparisonContextMember_Member_Correct_Member() + { + var memberInfo = typeof(Address).GetMember(nameof(Address.Country)).Single(); + var ctxMember = ComparisonContextMember.Create(memberInfo); + Assert.AreEqual(nameof(Address.Country), ctxMember.Info.Name); + Assert.AreEqual(nameof(Address.Country), ctxMember.Name); + } + + [Test] + public void CustomComparisonContext() + { + var settings = new ComparisonSettings(); + var rootCtx = ComparisonContextProvider.CreateRootContext(); + + settings.ConfigureComparisonContext((currentContex, options) => + { + options.UseComparisonContextFactory(ctxMember => new CustomComparisonContext(ctxMember, rootCtx)); + }); + + var ctx = ComparisonContextProvider.CreateContext(settings, rootCtx, "Property1"); + + Assert.AreEqual("Property1", ctx.Member.Name); + Assert.IsTrue(ctx.GetType() == typeof(CustomComparisonContext)); + Assert.IsTrue(ctx.Ancestor == rootCtx); + } + + [Test] + public void CustomComparisonContextMember() + { + var settings = new ComparisonSettings(); + var rootCtx = ComparisonContextProvider.CreateRootContext(); + + settings.ConfigureComparisonContext((currentContex, options) => + { + options.UseComparisonContextMemberFactory(defaultMember => new CustomComparisonContextMember(defaultMember.Name)); + }); + + var ctx = ComparisonContextProvider.CreateContext(settings, rootCtx, "Property1"); + + Assert.AreEqual("Property1", ctx.Member.Name); + Assert.AreEqual(null, ctx.Member.Info); + Assert.IsTrue(ctx.Member.GetType() == typeof(CustomComparisonContextMember)); + Assert.IsTrue(ctx.Ancestor == rootCtx); + } + } + + class CustomComparisonContext : ComparisonContextBase + { + public CustomComparisonContext(IComparisonContextMember member = null, IComparisonContext ancestor = null) : base(member, ancestor) + { + + } + } + + class CustomComparisonContextMember : IComparisonContextMember + { + public CustomComparisonContextMember(string memberName) + { + Name = memberName; + } + public MemberInfo Info => null; + + public string Name { get; } + } +} diff --git a/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs b/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs index 012a753..799c767 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs @@ -325,7 +325,7 @@ public void TestListComparisonContextInfo() var member = ComparisonContextMember.Create(memberName: "Property2"); var ctx = new ComparisonContext(member, ancestorCtx); var listCtxInfo = new ListComparisonContextInfo(ctx); - Assert.AreEqual("Property1.Property2", $"{listCtxInfo.Ancestor.Member.MemberName}.{listCtxInfo.Member.MemberName}"); + Assert.AreEqual("Property1.Property2", $"{listCtxInfo.Ancestor.Member.Name}.{listCtxInfo.Member.Name}"); } } diff --git a/ObjectsComparer/ObjectsComparer/Comparer~1.cs b/ObjectsComparer/ObjectsComparer/Comparer~1.cs index b74632d..555260b 100644 --- a/ObjectsComparer/ObjectsComparer/Comparer~1.cs +++ b/ObjectsComparer/ObjectsComparer/Comparer~1.cs @@ -124,7 +124,7 @@ IEnumerable CalculateDifferences(T obj1, T obj2, MemberInfo memberIn continue; } - var memberContext = ComparisonContextProvider.CreateMemberContext(Settings, comparisonContext, member); + var memberContext = ComparisonContextProvider.CreateContext(Settings, comparisonContext, member); //var memberContext = new ComparisonContext(new ComparisonContextMember(member), comparisonContext); var valueComparer = DefaultValueComparer; diff --git a/ObjectsComparer/ObjectsComparer/Context/ComparisonContextMember.cs b/ObjectsComparer/ObjectsComparer/Context/ComparisonContextMember.cs index 790cebe..8a2ba25 100644 --- a/ObjectsComparer/ObjectsComparer/Context/ComparisonContextMember.cs +++ b/ObjectsComparer/ObjectsComparer/Context/ComparisonContextMember.cs @@ -16,20 +16,20 @@ public static ComparisonContextMember Create() public static ComparisonContextMember Create(MemberInfo member) { - return new ComparisonContextMember { Member = member ?? throw new ArgumentNullException(nameof(member)) }; + return new ComparisonContextMember { Info = member ?? throw new ArgumentNullException(nameof(member)) }; } public static ComparisonContextMember Create(string memberName) { - return new ComparisonContextMember { MemberName = memberName ?? throw new ArgumentNullException(nameof(memberName)) }; + return new ComparisonContextMember { Name = memberName ?? throw new ArgumentNullException(nameof(memberName)) }; } string _memberName; - public string MemberName + public string Name { get { - return Member?.Name ?? _memberName; + return Info?.Name ?? _memberName; } private set { @@ -37,6 +37,6 @@ private set } } - public MemberInfo Member { get; private set; } + public MemberInfo Info { get; private set; } } } \ No newline at end of file diff --git a/ObjectsComparer/ObjectsComparer/Context/ComparisonContextProvider.cs b/ObjectsComparer/ObjectsComparer/Context/ComparisonContextProvider.cs index f0d3508..bd86f69 100644 --- a/ObjectsComparer/ObjectsComparer/Context/ComparisonContextProvider.cs +++ b/ObjectsComparer/ObjectsComparer/Context/ComparisonContextProvider.cs @@ -3,71 +3,44 @@ namespace ObjectsComparer { - internal static class ComparisonContextProvider + public static class ComparisonContextProvider { - internal static IComparisonContext CreateImplicitRootContext(ComparisonSettings comparisonSettings) + public static IComparisonContext CreateRootContext() { - _ = comparisonSettings ?? throw new ArgumentNullException(nameof(comparisonSettings)); //For the future. + return new ComparisonContext(ComparisonContextMember.Create()); + } + + internal static IComparisonContext CreateImplicitRootContext(ComparisonSettings comparisonSettings) + { + _ = comparisonSettings ?? throw new ArgumentNullException(nameof(comparisonSettings)); //For future use. return new NullComparisonContext(ComparisonContextMember.Create()); } /// - /// Context with ancestor but without a member. + /// Context with ancestor but without a member, e.g. list element context. /// - public static IComparisonContext CreateListElementContext(ComparisonSettings comparisonSettings, IComparisonContext ancestor) + public static IComparisonContext CreateContext(ComparisonSettings comparisonSettings, IComparisonContext ancestor) { - _ = comparisonSettings ?? throw new ArgumentNullException(nameof(comparisonSettings)); - _ = ancestor ?? throw new ArgumentNullException(nameof(ancestor)); - return CreateContext(comparisonSettings, ComparisonContextMember.Create(), ancestor); } /// /// Context with ancestor and member. /// - public static IComparisonContext CreateMemberContext(ComparisonSettings comparisonSettings, IComparisonContext ancestor, MemberInfo member) + public static IComparisonContext CreateContext(ComparisonSettings comparisonSettings, IComparisonContext ancestor, MemberInfo member) { - _ = comparisonSettings ?? throw new ArgumentNullException(nameof(comparisonSettings)); - _ = ancestor ?? throw new ArgumentNullException(nameof(ancestor)); - _ = member ?? throw new ArgumentNullException(nameof(member)); - return CreateContext(comparisonSettings, ComparisonContextMember.Create(member), ancestor); } /// /// Context with ancestor and member. /// - public static IComparisonContext CreateMemberNameContext(ComparisonSettings comparisonSettings, IComparisonContext ancestor, string memberName) + public static IComparisonContext CreateContext(ComparisonSettings comparisonSettings, IComparisonContext ancestor, string memberName) { - _ = comparisonSettings ?? throw new ArgumentNullException(nameof(comparisonSettings)); - _ = ancestor ?? throw new ArgumentNullException(nameof(ancestor)); - _ = memberName ?? throw new ArgumentNullException(nameof(memberName)); - return CreateContext(comparisonSettings, ComparisonContextMember.Create(memberName), ancestor); } - /// - /// Context with ancestor and member. The takes precedence over . - /// - internal static IComparisonContext CreateMemberOrMemberNameContext(ComparisonSettings comparisonSettings, IComparisonContext ancestor, MemberInfo member, string memberName) - { - _ = comparisonSettings ?? throw new ArgumentNullException(nameof(comparisonSettings)); - _ = ancestor ?? throw new ArgumentNullException(nameof(ancestor)); - - if (member != null) - { - return CreateMemberContext(comparisonSettings, ancestor, member); - } - - if (memberName != null) - { - return CreateMemberNameContext(comparisonSettings, ancestor, memberName); - } - - throw new ArgumentException(); - } - static IComparisonContext CreateContext(ComparisonSettings comparisonSettings, IComparisonContextMember comparisonContextMember, IComparisonContext ancestor) { _ = comparisonSettings ?? throw new ArgumentNullException(nameof(comparisonSettings)); diff --git a/ObjectsComparer/ObjectsComparer/Context/IComparisonContextMember.cs b/ObjectsComparer/ObjectsComparer/Context/IComparisonContextMember.cs index 83e61a1..5cb643a 100644 --- a/ObjectsComparer/ObjectsComparer/Context/IComparisonContextMember.cs +++ b/ObjectsComparer/ObjectsComparer/Context/IComparisonContextMember.cs @@ -10,11 +10,11 @@ public interface IComparisonContextMember /// /// Member. /// - string MemberName { get; } + string Name { get; } /// /// Member. May be null for dynamic properties unknown at compile time. /// - MemberInfo Member { get; } + MemberInfo Info { get; } } } \ No newline at end of file diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractDynamicObjectsComprer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractDynamicObjectsComprer.cs index e2179ff..5ac97be 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractDynamicObjectsComprer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractDynamicObjectsComprer.cs @@ -51,9 +51,7 @@ public virtual IEnumerable CalculateDifferences(Type type, object ob TryGetMember(castedObject1, propertyKey, out member2); } - //var keyComparisonContextMember = (member1 ?? member2) != null ? new ComparisonContextMember(member1 ?? member2) : new ComparisonContextMember(propertyKey); - //var keyComparisonContext = new ComparisonContext(keyComparisonContextMember, comparisonContext); - var keyComparisonContext = ComparisonContextProvider.CreateMemberOrMemberNameContext(Settings, comparisonContext, member1 ?? member2, propertyKey); + var keyComparisonContext = CreateContextFromMemberOrMemberName(comparisonContext, member1 ?? member2, propertyKey); var propertyType = (value1 ?? value2)?.GetType() ?? typeof(object); var customComparer = OverridesCollection.GetComparer(propertyType) ?? @@ -146,7 +144,27 @@ public virtual IEnumerable CalculateDifferences(Type type, object ob yield return failure.InsertPath(propertyKey); } } - } + } + + /// + /// Creates context with ancestor and member. The takes precedence over . + /// + IComparisonContext CreateContextFromMemberOrMemberName(IComparisonContext ancestor, MemberInfo member, string memberName) + { + _ = ancestor ?? throw new ArgumentNullException(nameof(ancestor)); + + if (member != null) + { + return ComparisonContextProvider.CreateContext(Settings, ancestor, member); + } + + if (memberName != null) + { + return ComparisonContextProvider.CreateContext(Settings, ancestor, memberName); + } + + throw new ArgumentException(); + } public abstract bool IsMatch(Type type, object obj1, object obj2); diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparerBase.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparerBase.cs index ecaed8f..c43e588 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparerBase.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparerBase.cs @@ -45,7 +45,7 @@ protected virtual IEnumerable CalculateDifferencesByKey(IList { var element1 = array1[element1Index]; //var elementComparisonContext = new ComparisonContext(new ComparisonContextMember(), listComparisonContext); - var elementComparisonContext = ComparisonContextProvider.CreateListElementContext(Settings, listComparisonContext); + var elementComparisonContext = ComparisonContextProvider.CreateContext(Settings, listComparisonContext); if (element1 == null) { @@ -95,7 +95,7 @@ protected virtual IEnumerable CalculateDifferencesByKey(IList { var element2 = array2[element2Index]; //var elementComparisonContext = new ComparisonContext(new ComparisonContextMember(), listComparisonContext); - var elementComparisonContext = ComparisonContextProvider.CreateListElementContext(Settings, listComparisonContext); + var elementComparisonContext = ComparisonContextProvider.CreateContext(Settings, listComparisonContext); if (element2 == null) { @@ -146,7 +146,7 @@ protected virtual IEnumerable CalculateDifferencesByIndex(IList CalculateDifferencesByIndex(IList array2Count ? DifferenceTypes.MissedElementInSecondObject : DifferenceTypes.MissedElementInFirstObject); //yield return AddDifferenceToComparisonContext(difference, new ComparisonContext(new ComparisonContextMember(), listComparisonContext)); - yield return AddDifferenceToComparisonContext(difference, ComparisonContextProvider.CreateListElementContext(Settings, listComparisonContext)); + yield return AddDifferenceToComparisonContext(difference, ComparisonContextProvider.CreateContext(Settings, listComparisonContext)); } } } From 2dbedf2144ec9e066beaad47bbe239b433931509 Mon Sep 17 00:00:00 2001 From: nemec Date: Tue, 8 Feb 2022 17:59:33 +0100 Subject: [PATCH 103/181] Delete ListcomparisonContextInfo. Add ThrowContextableComparerNotImplemented operation. --- .../ComparisonContextTests.cs | 39 +++++++++++- .../ComparisonSettingsTests.cs | 8 +-- ObjectsComparer/ObjectsComparer/Comparer~1.cs | 1 - .../ObjectsComparer/ComparisonSettings.cs | 8 +-- .../Context/ComparisonContextInfo.cs | 9 +++ ...xtInfo.cs => ComparisonContextInfoBase.cs} | 18 +----- .../Context/ComparisonContextMember.cs | 34 ++--------- .../Context/ComparisonContextOptions.cs | 19 +++++- .../Context/ComparisonContextProvider.cs | 34 +++++------ .../Context/IComparerExtensions.cs | 59 +++++++++++++++---- .../Context/IComparisonContextMember.cs | 4 +- .../Context/IListComparisonContextInfo.cs | 6 -- .../Context/ImplicitRootComparisonContext.cs | 19 ++++++ .../Context/NullComparisonContext.cs | 19 ------ .../AbstractDynamicObjectsComprer.cs | 24 +------- .../CustomComparers/EnumerablesComparer.cs | 2 +- .../CustomComparers/EnumerablesComparer~1.cs | 2 +- ...textableComparerNotImplementedException.cs | 15 +---- 18 files changed, 165 insertions(+), 155 deletions(-) create mode 100644 ObjectsComparer/ObjectsComparer/Context/ComparisonContextInfo.cs rename ObjectsComparer/ObjectsComparer/Context/{ListComparisonContextInfo.cs => ComparisonContextInfoBase.cs} (51%) delete mode 100644 ObjectsComparer/ObjectsComparer/Context/IListComparisonContextInfo.cs create mode 100644 ObjectsComparer/ObjectsComparer/Context/ImplicitRootComparisonContext.cs delete mode 100644 ObjectsComparer/ObjectsComparer/Context/NullComparisonContext.cs diff --git a/ObjectsComparer/ObjectsComparer.Tests/ComparisonContextTests.cs b/ObjectsComparer/ObjectsComparer.Tests/ComparisonContextTests.cs index d77c6a5..25b774a 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/ComparisonContextTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/ComparisonContextTests.cs @@ -15,7 +15,7 @@ internal class ComparisonContextTests [Test] public void ComparisonContextMember_Member_Correct_MemberName() { - var ctxMember = ComparisonContextMember.Create("Property1"); + var ctxMember = new ComparisonContextMember(name: "Property1"); Assert.AreEqual("Property1", ctxMember.Name); Assert.AreEqual(null, ctxMember.Info); } @@ -24,7 +24,7 @@ public void ComparisonContextMember_Member_Correct_MemberName() public void ComparisonContextMember_Member_Correct_Member() { var memberInfo = typeof(Address).GetMember(nameof(Address.Country)).Single(); - var ctxMember = ComparisonContextMember.Create(memberInfo); + var ctxMember = new ComparisonContextMember(memberInfo, memberInfo.Name); Assert.AreEqual(nameof(Address.Country), ctxMember.Info.Name); Assert.AreEqual(nameof(Address.Country), ctxMember.Name); } @@ -65,6 +65,41 @@ public void CustomComparisonContextMember() Assert.IsTrue(ctx.Member.GetType() == typeof(CustomComparisonContextMember)); Assert.IsTrue(ctx.Ancestor == rootCtx); } + + [Test] + public void ComparisonContextException() + { + var factory = new CustomComparersFactory(); + var comparer = factory.GetObjectsComparer(); + var rootCtx = ComparisonContextProvider.CreateRootContext(); + + var diffs = comparer.CalculateDifferences("hello", "hi", rootCtx).ToArray(); + } + } + + class CustomComparersFactory : ComparersFactory + { + public override IComparer GetObjectsComparer(ComparisonSettings settings = null, BaseComparer parentComparer = null) + { + if (typeof(T) != typeof(string)) + { + return base.GetObjectsComparer(settings, parentComparer); + } + + return (IComparer)new CustomStringComparer(settings, parentComparer, this); + } + } + + class CustomStringComparer : AbstractComparer + { + public CustomStringComparer(ComparisonSettings settings, BaseComparer parentComparer, IComparersFactory factory) : base(settings, parentComparer, factory) + { + } + + public override IEnumerable CalculateDifferences(string obj1, string obj2) + { + throw new NotImplementedException(); + } } class CustomComparisonContext : ComparisonContextBase diff --git a/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs b/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs index 799c767..be004c9 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs @@ -82,7 +82,7 @@ public void CompareListElementsByKeyIsCorrectlySet() //Component side. var listComparisonOptions = ListComparisonOptions.Default(); var ctx = new ComparisonContext(); - var listComparisonContextInfo = new ListComparisonContextInfo(ctx); + var listComparisonContextInfo = new ComparisonContextInfo(ctx); settings.ListComparisonOptionsAction(listComparisonContextInfo, listComparisonOptions); var listElementComparisonByKeyOptions = ListElementComparisonByKeyOptions.Default(); listComparisonOptions.KeyOptionsAction(listElementComparisonByKeyOptions); @@ -320,11 +320,11 @@ public static void LambdaTest() [Test] public void TestListComparisonContextInfo() { - var ancestorMember = ComparisonContextMember.Create(memberName: "Property1"); + var ancestorMember = new ComparisonContextMember(name: "Property1"); var ancestorCtx = new ComparisonContext(ancestorMember); - var member = ComparisonContextMember.Create(memberName: "Property2"); + var member = new ComparisonContextMember(name: "Property2"); var ctx = new ComparisonContext(member, ancestorCtx); - var listCtxInfo = new ListComparisonContextInfo(ctx); + var listCtxInfo = new ComparisonContextInfo(ctx); Assert.AreEqual("Property1.Property2", $"{listCtxInfo.Ancestor.Member.Name}.{listCtxInfo.Member.Name}"); } } diff --git a/ObjectsComparer/ObjectsComparer/Comparer~1.cs b/ObjectsComparer/ObjectsComparer/Comparer~1.cs index 555260b..3191314 100644 --- a/ObjectsComparer/ObjectsComparer/Comparer~1.cs +++ b/ObjectsComparer/ObjectsComparer/Comparer~1.cs @@ -125,7 +125,6 @@ IEnumerable CalculateDifferences(T obj1, T obj2, MemberInfo memberIn } var memberContext = ComparisonContextProvider.CreateContext(Settings, comparisonContext, member); - //var memberContext = new ComparisonContext(new ComparisonContextMember(member), comparisonContext); var valueComparer = DefaultValueComparer; var hasCustomComparer = false; diff --git a/ObjectsComparer/ObjectsComparer/ComparisonSettings.cs b/ObjectsComparer/ObjectsComparer/ComparisonSettings.cs index 142b7e5..96b17c6 100644 --- a/ObjectsComparer/ObjectsComparer/ComparisonSettings.cs +++ b/ObjectsComparer/ObjectsComparer/ComparisonSettings.cs @@ -67,13 +67,13 @@ public T GetCustomSetting(string key = null) throw new KeyNotFoundException(); } - internal Action ListComparisonOptionsAction { get; private set; } = null; + internal Action ListComparisonOptionsAction { get; private set; } = null; /// /// Configures list comparison behavior, especially the type of the comparison. For more info, see . /// /// First parameter: Current list comparison context. - public ComparisonSettings ConfigureListComparison(Action comparisonOptions) + public ComparisonSettings ConfigureListComparison(Action comparisonOptions) { if (comparisonOptions is null) { @@ -117,9 +117,9 @@ public void ConfigureListComparison(bool compareElementsByKey = false, bool comp }); } - internal Action ComparisonContextOptionsAction { get; private set; } + internal Action ComparisonContextOptionsAction { get; private set; } - public void ConfigureComparisonContext(Action options) + public void ConfigureComparisonContext(Action options) { ComparisonContextOptionsAction = options ?? throw new ArgumentNullException(nameof(options)); } diff --git a/ObjectsComparer/ObjectsComparer/Context/ComparisonContextInfo.cs b/ObjectsComparer/ObjectsComparer/Context/ComparisonContextInfo.cs new file mode 100644 index 0000000..6c1dde1 --- /dev/null +++ b/ObjectsComparer/ObjectsComparer/Context/ComparisonContextInfo.cs @@ -0,0 +1,9 @@ +namespace ObjectsComparer +{ + internal class ComparisonContextInfo : ComparisonContextInfoBase + { + public ComparisonContextInfo(IComparisonContext comparisonContext) : base(comparisonContext) + { + } + } +} \ No newline at end of file diff --git a/ObjectsComparer/ObjectsComparer/Context/ListComparisonContextInfo.cs b/ObjectsComparer/ObjectsComparer/Context/ComparisonContextInfoBase.cs similarity index 51% rename from ObjectsComparer/ObjectsComparer/Context/ListComparisonContextInfo.cs rename to ObjectsComparer/ObjectsComparer/Context/ComparisonContextInfoBase.cs index a7a064a..dd5634f 100644 --- a/ObjectsComparer/ObjectsComparer/Context/ListComparisonContextInfo.cs +++ b/ObjectsComparer/ObjectsComparer/Context/ComparisonContextInfoBase.cs @@ -2,30 +2,16 @@ namespace ObjectsComparer { - internal class ListComparisonContextInfo : ComparisonContextInfoBase, IListComparisonContextInfo - { - public ListComparisonContextInfo(IComparisonContext comparisonContext) : base(comparisonContext) - { - } - } - - internal class ComparisonContextInfo : ComparisonContextInfoBase - { - public ComparisonContextInfo(IComparisonContext comparisonContext) : base(comparisonContext) - { - } - } - internal class ComparisonContextInfoBase : IComparisonContextInfo { readonly IComparisonContext _comparisonContext; - readonly IListComparisonContextInfo _ancestor; + readonly IComparisonContextInfo _ancestor; public ComparisonContextInfoBase(IComparisonContext comparisonContext) { _comparisonContext = comparisonContext ?? throw new ArgumentNullException(nameof(comparisonContext)); - _ancestor = _comparisonContext.Ancestor == null ? null : new ListComparisonContextInfo(_comparisonContext.Ancestor); + _ancestor = _comparisonContext.Ancestor == null ? null : new ComparisonContextInfo(_comparisonContext.Ancestor); } public IComparisonContextMember Member => _comparisonContext.Member; diff --git a/ObjectsComparer/ObjectsComparer/Context/ComparisonContextMember.cs b/ObjectsComparer/ObjectsComparer/Context/ComparisonContextMember.cs index 8a2ba25..d2f5aa2 100644 --- a/ObjectsComparer/ObjectsComparer/Context/ComparisonContextMember.cs +++ b/ObjectsComparer/ObjectsComparer/Context/ComparisonContextMember.cs @@ -5,38 +5,14 @@ namespace ObjectsComparer { public class ComparisonContextMember : IComparisonContextMember { - ComparisonContextMember() + public ComparisonContextMember(MemberInfo info = null, string name = null) { + Info = info; + Name = name; } - public static ComparisonContextMember Create() - { - return new ComparisonContextMember(); - } - - public static ComparisonContextMember Create(MemberInfo member) - { - return new ComparisonContextMember { Info = member ?? throw new ArgumentNullException(nameof(member)) }; - } - public static ComparisonContextMember Create(string memberName) - { - return new ComparisonContextMember { Name = memberName ?? throw new ArgumentNullException(nameof(memberName)) }; - } - - string _memberName; - - public string Name - { - get - { - return Info?.Name ?? _memberName; - } - private set - { - _memberName = value; - } - } + public MemberInfo Info { get; } - public MemberInfo Info { get; private set; } + public string Name { get; } } } \ No newline at end of file diff --git a/ObjectsComparer/ObjectsComparer/Context/ComparisonContextOptions.cs b/ObjectsComparer/ObjectsComparer/Context/ComparisonContextOptions.cs index f7779cb..d559b91 100644 --- a/ObjectsComparer/ObjectsComparer/Context/ComparisonContextOptions.cs +++ b/ObjectsComparer/ObjectsComparer/Context/ComparisonContextOptions.cs @@ -18,18 +18,33 @@ internal static ComparisonContextOptions Default() internal Func ComparisonContextMemberFactory { get; private set; } - + /// + /// Factory for instances. + /// + /// public void UseComparisonContextFactory(Func factory) { ComparisonContextFactory = factory ?? throw new ArgumentNullException(nameof(factory)); } /// + /// Factory for instances. /// - /// First parameter type: Default member. public void UseComparisonContextMemberFactory(Func factory) { ComparisonContextMemberFactory = factory ?? throw new ArgumentNullException(nameof(factory)); } + + public bool ThrowContextableComparerNotImplementedEnabled { get; private set; } = true; + + /// + /// Whether to throw an if the custom comparer does not implement or . + /// + public ComparisonContextOptions ThrowContextableComparerNotImplemented(bool value) + { + ThrowContextableComparerNotImplementedEnabled = false; + + return this; + } } } diff --git a/ObjectsComparer/ObjectsComparer/Context/ComparisonContextProvider.cs b/ObjectsComparer/ObjectsComparer/Context/ComparisonContextProvider.cs index bd86f69..607a913 100644 --- a/ObjectsComparer/ObjectsComparer/Context/ComparisonContextProvider.cs +++ b/ObjectsComparer/ObjectsComparer/Context/ComparisonContextProvider.cs @@ -7,48 +7,44 @@ public static class ComparisonContextProvider { public static IComparisonContext CreateRootContext() { - return new ComparisonContext(ComparisonContextMember.Create()); + return new ComparisonContext(new ComparisonContextMember()); } internal static IComparisonContext CreateImplicitRootContext(ComparisonSettings comparisonSettings) { - _ = comparisonSettings ?? throw new ArgumentNullException(nameof(comparisonSettings)); //For future use. + _ = comparisonSettings ?? throw new ArgumentNullException(nameof(comparisonSettings)); - return new NullComparisonContext(ComparisonContextMember.Create()); - } + return new ImplicitRootComparisonContext(new ComparisonContextMember()); + } - /// - /// Context with ancestor but without a member, e.g. list element context. - /// public static IComparisonContext CreateContext(ComparisonSettings comparisonSettings, IComparisonContext ancestor) { - return CreateContext(comparisonSettings, ComparisonContextMember.Create(), ancestor); + return CreateContext(comparisonSettings, new ComparisonContextMember(), ancestor); } - /// - /// Context with ancestor and member. - /// - public static IComparisonContext CreateContext(ComparisonSettings comparisonSettings, IComparisonContext ancestor, MemberInfo member) + public static IComparisonContext CreateContext(ComparisonSettings comparisonSettings, IComparisonContext ancestor, MemberInfo memberInfo) { - return CreateContext(comparisonSettings, ComparisonContextMember.Create(member), ancestor); + return CreateContext(comparisonSettings, new ComparisonContextMember(memberInfo, memberInfo?.Name), ancestor); } - /// - /// Context with ancestor and member. - /// public static IComparisonContext CreateContext(ComparisonSettings comparisonSettings, IComparisonContext ancestor, string memberName) { - return CreateContext(comparisonSettings, ComparisonContextMember.Create(memberName), ancestor); + return CreateContext(comparisonSettings, new ComparisonContextMember(name: memberName), ancestor); + } + + public static IComparisonContext CreateContext(ComparisonSettings comparisonSettings, IComparisonContext ancestor, MemberInfo memberInfo, string memberName) + { + return CreateContext(comparisonSettings, new ComparisonContextMember(memberInfo, memberName), ancestor); } - static IComparisonContext CreateContext(ComparisonSettings comparisonSettings, IComparisonContextMember comparisonContextMember, IComparisonContext ancestor) + public static IComparisonContext CreateContext(ComparisonSettings comparisonSettings, IComparisonContextMember comparisonContextMember, IComparisonContext ancestor) { _ = comparisonSettings ?? throw new ArgumentNullException(nameof(comparisonSettings)); _ = comparisonContextMember ?? throw new ArgumentNullException(nameof(comparisonContextMember)); _ = ancestor ?? throw new ArgumentNullException(nameof(ancestor)); ComparisonContextOptions options = ComparisonContextOptions.Default(); - comparisonSettings.ComparisonContextOptionsAction?.Invoke(ancestor, options); + comparisonSettings.ComparisonContextOptionsAction?.Invoke(new ComparisonContextInfo(ancestor), options); if (options.ComparisonContextMemberFactory != null) { diff --git a/ObjectsComparer/ObjectsComparer/Context/IComparerExtensions.cs b/ObjectsComparer/ObjectsComparer/Context/IComparerExtensions.cs index 3a89161..0905d6f 100644 --- a/ObjectsComparer/ObjectsComparer/Context/IComparerExtensions.cs +++ b/ObjectsComparer/ObjectsComparer/Context/IComparerExtensions.cs @@ -35,13 +35,9 @@ public static IEnumerable CalculateDifferences(this IComparer compar return contextableComparer.CalculateDifferences(type, obj1, obj2, comparisonContext); } - if (HasComparisonContextImplicitRoot(comparisonContext)) - { - return comparer.CalculateDifferences(type, obj1, obj2); - } + ThrowContextableComparerNotImplemented(comparisonContext, comparer.Settings, comparer, nameof(IContextableComparer)); - //The caller passed on the root context, but did not provide an contextable comparer. The component guarantees that all its own comparers are contextable. - throw new ContextableComparerNotImplementedException(comparer); + return comparer.CalculateDifferences(obj1, obj2); } public static IEnumerable CalculateDifferences(this IComparer comparer, T obj1, T obj2, IComparisonContext comparisonContext) @@ -61,13 +57,9 @@ public static IEnumerable CalculateDifferences(this IComparer return contextableComparer.CalculateDifferences(obj1, obj2, comparisonContext); } - if (HasComparisonContextImplicitRoot(comparisonContext)) - { - return comparer.CalculateDifferences(obj1, obj2); - } + ThrowContextableComparerNotImplemented(comparisonContext, comparer.Settings, comparer, $"{nameof(IContextableComparer)}<{typeof(T).FullName}>"); - //The caller passed on the root context, but did not provide an contextable comparer. The component guarantees that all its own comparers are contextable. - throw new ContextableComparerNotImplementedException(comparer); + return comparer.CalculateDifferences(obj1, obj2); } static bool HasComparisonContextImplicitRoot(IComparisonContext comparisonContext) @@ -79,7 +71,7 @@ static bool HasComparisonContextImplicitRoot(IComparisonContext comparisonContex do { - if (comparisonContext.Ancestor == null && comparisonContext is NullComparisonContext) + if (comparisonContext.Ancestor == null && comparisonContext is ImplicitRootComparisonContext) { return true; } @@ -90,5 +82,46 @@ static bool HasComparisonContextImplicitRoot(IComparisonContext comparisonContex return false; } + + static void ThrowContextableComparerNotImplemented(IComparisonContext comparisonContext, ComparisonSettings comparisonSettings, object comparer, string unImplementedInterface) + { + if (comparisonContext is null) + { + throw new ArgumentNullException(nameof(comparisonContext)); + } + + if (comparisonSettings is null) + { + throw new ArgumentNullException(nameof(comparisonSettings)); + } + + var options = ComparisonContextOptions.Default(); + comparisonSettings.ComparisonContextOptionsAction?.Invoke(null, options); + + if (options.ThrowContextableComparerNotImplementedEnabled == false) + { + return; + } + + if (comparisonSettings.ComparisonContextOptionsAction != null) + { + var message = $"Because the comparison context was passed to the comparison, the {comparer.GetType().FullName} must implement {unImplementedInterface} interface. If you do not want to implement this interface, you must not pass a comparison context or you must disable the ThrowContextableException."; + throw new ContextableComparerNotImplementedException(message); + } + + if (comparisonSettings.ListComparisonOptionsAction != null) + { + var message = $"Because the comparison context was passed to the comparison, the {comparer.GetType().FullName} must implement {unImplementedInterface} interface. If you do not want to implement this interface, you must not pass a comparison context or you must disable the ThrowContextableException."; + throw new ContextableComparerNotImplementedException(message); + } + + //TODO: Check DifferenceOptionsAction + + if (HasComparisonContextImplicitRoot(comparisonContext) == false) + { + var message = $"Because the comparison context was passed to the comparison, the {comparer.GetType().FullName} must implement {unImplementedInterface} interface. If you do not want to implement that interface, you must not pass a comparison context or you must disable the ThrowContextableException."; + throw new ContextableComparerNotImplementedException(message); + } + } } } \ No newline at end of file diff --git a/ObjectsComparer/ObjectsComparer/Context/IComparisonContextMember.cs b/ObjectsComparer/ObjectsComparer/Context/IComparisonContextMember.cs index 5cb643a..376f3ed 100644 --- a/ObjectsComparer/ObjectsComparer/Context/IComparisonContextMember.cs +++ b/ObjectsComparer/ObjectsComparer/Context/IComparisonContextMember.cs @@ -3,12 +3,12 @@ namespace ObjectsComparer { /// - /// The member being compared in the comparison process, usually a property. + /// The member in the comparison process, usually a property. /// public interface IComparisonContextMember { /// - /// Member. + /// Member. It should never be empty. /// string Name { get; } diff --git a/ObjectsComparer/ObjectsComparer/Context/IListComparisonContextInfo.cs b/ObjectsComparer/ObjectsComparer/Context/IListComparisonContextInfo.cs deleted file mode 100644 index 83c0132..0000000 --- a/ObjectsComparer/ObjectsComparer/Context/IListComparisonContextInfo.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace ObjectsComparer -{ - public interface IListComparisonContextInfo : IComparisonContextInfo - { - } -} \ No newline at end of file diff --git a/ObjectsComparer/ObjectsComparer/Context/ImplicitRootComparisonContext.cs b/ObjectsComparer/ObjectsComparer/Context/ImplicitRootComparisonContext.cs new file mode 100644 index 0000000..eb24410 --- /dev/null +++ b/ObjectsComparer/ObjectsComparer/Context/ImplicitRootComparisonContext.cs @@ -0,0 +1,19 @@ +using System.Collections.Generic; +using System.Linq; + +namespace ObjectsComparer +{ + /// + /// Root compariosin context for cases where the consumer does not create and pass his own root context at the beginning of the comparison. + /// + internal class ImplicitRootComparisonContext : ComparisonContextBase + { + public ImplicitRootComparisonContext(IComparisonContextMember member = null, IComparisonContext ancestor = null) : base(member, ancestor) + { + } + + public override void AddDifference(Difference difference) + { + } + } +} diff --git a/ObjectsComparer/ObjectsComparer/Context/NullComparisonContext.cs b/ObjectsComparer/ObjectsComparer/Context/NullComparisonContext.cs deleted file mode 100644 index 7afbaad..0000000 --- a/ObjectsComparer/ObjectsComparer/Context/NullComparisonContext.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System.Collections.Generic; -using System.Linq; - -namespace ObjectsComparer -{ - /// - /// Null context for cases where the consumer does not create his own root context at the beginning of the comparison. No descendants or differences will be builded in the comparison process. - /// - internal class NullComparisonContext : ComparisonContextBase - { - public NullComparisonContext(IComparisonContextMember member = null, IComparisonContext ancestor = null) : base(member, ancestor) - { - } - - public override void AddDifference(Difference difference) - { - } - } -} diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractDynamicObjectsComprer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractDynamicObjectsComprer.cs index 5ac97be..0ffc9a0 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractDynamicObjectsComprer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractDynamicObjectsComprer.cs @@ -51,7 +51,7 @@ public virtual IEnumerable CalculateDifferences(Type type, object ob TryGetMember(castedObject1, propertyKey, out member2); } - var keyComparisonContext = CreateContextFromMemberOrMemberName(comparisonContext, member1 ?? member2, propertyKey); + var keyComparisonContext = ComparisonContextProvider.CreateContext(Settings, comparisonContext, member1 ?? member2, propertyKey); var propertyType = (value1 ?? value2)?.GetType() ?? typeof(object); var customComparer = OverridesCollection.GetComparer(propertyType) ?? @@ -145,27 +145,7 @@ public virtual IEnumerable CalculateDifferences(Type type, object ob } } } - - /// - /// Creates context with ancestor and member. The takes precedence over . - /// - IComparisonContext CreateContextFromMemberOrMemberName(IComparisonContext ancestor, MemberInfo member, string memberName) - { - _ = ancestor ?? throw new ArgumentNullException(nameof(ancestor)); - - if (member != null) - { - return ComparisonContextProvider.CreateContext(Settings, ancestor, member); - } - - if (memberName != null) - { - return ComparisonContextProvider.CreateContext(Settings, ancestor, memberName); - } - - throw new ArgumentException(); - } - + public abstract bool IsMatch(Type type, object obj1, object obj2); public abstract bool IsStopComparison(Type type, object obj1, object obj2); diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs index e1ee04e..172ee8c 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs @@ -58,7 +58,7 @@ public IEnumerable CalculateDifferences(Type type, object obj1, obje var array2 = ((IEnumerable)obj2).Cast().ToArray(); var listComparisonOptions = ListComparisonOptions.Default(); - var listComparisonContextInfo = new ListComparisonContextInfo(listComparisonContext); + var listComparisonContextInfo = new ComparisonContextInfo(listComparisonContext); Settings.ListComparisonOptionsAction?.Invoke(listComparisonContextInfo, listComparisonOptions); if (array1.Length != array2.Length) diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer~1.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer~1.cs index 0eda6fc..da0dca3 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer~1.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer~1.cs @@ -58,7 +58,7 @@ public IEnumerable CalculateDifferences(Type type, object obj1, obje var list2 = ((IEnumerable)obj2).ToList(); var listComparisonOptions = ListComparisonOptions.Default(); - var listComparisonContextInfo = new ListComparisonContextInfo(listComparisonContext); + var listComparisonContextInfo = new ComparisonContextInfo(listComparisonContext); Settings.ListComparisonOptionsAction?.Invoke(listComparisonContextInfo, listComparisonOptions); if (list1.Count != list2.Count) diff --git a/ObjectsComparer/ObjectsComparer/Exceptions/ContextableComparerNotImplementedException.cs b/ObjectsComparer/ObjectsComparer/Exceptions/ContextableComparerNotImplementedException.cs index f3b48ef..dbb2897 100644 --- a/ObjectsComparer/ObjectsComparer/Exceptions/ContextableComparerNotImplementedException.cs +++ b/ObjectsComparer/ObjectsComparer/Exceptions/ContextableComparerNotImplementedException.cs @@ -4,21 +4,8 @@ namespace ObjectsComparer.Exceptions { public class ContextableComparerNotImplementedException : NotImplementedException { - internal ContextableComparerNotImplementedException(object comparer) : base(message: $"The comparer argument of type {comparer?.GetType()?.FullName} does not implement IContextableComparer interface.") + internal ContextableComparerNotImplementedException(string message) : base(message) { - Comparer = comparer ?? throw new ArgumentNullException(nameof(comparer)); } - - public object Comparer { get; } - } - - public class ContextableComparerNotImplementedException : NotImplementedException - { - internal ContextableComparerNotImplementedException(IComparer comparer) : base(message: $"The comparer argument of type {comparer?.GetType()?.FullName} does not implement IContextableComparer interface.") - { - Comparer = comparer ?? throw new ArgumentNullException(nameof(comparer)); - } - - public IComparer Comparer { get; } } } From 2f2f896151e88a58a557d7a57a10efa54c610de7 Mon Sep 17 00:00:00 2001 From: nemec Date: Thu, 10 Feb 2022 22:01:03 +0100 Subject: [PATCH 104/181] Rename ImplicitRootComparisonContext > ImplicitComparisonContext. Edit comments. --- .../Context/ComparisonContextOptions.cs | 6 ++++-- .../Context/ComparisonContextProvider.cs | 2 +- .../ObjectsComparer/Context/IComparerExtensions.cs | 13 +++++++++---- .../Context/ImplicitRootComparisonContext.cs | 4 ++-- .../ContextableComparerNotImplementedException.cs | 4 ++++ 5 files changed, 20 insertions(+), 9 deletions(-) diff --git a/ObjectsComparer/ObjectsComparer/Context/ComparisonContextOptions.cs b/ObjectsComparer/ObjectsComparer/Context/ComparisonContextOptions.cs index d559b91..93df834 100644 --- a/ObjectsComparer/ObjectsComparer/Context/ComparisonContextOptions.cs +++ b/ObjectsComparer/ObjectsComparer/Context/ComparisonContextOptions.cs @@ -1,5 +1,6 @@ using System; using System.Reflection; +using ObjectsComparer.Exceptions; namespace ObjectsComparer { @@ -38,11 +39,12 @@ public void UseComparisonContextMemberFactory(Func - /// Whether to throw an if the custom comparer does not implement or . + /// Whether to throw the when the user requires comparison context but has a comparer that does not implement or . + /// Default = true. /// public ComparisonContextOptions ThrowContextableComparerNotImplemented(bool value) { - ThrowContextableComparerNotImplementedEnabled = false; + ThrowContextableComparerNotImplementedEnabled = value; return this; } diff --git a/ObjectsComparer/ObjectsComparer/Context/ComparisonContextProvider.cs b/ObjectsComparer/ObjectsComparer/Context/ComparisonContextProvider.cs index 607a913..315afd7 100644 --- a/ObjectsComparer/ObjectsComparer/Context/ComparisonContextProvider.cs +++ b/ObjectsComparer/ObjectsComparer/Context/ComparisonContextProvider.cs @@ -14,7 +14,7 @@ internal static IComparisonContext CreateImplicitRootContext(ComparisonSettings { _ = comparisonSettings ?? throw new ArgumentNullException(nameof(comparisonSettings)); - return new ImplicitRootComparisonContext(new ComparisonContextMember()); + return new ImplicitComparisonContext(new ComparisonContextMember()); } public static IComparisonContext CreateContext(ComparisonSettings comparisonSettings, IComparisonContext ancestor) diff --git a/ObjectsComparer/ObjectsComparer/Context/IComparerExtensions.cs b/ObjectsComparer/ObjectsComparer/Context/IComparerExtensions.cs index 0905d6f..4e62fa2 100644 --- a/ObjectsComparer/ObjectsComparer/Context/IComparerExtensions.cs +++ b/ObjectsComparer/ObjectsComparer/Context/IComparerExtensions.cs @@ -12,7 +12,6 @@ public static class IComparerExtensions /// /// Calculates list of differences between objects. Accepts comparison context. /// - /// If does not implement . public static IEnumerable CalculateDifferences(this IComparer comparer, Type type, object obj1, object obj2, IComparisonContext comparisonContext) { if (comparer is null) @@ -40,6 +39,9 @@ public static IEnumerable CalculateDifferences(this IComparer compar return comparer.CalculateDifferences(obj1, obj2); } + /// + /// Calculates list of differences between objects. Accepts comparison context. + /// public static IEnumerable CalculateDifferences(this IComparer comparer, T obj1, T obj2, IComparisonContext comparisonContext) { if (comparer is null) @@ -105,13 +107,15 @@ static void ThrowContextableComparerNotImplemented(IComparisonContext comparison if (comparisonSettings.ComparisonContextOptionsAction != null) { - var message = $"Because the comparison context was passed to the comparison, the {comparer.GetType().FullName} must implement {unImplementedInterface} interface. If you do not want to implement this interface, you must not pass a comparison context or you must disable the ThrowContextableException."; + var message = $"Because the comparison context was explicitly configured, the {comparer.GetType().FullName} must implement {unImplementedInterface} interface " + + "or throwing the ContextableComparerNotImplementedException must be disabled."; throw new ContextableComparerNotImplementedException(message); } if (comparisonSettings.ListComparisonOptionsAction != null) { - var message = $"Because the comparison context was passed to the comparison, the {comparer.GetType().FullName} must implement {unImplementedInterface} interface. If you do not want to implement this interface, you must not pass a comparison context or you must disable the ThrowContextableException."; + var message = $"Because the list comparison was explicitly configured, the {comparer.GetType().FullName} must implement {unImplementedInterface} interface " + + "or throwing the ContextableComparerNotImplementedException must be disabled."; throw new ContextableComparerNotImplementedException(message); } @@ -119,7 +123,8 @@ static void ThrowContextableComparerNotImplemented(IComparisonContext comparison if (HasComparisonContextImplicitRoot(comparisonContext) == false) { - var message = $"Because the comparison context was passed to the comparison, the {comparer.GetType().FullName} must implement {unImplementedInterface} interface. If you do not want to implement that interface, you must not pass a comparison context or you must disable the ThrowContextableException."; + var message = $"Because the comparison context was explicitly passed, the {comparer.GetType().FullName} must implement {unImplementedInterface} interface " + + "or throwing the ContextableComparerNotImplementedException must be disabled."; throw new ContextableComparerNotImplementedException(message); } } diff --git a/ObjectsComparer/ObjectsComparer/Context/ImplicitRootComparisonContext.cs b/ObjectsComparer/ObjectsComparer/Context/ImplicitRootComparisonContext.cs index eb24410..4271038 100644 --- a/ObjectsComparer/ObjectsComparer/Context/ImplicitRootComparisonContext.cs +++ b/ObjectsComparer/ObjectsComparer/Context/ImplicitRootComparisonContext.cs @@ -6,9 +6,9 @@ namespace ObjectsComparer /// /// Root compariosin context for cases where the consumer does not create and pass his own root context at the beginning of the comparison. /// - internal class ImplicitRootComparisonContext : ComparisonContextBase + internal class ImplicitComparisonContext : ComparisonContextBase { - public ImplicitRootComparisonContext(IComparisonContextMember member = null, IComparisonContext ancestor = null) : base(member, ancestor) + public ImplicitComparisonContext(IComparisonContextMember member = null, IComparisonContext ancestor = null) : base(member, ancestor) { } diff --git a/ObjectsComparer/ObjectsComparer/Exceptions/ContextableComparerNotImplementedException.cs b/ObjectsComparer/ObjectsComparer/Exceptions/ContextableComparerNotImplementedException.cs index dbb2897..4408b9d 100644 --- a/ObjectsComparer/ObjectsComparer/Exceptions/ContextableComparerNotImplementedException.cs +++ b/ObjectsComparer/ObjectsComparer/Exceptions/ContextableComparerNotImplementedException.cs @@ -2,6 +2,10 @@ namespace ObjectsComparer.Exceptions { + /// + /// Depending on the configuration, this exception may be thrown when a user defined comparer does not implement or . + /// To prevent this exception from being thrown, see operation. + /// public class ContextableComparerNotImplementedException : NotImplementedException { internal ContextableComparerNotImplementedException(string message) : base(message) From dea64f1b515431c067b80deb09e5d03ae66670c9 Mon Sep 17 00:00:00 2001 From: nemec Date: Fri, 11 Feb 2022 14:07:02 +0100 Subject: [PATCH 105/181] Rename ImplicitComparisonContext. --- ObjectsComparer/ObjectsComparer/Context/IComparerExtensions.cs | 2 +- ...citRootComparisonContext.cs => ImplicitComparisonContext.cs} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename ObjectsComparer/ObjectsComparer/Context/{ImplicitRootComparisonContext.cs => ImplicitComparisonContext.cs} (100%) diff --git a/ObjectsComparer/ObjectsComparer/Context/IComparerExtensions.cs b/ObjectsComparer/ObjectsComparer/Context/IComparerExtensions.cs index 4e62fa2..1c84665 100644 --- a/ObjectsComparer/ObjectsComparer/Context/IComparerExtensions.cs +++ b/ObjectsComparer/ObjectsComparer/Context/IComparerExtensions.cs @@ -73,7 +73,7 @@ static bool HasComparisonContextImplicitRoot(IComparisonContext comparisonContex do { - if (comparisonContext.Ancestor == null && comparisonContext is ImplicitRootComparisonContext) + if (comparisonContext.Ancestor == null && comparisonContext is ImplicitComparisonContext) { return true; } diff --git a/ObjectsComparer/ObjectsComparer/Context/ImplicitRootComparisonContext.cs b/ObjectsComparer/ObjectsComparer/Context/ImplicitComparisonContext.cs similarity index 100% rename from ObjectsComparer/ObjectsComparer/Context/ImplicitRootComparisonContext.cs rename to ObjectsComparer/ObjectsComparer/Context/ImplicitComparisonContext.cs From d9485610ea5867add0cfeb5daa00de2ec487e38d Mon Sep 17 00:00:00 2001 From: Daniel Nemec Date: Wed, 2 Mar 2022 07:42:28 +0100 Subject: [PATCH 106/181] Mark IComparisonContextInfo as obsolete. --- .../ObjectsComparer/Context/IComparisonContextInfo.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ObjectsComparer/ObjectsComparer/Context/IComparisonContextInfo.cs b/ObjectsComparer/ObjectsComparer/Context/IComparisonContextInfo.cs index 4201ad4..7abbf7c 100644 --- a/ObjectsComparer/ObjectsComparer/Context/IComparisonContextInfo.cs +++ b/ObjectsComparer/ObjectsComparer/Context/IComparisonContextInfo.cs @@ -1,5 +1,8 @@ -namespace ObjectsComparer +using System; + +namespace ObjectsComparer { + [Obsolete] public interface IComparisonContextInfo { IComparisonContextMember Member { get; } From 96aee9ce4720d5b608ba34b51def4ed4c68e7ce6 Mon Sep 17 00:00:00 2001 From: Daniel Nemec Date: Wed, 2 Mar 2022 14:44:12 +0100 Subject: [PATCH 107/181] Add EnumerateConditional test method. --- .../ComparisonContextTests.cs | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/ObjectsComparer/ObjectsComparer.Tests/ComparisonContextTests.cs b/ObjectsComparer/ObjectsComparer.Tests/ComparisonContextTests.cs index 25b774a..38b9f02 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/ComparisonContextTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/ComparisonContextTests.cs @@ -6,6 +6,7 @@ using ObjectsComparer.Tests.TestClasses; using ObjectsComparer.Tests.Utils; using System.Reflection; +using System.Diagnostics; namespace ObjectsComparer.Tests { @@ -75,6 +76,40 @@ public void ComparisonContextException() var diffs = comparer.CalculateDifferences("hello", "hi", rootCtx).ToArray(); } + + [Test] + public void EnumerateConditional() + { + var list = new List { 6, 8, 79, 3, 45, 9 }; + + var enumerateConditional = EnumerateConditionalExt( + list, + moveNextItem: () => true, + completed: () => Debug.WriteLine("Completed")); + + foreach (var item in enumerateConditional) + { + Debug.WriteLine(item); + } + } + + protected IEnumerable EnumerateConditionalExt(IEnumerable enumerable, Func moveNextItem, Action completed = null) + { + var enumerator = enumerable.GetEnumerator(); + + while (moveNextItem()) + { + if (enumerator.MoveNext()) + { + yield return enumerator.Current; + } + else + { + completed?.Invoke(); + break; + } + } + } } class CustomComparersFactory : ComparersFactory From 21725dfb94d0e86912ddaa3587675491769c6dd3 Mon Sep 17 00:00:00 2001 From: Daniel Nemec Date: Sat, 12 Mar 2022 10:30:31 +0100 Subject: [PATCH 108/181] Delete IComparisonContextInfo. --- .../ComparisonSettingsTests.cs | 14 +------------ .../ObjectsComparer/ComparisonSettings.cs | 8 +++---- .../Context/ComparisonContextInfo.cs | 9 -------- .../Context/ComparisonContextInfoBase.cs | 21 ------------------- .../Context/ComparisonContextProvider.cs | 2 +- .../Context/IComparisonContextInfo.cs | 12 ----------- .../CustomComparers/EnumerablesComparer.cs | 3 +-- .../CustomComparers/EnumerablesComparer~1.cs | 3 +-- 8 files changed, 8 insertions(+), 64 deletions(-) delete mode 100644 ObjectsComparer/ObjectsComparer/Context/ComparisonContextInfo.cs delete mode 100644 ObjectsComparer/ObjectsComparer/Context/ComparisonContextInfoBase.cs delete mode 100644 ObjectsComparer/ObjectsComparer/Context/IComparisonContextInfo.cs diff --git a/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs b/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs index be004c9..fdca3a0 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs @@ -82,8 +82,7 @@ public void CompareListElementsByKeyIsCorrectlySet() //Component side. var listComparisonOptions = ListComparisonOptions.Default(); var ctx = new ComparisonContext(); - var listComparisonContextInfo = new ComparisonContextInfo(ctx); - settings.ListComparisonOptionsAction(listComparisonContextInfo, listComparisonOptions); + settings.ListComparisonOptionsAction(ctx, listComparisonOptions); var listElementComparisonByKeyOptions = ListElementComparisonByKeyOptions.Default(); listComparisonOptions.KeyOptionsAction(listElementComparisonByKeyOptions); @@ -316,17 +315,6 @@ public static void LambdaTest() // Captured local variable is equal to 10: True // 3 is greater than 5: False // Another lambda observes a new value of captured variable: True - - [Test] - public void TestListComparisonContextInfo() - { - var ancestorMember = new ComparisonContextMember(name: "Property1"); - var ancestorCtx = new ComparisonContext(ancestorMember); - var member = new ComparisonContextMember(name: "Property2"); - var ctx = new ComparisonContext(member, ancestorCtx); - var listCtxInfo = new ComparisonContextInfo(ctx); - Assert.AreEqual("Property1.Property2", $"{listCtxInfo.Ancestor.Member.Name}.{listCtxInfo.Member.Name}"); - } } public class VariableCaptureGame diff --git a/ObjectsComparer/ObjectsComparer/ComparisonSettings.cs b/ObjectsComparer/ObjectsComparer/ComparisonSettings.cs index 96b17c6..9f9fe5a 100644 --- a/ObjectsComparer/ObjectsComparer/ComparisonSettings.cs +++ b/ObjectsComparer/ObjectsComparer/ComparisonSettings.cs @@ -67,13 +67,13 @@ public T GetCustomSetting(string key = null) throw new KeyNotFoundException(); } - internal Action ListComparisonOptionsAction { get; private set; } = null; + internal Action ListComparisonOptionsAction { get; private set; } = null; /// /// Configures list comparison behavior, especially the type of the comparison. For more info, see . /// /// First parameter: Current list comparison context. - public ComparisonSettings ConfigureListComparison(Action comparisonOptions) + public ComparisonSettings ConfigureListComparison(Action comparisonOptions) { if (comparisonOptions is null) { @@ -117,9 +117,9 @@ public void ConfigureListComparison(bool compareElementsByKey = false, bool comp }); } - internal Action ComparisonContextOptionsAction { get; private set; } + internal Action ComparisonContextOptionsAction { get; private set; } - public void ConfigureComparisonContext(Action options) + public void ConfigureComparisonContext(Action options) { ComparisonContextOptionsAction = options ?? throw new ArgumentNullException(nameof(options)); } diff --git a/ObjectsComparer/ObjectsComparer/Context/ComparisonContextInfo.cs b/ObjectsComparer/ObjectsComparer/Context/ComparisonContextInfo.cs deleted file mode 100644 index 6c1dde1..0000000 --- a/ObjectsComparer/ObjectsComparer/Context/ComparisonContextInfo.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace ObjectsComparer -{ - internal class ComparisonContextInfo : ComparisonContextInfoBase - { - public ComparisonContextInfo(IComparisonContext comparisonContext) : base(comparisonContext) - { - } - } -} \ No newline at end of file diff --git a/ObjectsComparer/ObjectsComparer/Context/ComparisonContextInfoBase.cs b/ObjectsComparer/ObjectsComparer/Context/ComparisonContextInfoBase.cs deleted file mode 100644 index dd5634f..0000000 --- a/ObjectsComparer/ObjectsComparer/Context/ComparisonContextInfoBase.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System; - -namespace ObjectsComparer -{ - internal class ComparisonContextInfoBase : IComparisonContextInfo - { - readonly IComparisonContext _comparisonContext; - - readonly IComparisonContextInfo _ancestor; - - public ComparisonContextInfoBase(IComparisonContext comparisonContext) - { - _comparisonContext = comparisonContext ?? throw new ArgumentNullException(nameof(comparisonContext)); - _ancestor = _comparisonContext.Ancestor == null ? null : new ComparisonContextInfo(_comparisonContext.Ancestor); - } - - public IComparisonContextMember Member => _comparisonContext.Member; - - public IComparisonContextInfo Ancestor => _ancestor; - } -} \ No newline at end of file diff --git a/ObjectsComparer/ObjectsComparer/Context/ComparisonContextProvider.cs b/ObjectsComparer/ObjectsComparer/Context/ComparisonContextProvider.cs index 315afd7..a662663 100644 --- a/ObjectsComparer/ObjectsComparer/Context/ComparisonContextProvider.cs +++ b/ObjectsComparer/ObjectsComparer/Context/ComparisonContextProvider.cs @@ -44,7 +44,7 @@ public static IComparisonContext CreateContext(ComparisonSettings comparisonSett _ = ancestor ?? throw new ArgumentNullException(nameof(ancestor)); ComparisonContextOptions options = ComparisonContextOptions.Default(); - comparisonSettings.ComparisonContextOptionsAction?.Invoke(new ComparisonContextInfo(ancestor), options); + comparisonSettings.ComparisonContextOptionsAction?.Invoke(ancestor, options); if (options.ComparisonContextMemberFactory != null) { diff --git a/ObjectsComparer/ObjectsComparer/Context/IComparisonContextInfo.cs b/ObjectsComparer/ObjectsComparer/Context/IComparisonContextInfo.cs deleted file mode 100644 index 7abbf7c..0000000 --- a/ObjectsComparer/ObjectsComparer/Context/IComparisonContextInfo.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System; - -namespace ObjectsComparer -{ - [Obsolete] - public interface IComparisonContextInfo - { - IComparisonContextMember Member { get; } - - IComparisonContextInfo Ancestor { get; } - } -} \ No newline at end of file diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs index 172ee8c..1eee6e4 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs @@ -58,8 +58,7 @@ public IEnumerable CalculateDifferences(Type type, object obj1, obje var array2 = ((IEnumerable)obj2).Cast().ToArray(); var listComparisonOptions = ListComparisonOptions.Default(); - var listComparisonContextInfo = new ComparisonContextInfo(listComparisonContext); - Settings.ListComparisonOptionsAction?.Invoke(listComparisonContextInfo, listComparisonOptions); + Settings.ListComparisonOptionsAction?.Invoke(listComparisonContext, listComparisonOptions); if (array1.Length != array2.Length) { diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer~1.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer~1.cs index da0dca3..602b2dc 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer~1.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer~1.cs @@ -58,8 +58,7 @@ public IEnumerable CalculateDifferences(Type type, object obj1, obje var list2 = ((IEnumerable)obj2).ToList(); var listComparisonOptions = ListComparisonOptions.Default(); - var listComparisonContextInfo = new ComparisonContextInfo(listComparisonContext); - Settings.ListComparisonOptionsAction?.Invoke(listComparisonContextInfo, listComparisonOptions); + Settings.ListComparisonOptionsAction?.Invoke(listComparisonContext, listComparisonOptions); if (list1.Count != list2.Count) { From 8a6801b59d0febc7363751622d9c835a947f01a9 Mon Sep 17 00:00:00 2001 From: Daniel Nemec Date: Sat, 12 Mar 2022 11:17:22 +0100 Subject: [PATCH 109/181] Comment ComparisonContextException test method. --- .../ComparisonContextTests.cs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/ObjectsComparer/ObjectsComparer.Tests/ComparisonContextTests.cs b/ObjectsComparer/ObjectsComparer.Tests/ComparisonContextTests.cs index 38b9f02..7fcb6ea 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/ComparisonContextTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/ComparisonContextTests.cs @@ -67,15 +67,15 @@ public void CustomComparisonContextMember() Assert.IsTrue(ctx.Ancestor == rootCtx); } - [Test] - public void ComparisonContextException() - { - var factory = new CustomComparersFactory(); - var comparer = factory.GetObjectsComparer(); - var rootCtx = ComparisonContextProvider.CreateRootContext(); - - var diffs = comparer.CalculateDifferences("hello", "hi", rootCtx).ToArray(); - } + //[Test] + //public void ComparisonContextException() + //{ + // var factory = new CustomComparersFactory(); + // var comparer = factory.GetObjectsComparer(); + // var rootCtx = ComparisonContextProvider.CreateRootContext(); + + // var diffs = comparer.CalculateDifferences("hello", "hi", rootCtx).ToArray(); + //} [Test] public void EnumerateConditional() From 00b3c5e87022d872a1b1c5691979a2793980eda1 Mon Sep 17 00:00:00 2001 From: Daniel Nemec Date: Sat, 12 Mar 2022 21:28:40 +0100 Subject: [PATCH 110/181] Make ComparisonContextBase thread not safe again. --- .../Comparer_GenericEnumerableTests.cs | 2 -- .../ComparisonSettingsTests.cs | 2 -- .../Context/ComparisonContextBase.cs | 23 ++++++++----------- 3 files changed, 9 insertions(+), 18 deletions(-) diff --git a/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs b/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs index a2fc2d8..95eb89c 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs @@ -87,8 +87,6 @@ public void PrimitiveTypeArrayInequalityCount_CompareUnequalLists() Assert.AreEqual(2, diffsFromCtx.Count); Assert.AreEqual(differences[0], diffsFromCtx[0]); Assert.AreEqual(differences[1], diffsFromCtx[1]); - - var ctxjson = (rootCtx.Shrink() as ComparisonContext).ToJson(skipNullReference: false); } [Test] diff --git a/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs b/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs index fdca3a0..0ac4689 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs @@ -139,8 +139,6 @@ public void FluentTest_CompareUnequalLists() Assert.AreEqual("4", differences[3].Value2); Assert.IsTrue(differences.AreEquivalent(ctx.GetDifferences(true))); - - var ctxJson = (ctx.Shrink() as ComparisonContext).ToJson(); } [Test] diff --git a/ObjectsComparer/ObjectsComparer/Context/ComparisonContextBase.cs b/ObjectsComparer/ObjectsComparer/Context/ComparisonContextBase.cs index 6d84368..fdcd75c 100644 --- a/ObjectsComparer/ObjectsComparer/Context/ComparisonContextBase.cs +++ b/ObjectsComparer/ObjectsComparer/Context/ComparisonContextBase.cs @@ -9,8 +9,6 @@ namespace ObjectsComparer /// public abstract class ComparisonContextBase : IComparisonContext { - object _shrinkLock = new object(); - readonly List _descendants = new List(); readonly List _differences = new List(); @@ -94,22 +92,19 @@ public bool HasDifferences(bool recursive) public IComparisonContext Shrink() { - lock (_shrinkLock) + List removeDescendants = new List(); + + _descendants.ForEach(descendantContext => { - List removeDescendants = new List(); + descendantContext.Shrink(); - _descendants.ForEach(descendantContext => + if (descendantContext.HasDifferences(true) == false) { - descendantContext.Shrink(); - - if (descendantContext.HasDifferences(true) == false) - { - removeDescendants.Add(descendantContext); - } - }); + removeDescendants.Add(descendantContext); + } + }); - _descendants.RemoveAll(ctx => removeDescendants.Contains(ctx)); - } + _descendants.RemoveAll(ctx => removeDescendants.Contains(ctx)); return this; } From ec5ffd0f775ba38c58c0f2a893fe141ed7d30a3f Mon Sep 17 00:00:00 2001 From: nemec Date: Wed, 16 Mar 2022 05:28:28 +0100 Subject: [PATCH 111/181] Init CalculateDifferences override. --- .../Context/ComparisonContextProvider.cs | 2 +- .../Context/IComparerExtensions.cs | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/ObjectsComparer/ObjectsComparer/Context/ComparisonContextProvider.cs b/ObjectsComparer/ObjectsComparer/Context/ComparisonContextProvider.cs index a662663..df8abdf 100644 --- a/ObjectsComparer/ObjectsComparer/Context/ComparisonContextProvider.cs +++ b/ObjectsComparer/ObjectsComparer/Context/ComparisonContextProvider.cs @@ -41,7 +41,7 @@ public static IComparisonContext CreateContext(ComparisonSettings comparisonSett { _ = comparisonSettings ?? throw new ArgumentNullException(nameof(comparisonSettings)); _ = comparisonContextMember ?? throw new ArgumentNullException(nameof(comparisonContextMember)); - _ = ancestor ?? throw new ArgumentNullException(nameof(ancestor)); + //_ = ancestor ?? throw new ArgumentNullException(nameof(ancestor)); ComparisonContextOptions options = ComparisonContextOptions.Default(); comparisonSettings.ComparisonContextOptionsAction?.Invoke(ancestor, options); diff --git a/ObjectsComparer/ObjectsComparer/Context/IComparerExtensions.cs b/ObjectsComparer/ObjectsComparer/Context/IComparerExtensions.cs index 1c84665..5e60810 100644 --- a/ObjectsComparer/ObjectsComparer/Context/IComparerExtensions.cs +++ b/ObjectsComparer/ObjectsComparer/Context/IComparerExtensions.cs @@ -128,5 +128,23 @@ static void ThrowContextableComparerNotImplemented(IComparisonContext comparison throw new ContextableComparerNotImplementedException(message); } } + + public static IComparisonContext CalculateDifferences(this IComparer comparer, Type type, object obj1, object obj2, Func findNextDifference = null, Action contextCompleted = null) + { + if (comparer is null) + { + throw new ArgumentNullException(nameof(comparer)); + } + + if (type is null) + { + throw new ArgumentNullException(nameof(type)); + } + + var rootCtx = ComparisonContextProvider.CreateContext(comparer.Settings, null); + var differences = comparer.CalculateDifferences(type, obj1, obj2, rootCtx); + + return rootCtx; + } } } \ No newline at end of file From 716282492ea2e930a886600572f2297500d519c7 Mon Sep 17 00:00:00 2001 From: Daniel Nemec Date: Wed, 16 Mar 2022 12:45:44 +0100 Subject: [PATCH 112/181] Edit comment. --- ObjectsComparer/ObjectsComparer/Context/IComparisonContext.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ObjectsComparer/ObjectsComparer/Context/IComparisonContext.cs b/ObjectsComparer/ObjectsComparer/Context/IComparisonContext.cs index bcb6aa8..61d4a16 100644 --- a/ObjectsComparer/ObjectsComparer/Context/IComparisonContext.cs +++ b/ObjectsComparer/ObjectsComparer/Context/IComparisonContext.cs @@ -6,6 +6,8 @@ namespace ObjectsComparer { + //TODO: Edit "Once the comparison process is completed, it is possible to traverse " + /// /// Context of comparison process. Each instance wraps compared , which is typically property. Each context has its ancestor and descendants the same way as its compared has its ancestor and descendant members. /// Once the comparison process is completed, it is possible to traverse the comparison context graph and see differences at particular members. From d555a44d36ae610f75db8186949caa08693db4f3 Mon Sep 17 00:00:00 2001 From: nemec Date: Wed, 16 Mar 2022 17:01:40 +0100 Subject: [PATCH 113/181] Add EnumerateConditional extension. --- .../ComparisonContextTests.cs | 38 +++++++++++++++++++ .../Context/IComparerExtensions.cs | 33 +++++++++++++++- 2 files changed, 69 insertions(+), 2 deletions(-) diff --git a/ObjectsComparer/ObjectsComparer.Tests/ComparisonContextTests.cs b/ObjectsComparer/ObjectsComparer.Tests/ComparisonContextTests.cs index 7fcb6ea..5dfde00 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/ComparisonContextTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/ComparisonContextTests.cs @@ -93,6 +93,44 @@ public void EnumerateConditional() } } + [Test] + public void EnumerateConditional_Completed() + { + var list = new List { 6, 8, 79, 3, 45, 9 }; + bool completed = false; + int? lastElement = null; + + list.EnumerateConditional( + element => + { + lastElement = element; + return true; + }, + () => completed = true); + + Assert.AreEqual(9, lastElement); + Assert.AreEqual(true, completed); + } + + [Test] + public void EnumerateConditional_FetchOne_NotCompleted() + { + var list = new List { 6, 8, 79, 3, 45, 9 }; + bool completed = false; + int? firstElement = null; + + list.EnumerateConditional( + element => + { + firstElement = element; + return false; + }, + () => completed = true); + + Assert.AreEqual(6, firstElement); + Assert.AreEqual(false, completed); + } + protected IEnumerable EnumerateConditionalExt(IEnumerable enumerable, Func moveNextItem, Action completed = null) { var enumerator = enumerable.GetEnumerator(); diff --git a/ObjectsComparer/ObjectsComparer/Context/IComparerExtensions.cs b/ObjectsComparer/ObjectsComparer/Context/IComparerExtensions.cs index 5e60810..fd5de69 100644 --- a/ObjectsComparer/ObjectsComparer/Context/IComparerExtensions.cs +++ b/ObjectsComparer/ObjectsComparer/Context/IComparerExtensions.cs @@ -129,7 +129,7 @@ static void ThrowContextableComparerNotImplemented(IComparisonContext comparison } } - public static IComparisonContext CalculateDifferences(this IComparer comparer, Type type, object obj1, object obj2, Func findNextDifference = null, Action contextCompleted = null) + public static IComparisonContext CalculateDifferences(this IComparer comparer, Type type, object obj1, object obj2, Func findNextDifference = null, Action contextCompleted = null) { if (comparer is null) { @@ -141,10 +141,39 @@ public static IComparisonContext CalculateDifferences(this IComparer comparer, T throw new ArgumentNullException(nameof(type)); } - var rootCtx = ComparisonContextProvider.CreateContext(comparer.Settings, null); + var rootCtx = ComparisonContextProvider.CreateContext(comparer.Settings, ancestor: null); var differences = comparer.CalculateDifferences(type, obj1, obj2, rootCtx); + differences.EnumerateConditional( + currentDifference => + { + return findNextDifference(null, currentDifference); + }, + contextCompleted); + return rootCtx; } + + internal static void EnumerateConditional(this IEnumerable enumerable, Func findNextElement = null, Action enumerationCompleted = null) + { + _ = enumerable ?? throw new ArgumentNullException(nameof(enumerable)); + + var enumerator = enumerable.GetEnumerator(); + var enumerationTerminated = false; + + while (enumerator.MoveNext()) + { + if (findNextElement?.Invoke(enumerator.Current) == false) + { + enumerationTerminated = true; + break; + } + } + + if (enumerationTerminated == false) + { + enumerationCompleted?.Invoke(); + } + } } } \ No newline at end of file From f635d289e8fc1fab16c4e09d822ee30598cfd249 Mon Sep 17 00:00:00 2001 From: nemec Date: Fri, 18 Mar 2022 13:36:58 +0100 Subject: [PATCH 114/181] Add nms ObjectsComparer.ContextExtensions. --- ObjectsComparer/ObjectsComparer/Comparer~1.cs | 1 + .../Context/ContextableExtensions.cs | 234 +++++++++++++++++ .../Context/IComparerExtensions.cs | 241 +++++++++--------- .../AbstractDynamicObjectsComprer.cs | 1 + .../EnumerablesComparerBase.cs | 3 +- .../GenericEnumerablesComparer.cs | 1 + .../CustomComparers/HashSetsComparer.cs | 1 + .../MultidimensionalArrayComparer~1.cs | 1 + .../MultidimensionalArraysComparer.cs | 1 + 9 files changed, 363 insertions(+), 121 deletions(-) create mode 100644 ObjectsComparer/ObjectsComparer/Context/ContextableExtensions.cs diff --git a/ObjectsComparer/ObjectsComparer/Comparer~1.cs b/ObjectsComparer/ObjectsComparer/Comparer~1.cs index 3191314..7594d59 100644 --- a/ObjectsComparer/ObjectsComparer/Comparer~1.cs +++ b/ObjectsComparer/ObjectsComparer/Comparer~1.cs @@ -3,6 +3,7 @@ using System.Linq; using System.Reflection; using System.Text; +using ObjectsComparer.ContextExtensions; using ObjectsComparer.Utils; namespace ObjectsComparer diff --git a/ObjectsComparer/ObjectsComparer/Context/ContextableExtensions.cs b/ObjectsComparer/ObjectsComparer/Context/ContextableExtensions.cs new file mode 100644 index 0000000..d997c51 --- /dev/null +++ b/ObjectsComparer/ObjectsComparer/Context/ContextableExtensions.cs @@ -0,0 +1,234 @@ +using ObjectsComparer.Exceptions; +using System; +using System.Collections.Generic; + +namespace ObjectsComparer.ContextExtensions +{ + internal class ContextableComparerAdapater : IContextableComparer + { + readonly IComparer _comparer; + + public ContextableComparerAdapater(IComparer comparer) + { + _comparer = comparer ?? throw new ArgumentNullException(nameof(comparer)); + } + + public IEnumerable CalculateDifferences(Type type, object obj1, object obj2, IComparisonContext comparisonContext) + { + if (type is null) + { + throw new ArgumentNullException(nameof(type)); + } + + if (comparisonContext is null) + { + throw new ArgumentNullException(nameof(comparisonContext)); + } + + if (_comparer is IContextableComparer contextableComparer) + { + return contextableComparer.CalculateDifferences(type, obj1, obj2, comparisonContext); + } + + ThrowContextableComparerNotImplemented(comparisonContext, _comparer.Settings, _comparer, nameof(IContextableComparer)); + + return _comparer.CalculateDifferences(obj1, obj2); + } + + static bool HasComparisonContextImplicitRoot(IComparisonContext comparisonContext) + { + if (comparisonContext is null) + { + throw new ArgumentNullException(nameof(comparisonContext)); + } + + do + { + if (comparisonContext.Ancestor == null && comparisonContext is ImplicitComparisonContext) + { + return true; + } + + comparisonContext = comparisonContext.Ancestor; + + } while (comparisonContext != null); + + return false; + } + + static void ThrowContextableComparerNotImplemented(IComparisonContext comparisonContext, ComparisonSettings comparisonSettings, object comparer, string unImplementedInterface) + { + if (comparisonContext is null) + { + throw new ArgumentNullException(nameof(comparisonContext)); + } + + if (comparisonSettings is null) + { + throw new ArgumentNullException(nameof(comparisonSettings)); + } + + var options = ComparisonContextOptions.Default(); + comparisonSettings.ComparisonContextOptionsAction?.Invoke(null, options); + + if (options.ThrowContextableComparerNotImplementedEnabled == false) + { + return; + } + + if (comparisonSettings.ComparisonContextOptionsAction != null) + { + var message = $"Because the comparison context was explicitly configured, the {comparer.GetType().FullName} must implement {unImplementedInterface} interface " + + "or throwing the ContextableComparerNotImplementedException must be disabled."; + throw new ContextableComparerNotImplementedException(message); + } + + if (comparisonSettings.ListComparisonOptionsAction != null) + { + var message = $"Because the list comparison was explicitly configured, the {comparer.GetType().FullName} must implement {unImplementedInterface} interface " + + "or throwing the ContextableComparerNotImplementedException must be disabled."; + throw new ContextableComparerNotImplementedException(message); + } + + //TODO: Check DifferenceOptionsAction + + if (HasComparisonContextImplicitRoot(comparisonContext) == false) + { + var message = $"Because the comparison context was explicitly passed, the {comparer.GetType().FullName} must implement {unImplementedInterface} interface " + + "or throwing the ContextableComparerNotImplementedException must be disabled."; + throw new ContextableComparerNotImplementedException(message); + } + } + } + + public static class ContextableExtensions + { + /// + /// For implementors of . + /// + public static IContextableComparer AsContextable(this IComparer comparer) + { + return new ContextableComparerAdapater(comparer); + } + + /// + /// Calculates list of differences between objects. Accepts comparison context. + /// + public static IEnumerable CalculateDifferences(this IComparer comparer, Type type, object obj1, object obj2, IComparisonContext comparisonContext) + { + if (comparer is null) + { + throw new ArgumentNullException(nameof(comparer)); + } + + if (type is null) + { + throw new ArgumentNullException(nameof(type)); + } + + if (comparisonContext is null) + { + throw new ArgumentNullException(nameof(comparisonContext)); + } + + if (comparer is IContextableComparer contextableComparer) + { + return contextableComparer.CalculateDifferences(type, obj1, obj2, comparisonContext); + } + + ThrowContextableComparerNotImplemented(comparisonContext, comparer.Settings, comparer, nameof(IContextableComparer)); + + return comparer.CalculateDifferences(obj1, obj2); + } + + /// + /// Calculates list of differences between objects. Accepts comparison context. + /// + public static IEnumerable CalculateDifferences(this IComparer comparer, T obj1, T obj2, IComparisonContext comparisonContext) + { + if (comparer is null) + { + throw new ArgumentNullException(nameof(comparer)); + } + + if (comparisonContext is null) + { + throw new ArgumentNullException(nameof(comparisonContext)); + } + + if (comparer is IContextableComparer contextableComparer) + { + return contextableComparer.CalculateDifferences(obj1, obj2, comparisonContext); + } + + ThrowContextableComparerNotImplemented(comparisonContext, comparer.Settings, comparer, $"{nameof(IContextableComparer)}<{typeof(T).FullName}>"); + + return comparer.CalculateDifferences(obj1, obj2); + } + + static bool HasComparisonContextImplicitRoot(IComparisonContext comparisonContext) + { + if (comparisonContext is null) + { + throw new ArgumentNullException(nameof(comparisonContext)); + } + + do + { + if (comparisonContext.Ancestor == null && comparisonContext is ImplicitComparisonContext) + { + return true; + } + + comparisonContext = comparisonContext.Ancestor; + + } while (comparisonContext != null); + + return false; + } + + static void ThrowContextableComparerNotImplemented(IComparisonContext comparisonContext, ComparisonSettings comparisonSettings, object comparer, string unImplementedInterface) + { + if (comparisonContext is null) + { + throw new ArgumentNullException(nameof(comparisonContext)); + } + + if (comparisonSettings is null) + { + throw new ArgumentNullException(nameof(comparisonSettings)); + } + + var options = ComparisonContextOptions.Default(); + comparisonSettings.ComparisonContextOptionsAction?.Invoke(null, options); + + if (options.ThrowContextableComparerNotImplementedEnabled == false) + { + return; + } + + if (comparisonSettings.ComparisonContextOptionsAction != null) + { + var message = $"Because the comparison context was explicitly configured, the {comparer.GetType().FullName} must implement {unImplementedInterface} interface " + + "or throwing the ContextableComparerNotImplementedException must be disabled."; + throw new ContextableComparerNotImplementedException(message); + } + + if (comparisonSettings.ListComparisonOptionsAction != null) + { + var message = $"Because the list comparison was explicitly configured, the {comparer.GetType().FullName} must implement {unImplementedInterface} interface " + + "or throwing the ContextableComparerNotImplementedException must be disabled."; + throw new ContextableComparerNotImplementedException(message); + } + + //TODO: Check DifferenceOptionsAction + + if (HasComparisonContextImplicitRoot(comparisonContext) == false) + { + var message = $"Because the comparison context was explicitly passed, the {comparer.GetType().FullName} must implement {unImplementedInterface} interface " + + "or throwing the ContextableComparerNotImplementedException must be disabled."; + throw new ContextableComparerNotImplementedException(message); + } + } + } +} \ No newline at end of file diff --git a/ObjectsComparer/ObjectsComparer/Context/IComparerExtensions.cs b/ObjectsComparer/ObjectsComparer/Context/IComparerExtensions.cs index fd5de69..5fea3d3 100644 --- a/ObjectsComparer/ObjectsComparer/Context/IComparerExtensions.cs +++ b/ObjectsComparer/ObjectsComparer/Context/IComparerExtensions.cs @@ -1,4 +1,5 @@ -using ObjectsComparer.Exceptions; +using ObjectsComparer.ContextExtensions; +using ObjectsComparer.Exceptions; using System; using System.Collections.Generic; @@ -9,125 +10,125 @@ namespace ObjectsComparer /// public static class IComparerExtensions { - /// - /// Calculates list of differences between objects. Accepts comparison context. - /// - public static IEnumerable CalculateDifferences(this IComparer comparer, Type type, object obj1, object obj2, IComparisonContext comparisonContext) - { - if (comparer is null) - { - throw new ArgumentNullException(nameof(comparer)); - } - - if (type is null) - { - throw new ArgumentNullException(nameof(type)); - } - - if (comparisonContext is null) - { - throw new ArgumentNullException(nameof(comparisonContext)); - } - - if (comparer is IContextableComparer contextableComparer) - { - return contextableComparer.CalculateDifferences(type, obj1, obj2, comparisonContext); - } - - ThrowContextableComparerNotImplemented(comparisonContext, comparer.Settings, comparer, nameof(IContextableComparer)); - - return comparer.CalculateDifferences(obj1, obj2); - } - - /// - /// Calculates list of differences between objects. Accepts comparison context. - /// - public static IEnumerable CalculateDifferences(this IComparer comparer, T obj1, T obj2, IComparisonContext comparisonContext) - { - if (comparer is null) - { - throw new ArgumentNullException(nameof(comparer)); - } - - if (comparisonContext is null) - { - throw new ArgumentNullException(nameof(comparisonContext)); - } - - if (comparer is IContextableComparer contextableComparer) - { - return contextableComparer.CalculateDifferences(obj1, obj2, comparisonContext); - } - - ThrowContextableComparerNotImplemented(comparisonContext, comparer.Settings, comparer, $"{nameof(IContextableComparer)}<{typeof(T).FullName}>"); - - return comparer.CalculateDifferences(obj1, obj2); - } - - static bool HasComparisonContextImplicitRoot(IComparisonContext comparisonContext) - { - if (comparisonContext is null) - { - throw new ArgumentNullException(nameof(comparisonContext)); - } - - do - { - if (comparisonContext.Ancestor == null && comparisonContext is ImplicitComparisonContext) - { - return true; - } - - comparisonContext = comparisonContext.Ancestor; - - } while (comparisonContext != null); - - return false; - } - - static void ThrowContextableComparerNotImplemented(IComparisonContext comparisonContext, ComparisonSettings comparisonSettings, object comparer, string unImplementedInterface) - { - if (comparisonContext is null) - { - throw new ArgumentNullException(nameof(comparisonContext)); - } - - if (comparisonSettings is null) - { - throw new ArgumentNullException(nameof(comparisonSettings)); - } - - var options = ComparisonContextOptions.Default(); - comparisonSettings.ComparisonContextOptionsAction?.Invoke(null, options); - - if (options.ThrowContextableComparerNotImplementedEnabled == false) - { - return; - } - - if (comparisonSettings.ComparisonContextOptionsAction != null) - { - var message = $"Because the comparison context was explicitly configured, the {comparer.GetType().FullName} must implement {unImplementedInterface} interface " + - "or throwing the ContextableComparerNotImplementedException must be disabled."; - throw new ContextableComparerNotImplementedException(message); - } - - if (comparisonSettings.ListComparisonOptionsAction != null) - { - var message = $"Because the list comparison was explicitly configured, the {comparer.GetType().FullName} must implement {unImplementedInterface} interface " + - "or throwing the ContextableComparerNotImplementedException must be disabled."; - throw new ContextableComparerNotImplementedException(message); - } - - //TODO: Check DifferenceOptionsAction - - if (HasComparisonContextImplicitRoot(comparisonContext) == false) - { - var message = $"Because the comparison context was explicitly passed, the {comparer.GetType().FullName} must implement {unImplementedInterface} interface " + - "or throwing the ContextableComparerNotImplementedException must be disabled."; - throw new ContextableComparerNotImplementedException(message); - } - } + ///// + ///// Calculates list of differences between objects. Accepts comparison context. + ///// + //public static IEnumerable CalculateDifferences(this IComparer comparer, Type type, object obj1, object obj2, IComparisonContext comparisonContext) + //{ + // if (comparer is null) + // { + // throw new ArgumentNullException(nameof(comparer)); + // } + + // if (type is null) + // { + // throw new ArgumentNullException(nameof(type)); + // } + + // if (comparisonContext is null) + // { + // throw new ArgumentNullException(nameof(comparisonContext)); + // } + + // if (comparer is IContextableComparer contextableComparer) + // { + // return contextableComparer.CalculateDifferences(type, obj1, obj2, comparisonContext); + // } + + // ThrowContextableComparerNotImplemented(comparisonContext, comparer.Settings, comparer, nameof(IContextableComparer)); + + // return comparer.CalculateDifferences(obj1, obj2); + //} + + ///// + ///// Calculates list of differences between objects. Accepts comparison context. + ///// + //public static IEnumerable CalculateDifferences(this IComparer comparer, T obj1, T obj2, IComparisonContext comparisonContext) + //{ + // if (comparer is null) + // { + // throw new ArgumentNullException(nameof(comparer)); + // } + + // if (comparisonContext is null) + // { + // throw new ArgumentNullException(nameof(comparisonContext)); + // } + + // if (comparer is IContextableComparer contextableComparer) + // { + // return contextableComparer.CalculateDifferences(obj1, obj2, comparisonContext); + // } + + // ThrowContextableComparerNotImplemented(comparisonContext, comparer.Settings, comparer, $"{nameof(IContextableComparer)}<{typeof(T).FullName}>"); + + // return comparer.CalculateDifferences(obj1, obj2); + //} + + //static bool HasComparisonContextImplicitRoot(IComparisonContext comparisonContext) + //{ + // if (comparisonContext is null) + // { + // throw new ArgumentNullException(nameof(comparisonContext)); + // } + + // do + // { + // if (comparisonContext.Ancestor == null && comparisonContext is ImplicitComparisonContext) + // { + // return true; + // } + + // comparisonContext = comparisonContext.Ancestor; + + // } while (comparisonContext != null); + + // return false; + //} + + //static void ThrowContextableComparerNotImplemented(IComparisonContext comparisonContext, ComparisonSettings comparisonSettings, object comparer, string unImplementedInterface) + //{ + // if (comparisonContext is null) + // { + // throw new ArgumentNullException(nameof(comparisonContext)); + // } + + // if (comparisonSettings is null) + // { + // throw new ArgumentNullException(nameof(comparisonSettings)); + // } + + // var options = ComparisonContextOptions.Default(); + // comparisonSettings.ComparisonContextOptionsAction?.Invoke(null, options); + + // if (options.ThrowContextableComparerNotImplementedEnabled == false) + // { + // return; + // } + + // if (comparisonSettings.ComparisonContextOptionsAction != null) + // { + // var message = $"Because the comparison context was explicitly configured, the {comparer.GetType().FullName} must implement {unImplementedInterface} interface " + + // "or throwing the ContextableComparerNotImplementedException must be disabled."; + // throw new ContextableComparerNotImplementedException(message); + // } + + // if (comparisonSettings.ListComparisonOptionsAction != null) + // { + // var message = $"Because the list comparison was explicitly configured, the {comparer.GetType().FullName} must implement {unImplementedInterface} interface " + + // "or throwing the ContextableComparerNotImplementedException must be disabled."; + // throw new ContextableComparerNotImplementedException(message); + // } + + // //TODO: Check DifferenceOptionsAction + + // if (HasComparisonContextImplicitRoot(comparisonContext) == false) + // { + // var message = $"Because the comparison context was explicitly passed, the {comparer.GetType().FullName} must implement {unImplementedInterface} interface " + + // "or throwing the ContextableComparerNotImplementedException must be disabled."; + // throw new ContextableComparerNotImplementedException(message); + // } + //} public static IComparisonContext CalculateDifferences(this IComparer comparer, Type type, object obj1, object obj2, Func findNextDifference = null, Action contextCompleted = null) { diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractDynamicObjectsComprer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractDynamicObjectsComprer.cs index 0ffc9a0..cd996ff 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractDynamicObjectsComprer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractDynamicObjectsComprer.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using System.Reflection; +using ObjectsComparer.ContextExtensions; using ObjectsComparer.Utils; namespace ObjectsComparer diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparerBase.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparerBase.cs index c43e588..188203c 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparerBase.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparerBase.cs @@ -1,4 +1,5 @@ -using ObjectsComparer.Exceptions; +using ObjectsComparer.ContextExtensions; +using ObjectsComparer.Exceptions; using System; using System.Collections.Generic; using System.Diagnostics; diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/GenericEnumerablesComparer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/GenericEnumerablesComparer.cs index f7dfa20..91fe169 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/GenericEnumerablesComparer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/GenericEnumerablesComparer.cs @@ -3,6 +3,7 @@ using System.Collections.ObjectModel; using System.Linq; using System.Reflection; +using ObjectsComparer.ContextExtensions; using ObjectsComparer.Utils; namespace ObjectsComparer diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/HashSetsComparer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/HashSetsComparer.cs index f011ed7..9b3aec2 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/HashSetsComparer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/HashSetsComparer.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using System.Reflection; +using ObjectsComparer.ContextExtensions; using ObjectsComparer.Utils; namespace ObjectsComparer diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/MultidimensionalArrayComparer~1.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/MultidimensionalArrayComparer~1.cs index dd530c8..5ff2447 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/MultidimensionalArrayComparer~1.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/MultidimensionalArrayComparer~1.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using ObjectsComparer.ContextExtensions; using ObjectsComparer.Utils; namespace ObjectsComparer diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/MultidimensionalArraysComparer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/MultidimensionalArraysComparer.cs index 5aff3e2..be1bee2 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/MultidimensionalArraysComparer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/MultidimensionalArraysComparer.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Reflection; +using ObjectsComparer.ContextExtensions; using ObjectsComparer.Utils; namespace ObjectsComparer From f1665e2785a155d6763b1387e3ce75623b48b310 Mon Sep 17 00:00:00 2001 From: Daniel Nemec Date: Sun, 20 Mar 2022 18:17:54 +0100 Subject: [PATCH 115/181] Remove ContextableComparerAdapater. --- .../Example4/Example4Tests.cs | 4 +- .../Context/ComparerExtensions.cs | 87 +++++++++ .../Context/ContextableExtensions.cs | 107 +---------- .../Context/IComparerExtensions.cs | 180 ------------------ 4 files changed, 91 insertions(+), 287 deletions(-) create mode 100644 ObjectsComparer/ObjectsComparer/Context/ComparerExtensions.cs delete mode 100644 ObjectsComparer/ObjectsComparer/Context/IComparerExtensions.cs diff --git a/ObjectsComparer/ObjectsComparer.Examples/Example4/Example4Tests.cs b/ObjectsComparer/ObjectsComparer.Examples/Example4/Example4Tests.cs index 3f7b07d..48cfd10 100644 --- a/ObjectsComparer/ObjectsComparer.Examples/Example4/Example4Tests.cs +++ b/ObjectsComparer/ObjectsComparer.Examples/Example4/Example4Tests.cs @@ -100,8 +100,8 @@ public void List_Of_Equal_Sizes_But_Is_Inequality_Test_Ctx() } }; - var ctx = new ComparisonContext(); - var differences = _comparer.CalculateDifferences(formula1, formula2, ctx).ToArray(); + var rootContext = _comparer.CalculateContextableDifferences(formula1, formula2); + var differences = rootContext.GetDifferences(true); Assert.AreEqual(3, differences.Count()); Assert.IsTrue(differences.Any(d => d.MemberPath == "Items[Id=1].Delay" && d.Value1 == "60" && d.Value2 == "80")); diff --git a/ObjectsComparer/ObjectsComparer/Context/ComparerExtensions.cs b/ObjectsComparer/ObjectsComparer/Context/ComparerExtensions.cs new file mode 100644 index 0000000..5c5ed46 --- /dev/null +++ b/ObjectsComparer/ObjectsComparer/Context/ComparerExtensions.cs @@ -0,0 +1,87 @@ +using ObjectsComparer.ContextExtensions; +using ObjectsComparer.Exceptions; +using System; +using System.Collections.Generic; + +namespace ObjectsComparer +{ + public static class ComparerExtensions + { + /// + /// Calculates list of differences between objects. Accepts comparison context. + /// + public static IComparisonContext CalculateDifferences(this IComparer comparer, Type type, object obj1, object obj2, Func findNextDifference = null, Action contextCompleted = null) + { + if (comparer is null) + { + throw new ArgumentNullException(nameof(comparer)); + } + + if (type is null) + { + throw new ArgumentNullException(nameof(type)); + } + + var rootCtx = ComparisonContextProvider.CreateContext(comparer.Settings, ancestor: null); + + var differences = comparer.CalculateDifferences(type, obj1, obj2, rootCtx); + + differences.EnumerateConditional( + currentDifference => + { + return findNextDifference(null, currentDifference); + }, + contextCompleted); + + return rootCtx; + } + + /// + /// Calculates list of differences between objects. Accepts comparison context. + /// + public static IComparisonContext CalculateContextableDifferences(this IComparer comparer, T obj1, T obj2, Func findNextDifference = null, Action contextCompleted = null) + { + if (comparer is null) + { + throw new ArgumentNullException(nameof(comparer)); + } + + findNextDifference = findNextDifference ?? ((ctx, _) => true); + + var rootCtx = ComparisonContextProvider.CreateContext(comparer.Settings, ancestor: null); + + var differences = comparer.CalculateDifferences(obj1, obj2, rootCtx); + + differences.EnumerateConditional( + currentDifference => + { + return findNextDifference(null, currentDifference); + }, + contextCompleted); + + return rootCtx; + } + + internal static void EnumerateConditional(this IEnumerable enumerable, Func findNextElement = null, Action enumerationCompleted = null) + { + _ = enumerable ?? throw new ArgumentNullException(nameof(enumerable)); + + var enumerator = enumerable.GetEnumerator(); + var enumerationTerminated = false; + + while (enumerator.MoveNext()) + { + if (findNextElement?.Invoke(enumerator.Current) == false) + { + enumerationTerminated = true; + break; + } + } + + if (enumerationTerminated == false) + { + enumerationCompleted?.Invoke(); + } + } + } +} \ No newline at end of file diff --git a/ObjectsComparer/ObjectsComparer/Context/ContextableExtensions.cs b/ObjectsComparer/ObjectsComparer/Context/ContextableExtensions.cs index d997c51..951478c 100644 --- a/ObjectsComparer/ObjectsComparer/Context/ContextableExtensions.cs +++ b/ObjectsComparer/ObjectsComparer/Context/ContextableExtensions.cs @@ -4,116 +4,12 @@ namespace ObjectsComparer.ContextExtensions { - internal class ContextableComparerAdapater : IContextableComparer - { - readonly IComparer _comparer; - - public ContextableComparerAdapater(IComparer comparer) - { - _comparer = comparer ?? throw new ArgumentNullException(nameof(comparer)); - } - - public IEnumerable CalculateDifferences(Type type, object obj1, object obj2, IComparisonContext comparisonContext) - { - if (type is null) - { - throw new ArgumentNullException(nameof(type)); - } - - if (comparisonContext is null) - { - throw new ArgumentNullException(nameof(comparisonContext)); - } - - if (_comparer is IContextableComparer contextableComparer) - { - return contextableComparer.CalculateDifferences(type, obj1, obj2, comparisonContext); - } - - ThrowContextableComparerNotImplemented(comparisonContext, _comparer.Settings, _comparer, nameof(IContextableComparer)); - - return _comparer.CalculateDifferences(obj1, obj2); - } - - static bool HasComparisonContextImplicitRoot(IComparisonContext comparisonContext) - { - if (comparisonContext is null) - { - throw new ArgumentNullException(nameof(comparisonContext)); - } - - do - { - if (comparisonContext.Ancestor == null && comparisonContext is ImplicitComparisonContext) - { - return true; - } - - comparisonContext = comparisonContext.Ancestor; - - } while (comparisonContext != null); - - return false; - } - - static void ThrowContextableComparerNotImplemented(IComparisonContext comparisonContext, ComparisonSettings comparisonSettings, object comparer, string unImplementedInterface) - { - if (comparisonContext is null) - { - throw new ArgumentNullException(nameof(comparisonContext)); - } - - if (comparisonSettings is null) - { - throw new ArgumentNullException(nameof(comparisonSettings)); - } - - var options = ComparisonContextOptions.Default(); - comparisonSettings.ComparisonContextOptionsAction?.Invoke(null, options); - - if (options.ThrowContextableComparerNotImplementedEnabled == false) - { - return; - } - - if (comparisonSettings.ComparisonContextOptionsAction != null) - { - var message = $"Because the comparison context was explicitly configured, the {comparer.GetType().FullName} must implement {unImplementedInterface} interface " + - "or throwing the ContextableComparerNotImplementedException must be disabled."; - throw new ContextableComparerNotImplementedException(message); - } - - if (comparisonSettings.ListComparisonOptionsAction != null) - { - var message = $"Because the list comparison was explicitly configured, the {comparer.GetType().FullName} must implement {unImplementedInterface} interface " + - "or throwing the ContextableComparerNotImplementedException must be disabled."; - throw new ContextableComparerNotImplementedException(message); - } - - //TODO: Check DifferenceOptionsAction - - if (HasComparisonContextImplicitRoot(comparisonContext) == false) - { - var message = $"Because the comparison context was explicitly passed, the {comparer.GetType().FullName} must implement {unImplementedInterface} interface " + - "or throwing the ContextableComparerNotImplementedException must be disabled."; - throw new ContextableComparerNotImplementedException(message); - } - } - } - public static class ContextableExtensions { - /// - /// For implementors of . - /// - public static IContextableComparer AsContextable(this IComparer comparer) - { - return new ContextableComparerAdapater(comparer); - } - /// /// Calculates list of differences between objects. Accepts comparison context. /// + /// The method is intended for IContextableComparer implementers. public static IEnumerable CalculateDifferences(this IComparer comparer, Type type, object obj1, object obj2, IComparisonContext comparisonContext) { if (comparer is null) @@ -144,6 +40,7 @@ public static IEnumerable CalculateDifferences(this IComparer compar /// /// Calculates list of differences between objects. Accepts comparison context. /// + /// The method is intended for IContextableComparer implementers. public static IEnumerable CalculateDifferences(this IComparer comparer, T obj1, T obj2, IComparisonContext comparisonContext) { if (comparer is null) diff --git a/ObjectsComparer/ObjectsComparer/Context/IComparerExtensions.cs b/ObjectsComparer/ObjectsComparer/Context/IComparerExtensions.cs deleted file mode 100644 index 5fea3d3..0000000 --- a/ObjectsComparer/ObjectsComparer/Context/IComparerExtensions.cs +++ /dev/null @@ -1,180 +0,0 @@ -using ObjectsComparer.ContextExtensions; -using ObjectsComparer.Exceptions; -using System; -using System.Collections.Generic; - -namespace ObjectsComparer -{ - /// - /// Extends interface . - /// - public static class IComparerExtensions - { - ///// - ///// Calculates list of differences between objects. Accepts comparison context. - ///// - //public static IEnumerable CalculateDifferences(this IComparer comparer, Type type, object obj1, object obj2, IComparisonContext comparisonContext) - //{ - // if (comparer is null) - // { - // throw new ArgumentNullException(nameof(comparer)); - // } - - // if (type is null) - // { - // throw new ArgumentNullException(nameof(type)); - // } - - // if (comparisonContext is null) - // { - // throw new ArgumentNullException(nameof(comparisonContext)); - // } - - // if (comparer is IContextableComparer contextableComparer) - // { - // return contextableComparer.CalculateDifferences(type, obj1, obj2, comparisonContext); - // } - - // ThrowContextableComparerNotImplemented(comparisonContext, comparer.Settings, comparer, nameof(IContextableComparer)); - - // return comparer.CalculateDifferences(obj1, obj2); - //} - - ///// - ///// Calculates list of differences between objects. Accepts comparison context. - ///// - //public static IEnumerable CalculateDifferences(this IComparer comparer, T obj1, T obj2, IComparisonContext comparisonContext) - //{ - // if (comparer is null) - // { - // throw new ArgumentNullException(nameof(comparer)); - // } - - // if (comparisonContext is null) - // { - // throw new ArgumentNullException(nameof(comparisonContext)); - // } - - // if (comparer is IContextableComparer contextableComparer) - // { - // return contextableComparer.CalculateDifferences(obj1, obj2, comparisonContext); - // } - - // ThrowContextableComparerNotImplemented(comparisonContext, comparer.Settings, comparer, $"{nameof(IContextableComparer)}<{typeof(T).FullName}>"); - - // return comparer.CalculateDifferences(obj1, obj2); - //} - - //static bool HasComparisonContextImplicitRoot(IComparisonContext comparisonContext) - //{ - // if (comparisonContext is null) - // { - // throw new ArgumentNullException(nameof(comparisonContext)); - // } - - // do - // { - // if (comparisonContext.Ancestor == null && comparisonContext is ImplicitComparisonContext) - // { - // return true; - // } - - // comparisonContext = comparisonContext.Ancestor; - - // } while (comparisonContext != null); - - // return false; - //} - - //static void ThrowContextableComparerNotImplemented(IComparisonContext comparisonContext, ComparisonSettings comparisonSettings, object comparer, string unImplementedInterface) - //{ - // if (comparisonContext is null) - // { - // throw new ArgumentNullException(nameof(comparisonContext)); - // } - - // if (comparisonSettings is null) - // { - // throw new ArgumentNullException(nameof(comparisonSettings)); - // } - - // var options = ComparisonContextOptions.Default(); - // comparisonSettings.ComparisonContextOptionsAction?.Invoke(null, options); - - // if (options.ThrowContextableComparerNotImplementedEnabled == false) - // { - // return; - // } - - // if (comparisonSettings.ComparisonContextOptionsAction != null) - // { - // var message = $"Because the comparison context was explicitly configured, the {comparer.GetType().FullName} must implement {unImplementedInterface} interface " + - // "or throwing the ContextableComparerNotImplementedException must be disabled."; - // throw new ContextableComparerNotImplementedException(message); - // } - - // if (comparisonSettings.ListComparisonOptionsAction != null) - // { - // var message = $"Because the list comparison was explicitly configured, the {comparer.GetType().FullName} must implement {unImplementedInterface} interface " + - // "or throwing the ContextableComparerNotImplementedException must be disabled."; - // throw new ContextableComparerNotImplementedException(message); - // } - - // //TODO: Check DifferenceOptionsAction - - // if (HasComparisonContextImplicitRoot(comparisonContext) == false) - // { - // var message = $"Because the comparison context was explicitly passed, the {comparer.GetType().FullName} must implement {unImplementedInterface} interface " + - // "or throwing the ContextableComparerNotImplementedException must be disabled."; - // throw new ContextableComparerNotImplementedException(message); - // } - //} - - public static IComparisonContext CalculateDifferences(this IComparer comparer, Type type, object obj1, object obj2, Func findNextDifference = null, Action contextCompleted = null) - { - if (comparer is null) - { - throw new ArgumentNullException(nameof(comparer)); - } - - if (type is null) - { - throw new ArgumentNullException(nameof(type)); - } - - var rootCtx = ComparisonContextProvider.CreateContext(comparer.Settings, ancestor: null); - var differences = comparer.CalculateDifferences(type, obj1, obj2, rootCtx); - - differences.EnumerateConditional( - currentDifference => - { - return findNextDifference(null, currentDifference); - }, - contextCompleted); - - return rootCtx; - } - - internal static void EnumerateConditional(this IEnumerable enumerable, Func findNextElement = null, Action enumerationCompleted = null) - { - _ = enumerable ?? throw new ArgumentNullException(nameof(enumerable)); - - var enumerator = enumerable.GetEnumerator(); - var enumerationTerminated = false; - - while (enumerator.MoveNext()) - { - if (findNextElement?.Invoke(enumerator.Current) == false) - { - enumerationTerminated = true; - break; - } - } - - if (enumerationTerminated == false) - { - enumerationCompleted?.Invoke(); - } - } - } -} \ No newline at end of file From ffd5542f8dbcf3d87584015fd7233bd58d0aa3c5 Mon Sep 17 00:00:00 2001 From: Daniel Nemec Date: Sun, 27 Mar 2022 18:59:47 +0200 Subject: [PATCH 116/181] Add DifferenceTreeNodeInfo. --- .../ObjectsComparer/BaseComparer.cs | 5 +-- ObjectsComparer/ObjectsComparer/Comparer~1.cs | 11 +++--- .../Context/ContextableExtensions.cs | 34 +++++++++++++++---- .../Context/DifferenceTreeNodeInfo.cs | 20 +++++++++++ .../Context/IContextableComparer.cs | 4 +-- .../Context/IContextableComparer~1.cs | 4 +-- ObjectsComparer/ObjectsComparer/Difference.cs | 1 + 7 files changed, 63 insertions(+), 16 deletions(-) create mode 100644 ObjectsComparer/ObjectsComparer/Context/DifferenceTreeNodeInfo.cs diff --git a/ObjectsComparer/ObjectsComparer/BaseComparer.cs b/ObjectsComparer/ObjectsComparer/BaseComparer.cs index 454b5f4..74cfce8 100644 --- a/ObjectsComparer/ObjectsComparer/BaseComparer.cs +++ b/ObjectsComparer/ObjectsComparer/BaseComparer.cs @@ -2,6 +2,7 @@ using System.Linq.Expressions; using System.Reflection; using ObjectsComparer.Utils; +using ObjectsComparer.ContextExtensions; namespace ObjectsComparer { @@ -188,7 +189,7 @@ public void IgnoreMember(Func filter) /// Adds an to the end of the 's . /// /// The argument. - protected virtual Difference AddDifferenceToComparisonContext(Difference difference, IComparisonContext comparisonContext) + protected virtual DifferenceTreeNodeInfo AddDifferenceToComparisonContext(Difference difference, IComparisonContext comparisonContext) { if (difference is null) { @@ -202,7 +203,7 @@ protected virtual Difference AddDifferenceToComparisonContext(Difference differe comparisonContext.AddDifference(difference); - return difference; + return new DifferenceTreeNodeInfo(difference, comparisonContext); } } } \ No newline at end of file diff --git a/ObjectsComparer/ObjectsComparer/Comparer~1.cs b/ObjectsComparer/ObjectsComparer/Comparer~1.cs index 7594d59..011c0b6 100644 --- a/ObjectsComparer/ObjectsComparer/Comparer~1.cs +++ b/ObjectsComparer/ObjectsComparer/Comparer~1.cs @@ -59,15 +59,17 @@ public override IEnumerable CalculateDifferences(T obj1, T obj2) public IEnumerable CalculateDifferences(T obj1, T obj2, IComparisonContext comparisonContext) { - return CalculateDifferences(obj1, obj2, memberInfo: null, comparisonContext); + return CalculateDifferences(obj1, obj2, memberInfo: null, comparisonContext) + .Select(differenceTreeNodeInfo => differenceTreeNodeInfo.Difference); } internal IEnumerable CalculateDifferences(T obj1, T obj2, MemberInfo memberInfo) { - return CalculateDifferences(obj1, obj2, memberInfo, ComparisonContextProvider.CreateImplicitRootContext(Settings)); + return CalculateDifferences(obj1, obj2, memberInfo, ComparisonContextProvider.CreateImplicitRootContext(Settings)) + .Select(differenceTreeNodeInfo => differenceTreeNodeInfo.Difference); } - IEnumerable CalculateDifferences(T obj1, T obj2, MemberInfo memberInfo, IComparisonContext comparisonContext) + IEnumerable CalculateDifferences(T obj1, T obj2, MemberInfo memberInfo, IComparisonContext comparisonContext) { var comparer = memberInfo != null ? OverridesCollection.GetComparer(memberInfo) @@ -144,7 +146,8 @@ IEnumerable CalculateDifferences(T obj1, T obj2, MemberInfo memberIn foreach (var failure in objectDataComparer.CalculateDifferences(type, value1, value2, memberContext)) { - yield return failure.InsertPath(member.Name); + failure.Difference.InsertPath(member.Name); + yield return failure; } continue; diff --git a/ObjectsComparer/ObjectsComparer/Context/ContextableExtensions.cs b/ObjectsComparer/ObjectsComparer/Context/ContextableExtensions.cs index 951478c..447cbb0 100644 --- a/ObjectsComparer/ObjectsComparer/Context/ContextableExtensions.cs +++ b/ObjectsComparer/ObjectsComparer/Context/ContextableExtensions.cs @@ -1,5 +1,6 @@ using ObjectsComparer.Exceptions; using System; +using System.Linq; using System.Collections.Generic; namespace ObjectsComparer.ContextExtensions @@ -10,7 +11,7 @@ public static class ContextableExtensions /// Calculates list of differences between objects. Accepts comparison context. /// /// The method is intended for IContextableComparer implementers. - public static IEnumerable CalculateDifferences(this IComparer comparer, Type type, object obj1, object obj2, IComparisonContext comparisonContext) + public static IEnumerable CalculateDifferences(this IComparer comparer, Type type, object obj1, object obj2, IComparisonContext comparisonContext) { if (comparer is null) { @@ -29,19 +30,30 @@ public static IEnumerable CalculateDifferences(this IComparer compar if (comparer is IContextableComparer contextableComparer) { - return contextableComparer.CalculateDifferences(type, obj1, obj2, comparisonContext); + var differenceTreeNodeInfoList = contextableComparer.CalculateDifferences(type, obj1, obj2, comparisonContext); + + foreach (var differenceTreeNodeInfo in differenceTreeNodeInfoList) + { + yield return differenceTreeNodeInfo; + } } ThrowContextableComparerNotImplemented(comparisonContext, comparer.Settings, comparer, nameof(IContextableComparer)); - return comparer.CalculateDifferences(obj1, obj2); + var differences = comparer.CalculateDifferences(type, obj1, obj2); + + foreach (var difference in differences) + { + yield return new DifferenceTreeNodeInfo(difference); + } + } /// /// Calculates list of differences between objects. Accepts comparison context. /// /// The method is intended for IContextableComparer implementers. - public static IEnumerable CalculateDifferences(this IComparer comparer, T obj1, T obj2, IComparisonContext comparisonContext) + public static IEnumerable CalculateDifferences(this IComparer comparer, T obj1, T obj2, IComparisonContext comparisonContext) { if (comparer is null) { @@ -55,12 +67,22 @@ public static IEnumerable CalculateDifferences(this IComparer if (comparer is IContextableComparer contextableComparer) { - return contextableComparer.CalculateDifferences(obj1, obj2, comparisonContext); + var differenceTreeNodeInfoList = contextableComparer.CalculateDifferences(obj1, obj2, comparisonContext); + + foreach (var differenceTreeNodeInfo in differenceTreeNodeInfoList) + { + yield return differenceTreeNodeInfo; + } } ThrowContextableComparerNotImplemented(comparisonContext, comparer.Settings, comparer, $"{nameof(IContextableComparer)}<{typeof(T).FullName}>"); - return comparer.CalculateDifferences(obj1, obj2); + var differences = comparer.CalculateDifferences(obj1, obj2); + + foreach (var difference in differences) + { + yield return new DifferenceTreeNodeInfo(difference); + } } static bool HasComparisonContextImplicitRoot(IComparisonContext comparisonContext) diff --git a/ObjectsComparer/ObjectsComparer/Context/DifferenceTreeNodeInfo.cs b/ObjectsComparer/ObjectsComparer/Context/DifferenceTreeNodeInfo.cs new file mode 100644 index 0000000..08d2f38 --- /dev/null +++ b/ObjectsComparer/ObjectsComparer/Context/DifferenceTreeNodeInfo.cs @@ -0,0 +1,20 @@ +using System; + +namespace ObjectsComparer.ContextExtensions +{ + /// + /// The location of the in the difference tree. + /// + public class DifferenceTreeNodeInfo + { + public DifferenceTreeNodeInfo(Difference difference, IComparisonContext treeNode = null) + { + Difference = difference ?? throw new ArgumentNullException(nameof(difference)); + TreeNode = treeNode; + } + + public Difference Difference { get; } + + public IComparisonContext TreeNode { get; } + } +} \ No newline at end of file diff --git a/ObjectsComparer/ObjectsComparer/Context/IContextableComparer.cs b/ObjectsComparer/ObjectsComparer/Context/IContextableComparer.cs index 648bb2d..c929846 100644 --- a/ObjectsComparer/ObjectsComparer/Context/IContextableComparer.cs +++ b/ObjectsComparer/ObjectsComparer/Context/IContextableComparer.cs @@ -1,13 +1,13 @@ using System; using System.Collections.Generic; -namespace ObjectsComparer +namespace ObjectsComparer.ContextExtensions { /// /// Comparer accepting . /// public interface IContextableComparer { - IEnumerable CalculateDifferences(Type type, object obj1, object obj2, IComparisonContext comparisonContext); + IEnumerable CalculateDifferences(Type type, object obj1, object obj2, IComparisonContext comparisonContext); } } \ No newline at end of file diff --git a/ObjectsComparer/ObjectsComparer/Context/IContextableComparer~1.cs b/ObjectsComparer/ObjectsComparer/Context/IContextableComparer~1.cs index eddfa04..1e8d1fe 100644 --- a/ObjectsComparer/ObjectsComparer/Context/IContextableComparer~1.cs +++ b/ObjectsComparer/ObjectsComparer/Context/IContextableComparer~1.cs @@ -1,13 +1,13 @@ using System; using System.Collections.Generic; -namespace ObjectsComparer +namespace ObjectsComparer.ContextExtensions { /// /// Comparer accepting . /// public interface IContextableComparer { - IEnumerable CalculateDifferences(T obj1, T obj2, IComparisonContext comparisonContext); + IEnumerable CalculateDifferences(T obj1, T obj2, IComparisonContext comparisonContext); } } diff --git a/ObjectsComparer/ObjectsComparer/Difference.cs b/ObjectsComparer/ObjectsComparer/Difference.cs index c84f911..2bbc141 100644 --- a/ObjectsComparer/ObjectsComparer/Difference.cs +++ b/ObjectsComparer/ObjectsComparer/Difference.cs @@ -52,6 +52,7 @@ public Difference InsertPath(string path) ? path + MemberPath : path + "." + MemberPath; + //This instance is probably already included in the difference tree, so I can't create a new one. //return new Difference( // newPath, // Value1, From c60bbeb3bf98598687574b8e71ffb8950b25ba7e Mon Sep 17 00:00:00 2001 From: nemec Date: Fri, 1 Apr 2022 17:44:40 +0200 Subject: [PATCH 117/181] Apply DifferenceLocation to all IContextableComparer implementers. --- .../ObjectsComparer/BaseComparer.cs | 6 ++-- ObjectsComparer/ObjectsComparer/Comparer.cs | 8 +++-- ObjectsComparer/ObjectsComparer/Comparer~1.cs | 15 +++++----- .../Context/ComparerExtensions.cs | 22 +++++++------- .../Context/ContextableExtensions.cs | 9 +++--- .../Context/DifferenceTreeNodeInfo.cs | 6 ++-- .../Context/IContextableComparer.cs | 2 +- .../Context/IContextableComparer~1.cs | 2 +- .../AbstractDynamicObjectsComprer.cs | 29 ++++++++++++------- .../AbstractEnumerablesComparer.cs | 3 +- .../CustomComparers/EnumerablesComparer.cs | 14 +++++---- .../EnumerablesComparerBase.cs | 28 +++++++++--------- .../CustomComparers/EnumerablesComparer~1.cs | 12 ++++---- .../GenericEnumerablesComparer.cs | 5 ++-- .../CustomComparers/HashSetsComparer.cs | 5 ++-- .../CustomComparers/HashSetsComparer~1.cs | 12 ++++---- .../MultidimensionalArrayComparer~1.cs | 14 +++++---- .../MultidimensionalArraysComparer.cs | 6 ++-- .../CustomComparers/TypesComparer.cs | 9 ++++-- 19 files changed, 118 insertions(+), 89 deletions(-) diff --git a/ObjectsComparer/ObjectsComparer/BaseComparer.cs b/ObjectsComparer/ObjectsComparer/BaseComparer.cs index 74cfce8..95fc192 100644 --- a/ObjectsComparer/ObjectsComparer/BaseComparer.cs +++ b/ObjectsComparer/ObjectsComparer/BaseComparer.cs @@ -188,8 +188,8 @@ public void IgnoreMember(Func filter) /// /// Adds an to the end of the 's . /// - /// The argument. - protected virtual DifferenceTreeNodeInfo AddDifferenceToComparisonContext(Difference difference, IComparisonContext comparisonContext) + /// The instance. + protected virtual DifferenceLocation AddDifferenceToTree(Difference difference, IComparisonContext comparisonContext) { if (difference is null) { @@ -203,7 +203,7 @@ protected virtual DifferenceTreeNodeInfo AddDifferenceToComparisonContext(Differ comparisonContext.AddDifference(difference); - return new DifferenceTreeNodeInfo(difference, comparisonContext); + return new DifferenceLocation(difference, comparisonContext); } } } \ No newline at end of file diff --git a/ObjectsComparer/ObjectsComparer/Comparer.cs b/ObjectsComparer/ObjectsComparer/Comparer.cs index e82d45c..2de2bbe 100644 --- a/ObjectsComparer/ObjectsComparer/Comparer.cs +++ b/ObjectsComparer/ObjectsComparer/Comparer.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using System.Reflection; +using ObjectsComparer.ContextExtensions; using ObjectsComparer.Utils; namespace ObjectsComparer @@ -29,10 +30,11 @@ public Comparer(ComparisonSettings settings = null, BaseComparer parentComparer public override IEnumerable CalculateDifferences(Type type, object obj1, object obj2) { - return CalculateDifferences(type, obj1, obj2, ComparisonContextProvider.CreateImplicitRootContext(Settings)); + return CalculateDifferences(type, obj1, obj2, ComparisonContextProvider.CreateImplicitRootContext(Settings)) + .Select(differenceLoccation => differenceLoccation.Difference); } - public IEnumerable CalculateDifferences(Type type, object obj1, object obj2, IComparisonContext comparisonContext) + public IEnumerable CalculateDifferences(Type type, object obj1, object obj2, IComparisonContext comparisonContext) { if (comparisonContext is null) { @@ -60,7 +62,7 @@ public IEnumerable CalculateDifferences(Type type, object obj1, obje var genericMethodParameters = comparerIsIContextableComparerT ? new[] { obj1, obj2, comparisonContext } : new[] { obj1, obj2 }; // ReSharper disable once PossibleNullReferenceException - return (IEnumerable)genericMethod.Invoke(comparer, genericMethodParameters); + return (IEnumerable)genericMethod.Invoke(comparer, genericMethodParameters); } } } diff --git a/ObjectsComparer/ObjectsComparer/Comparer~1.cs b/ObjectsComparer/ObjectsComparer/Comparer~1.cs index 011c0b6..76573aa 100644 --- a/ObjectsComparer/ObjectsComparer/Comparer~1.cs +++ b/ObjectsComparer/ObjectsComparer/Comparer~1.cs @@ -57,19 +57,18 @@ public override IEnumerable CalculateDifferences(T obj1, T obj2) return CalculateDifferences(obj1, obj2, memberInfo: null); } - public IEnumerable CalculateDifferences(T obj1, T obj2, IComparisonContext comparisonContext) + public IEnumerable CalculateDifferences(T obj1, T obj2, IComparisonContext comparisonContext) { - return CalculateDifferences(obj1, obj2, memberInfo: null, comparisonContext) - .Select(differenceTreeNodeInfo => differenceTreeNodeInfo.Difference); + return CalculateDifferences(obj1, obj2, memberInfo: null, comparisonContext); } internal IEnumerable CalculateDifferences(T obj1, T obj2, MemberInfo memberInfo) { return CalculateDifferences(obj1, obj2, memberInfo, ComparisonContextProvider.CreateImplicitRootContext(Settings)) - .Select(differenceTreeNodeInfo => differenceTreeNodeInfo.Difference); + .Select(differenceLocation => differenceLocation.Difference); } - IEnumerable CalculateDifferences(T obj1, T obj2, MemberInfo memberInfo, IComparisonContext comparisonContext) + IEnumerable CalculateDifferences(T obj1, T obj2, MemberInfo memberInfo, IComparisonContext comparisonContext) { var comparer = memberInfo != null ? OverridesCollection.GetComparer(memberInfo) @@ -81,7 +80,7 @@ IEnumerable CalculateDifferences(T obj1, T obj2, MemberI comparer = comparer ?? DefaultValueComparer; if (!comparer.Compare(obj1, obj2, Settings)) { - yield return AddDifferenceToComparisonContext(new Difference(string.Empty, comparer.ToString(obj1), comparer.ToString(obj2)), comparisonContext); + yield return AddDifferenceToTree(new Difference(string.Empty, comparer.ToString(obj1), comparer.ToString(obj2)), comparisonContext); } yield break; @@ -105,7 +104,7 @@ IEnumerable CalculateDifferences(T obj1, T obj2, MemberI { if (!DefaultValueComparer.Compare(obj1, obj2, Settings)) { - yield return AddDifferenceToComparisonContext(new Difference(string.Empty, DefaultValueComparer.ToString(obj1), DefaultValueComparer.ToString(obj2)), comparisonContext); + yield return AddDifferenceToTree(new Difference(string.Empty, DefaultValueComparer.ToString(obj1), DefaultValueComparer.ToString(obj2)), comparisonContext); } yield break; @@ -155,7 +154,7 @@ IEnumerable CalculateDifferences(T obj1, T obj2, MemberI if (!valueComparer.Compare(value1, value2, Settings)) { - yield return AddDifferenceToComparisonContext(new Difference(member.Name, valueComparer.ToString(value1), valueComparer.ToString(value2)), memberContext); + yield return AddDifferenceToTree(new Difference(member.Name, valueComparer.ToString(value1), valueComparer.ToString(value2)), memberContext); } } } diff --git a/ObjectsComparer/ObjectsComparer/Context/ComparerExtensions.cs b/ObjectsComparer/ObjectsComparer/Context/ComparerExtensions.cs index 5c5ed46..b5ffca7 100644 --- a/ObjectsComparer/ObjectsComparer/Context/ComparerExtensions.cs +++ b/ObjectsComparer/ObjectsComparer/Context/ComparerExtensions.cs @@ -10,7 +10,7 @@ public static class ComparerExtensions /// /// Calculates list of differences between objects. Accepts comparison context. /// - public static IComparisonContext CalculateDifferences(this IComparer comparer, Type type, object obj1, object obj2, Func findNextDifference = null, Action contextCompleted = null) + public static IComparisonContext CalculateDifferences(this IComparer comparer, Type type, object obj1, object obj2, Func findNextDifference = null, Action contextCompleted = null) { if (comparer is null) { @@ -24,12 +24,12 @@ public static IComparisonContext CalculateDifferences(this IComparer comparer, T var rootCtx = ComparisonContextProvider.CreateContext(comparer.Settings, ancestor: null); - var differences = comparer.CalculateDifferences(type, obj1, obj2, rootCtx); + var differenceLocationList = comparer.CalculateDifferences(type, obj1, obj2, rootCtx); - differences.EnumerateConditional( - currentDifference => + differenceLocationList.EnumerateConditional( + currentLocation => { - return findNextDifference(null, currentDifference); + return findNextDifference(currentLocation); }, contextCompleted); @@ -39,23 +39,23 @@ public static IComparisonContext CalculateDifferences(this IComparer comparer, T /// /// Calculates list of differences between objects. Accepts comparison context. /// - public static IComparisonContext CalculateContextableDifferences(this IComparer comparer, T obj1, T obj2, Func findNextDifference = null, Action contextCompleted = null) + public static IComparisonContext CalculateContextableDifferences(this IComparer comparer, T obj1, T obj2, Func findNextDifference = null, Action contextCompleted = null) { if (comparer is null) { throw new ArgumentNullException(nameof(comparer)); } - findNextDifference = findNextDifference ?? ((ctx, _) => true); + findNextDifference = findNextDifference ?? ((_) => true); var rootCtx = ComparisonContextProvider.CreateContext(comparer.Settings, ancestor: null); - var differences = comparer.CalculateDifferences(obj1, obj2, rootCtx); + var differenceLocationList = comparer.CalculateDifferences(obj1, obj2, rootCtx); - differences.EnumerateConditional( - currentDifference => + differenceLocationList.EnumerateConditional( + currentLocation => { - return findNextDifference(null, currentDifference); + return findNextDifference(currentLocation); }, contextCompleted); diff --git a/ObjectsComparer/ObjectsComparer/Context/ContextableExtensions.cs b/ObjectsComparer/ObjectsComparer/Context/ContextableExtensions.cs index 447cbb0..9d802b3 100644 --- a/ObjectsComparer/ObjectsComparer/Context/ContextableExtensions.cs +++ b/ObjectsComparer/ObjectsComparer/Context/ContextableExtensions.cs @@ -11,7 +11,8 @@ public static class ContextableExtensions /// Calculates list of differences between objects. Accepts comparison context. /// /// The method is intended for IContextableComparer implementers. - public static IEnumerable CalculateDifferences(this IComparer comparer, Type type, object obj1, object obj2, IComparisonContext comparisonContext) + /// Current difference and its location in the difference tree. + public static IEnumerable CalculateDifferences(this IComparer comparer, Type type, object obj1, object obj2, IComparisonContext comparisonContext) { if (comparer is null) { @@ -44,7 +45,7 @@ public static IEnumerable CalculateDifferences(this ICom foreach (var difference in differences) { - yield return new DifferenceTreeNodeInfo(difference); + yield return new DifferenceLocation(difference); } } @@ -53,7 +54,7 @@ public static IEnumerable CalculateDifferences(this ICom /// Calculates list of differences between objects. Accepts comparison context. /// /// The method is intended for IContextableComparer implementers. - public static IEnumerable CalculateDifferences(this IComparer comparer, T obj1, T obj2, IComparisonContext comparisonContext) + public static IEnumerable CalculateDifferences(this IComparer comparer, T obj1, T obj2, IComparisonContext comparisonContext) { if (comparer is null) { @@ -81,7 +82,7 @@ public static IEnumerable CalculateDifferences(this I foreach (var difference in differences) { - yield return new DifferenceTreeNodeInfo(difference); + yield return new DifferenceLocation(difference); } } diff --git a/ObjectsComparer/ObjectsComparer/Context/DifferenceTreeNodeInfo.cs b/ObjectsComparer/ObjectsComparer/Context/DifferenceTreeNodeInfo.cs index 08d2f38..1930d1b 100644 --- a/ObjectsComparer/ObjectsComparer/Context/DifferenceTreeNodeInfo.cs +++ b/ObjectsComparer/ObjectsComparer/Context/DifferenceTreeNodeInfo.cs @@ -5,16 +5,16 @@ namespace ObjectsComparer.ContextExtensions /// /// The location of the in the difference tree. /// - public class DifferenceTreeNodeInfo + public class DifferenceLocation { - public DifferenceTreeNodeInfo(Difference difference, IComparisonContext treeNode = null) + public DifferenceLocation(Difference difference, IComparisonContext treeNode = null) { Difference = difference ?? throw new ArgumentNullException(nameof(difference)); TreeNode = treeNode; } public Difference Difference { get; } - + public IComparisonContext TreeNode { get; } } } \ No newline at end of file diff --git a/ObjectsComparer/ObjectsComparer/Context/IContextableComparer.cs b/ObjectsComparer/ObjectsComparer/Context/IContextableComparer.cs index c929846..d01874d 100644 --- a/ObjectsComparer/ObjectsComparer/Context/IContextableComparer.cs +++ b/ObjectsComparer/ObjectsComparer/Context/IContextableComparer.cs @@ -8,6 +8,6 @@ namespace ObjectsComparer.ContextExtensions /// public interface IContextableComparer { - IEnumerable CalculateDifferences(Type type, object obj1, object obj2, IComparisonContext comparisonContext); + IEnumerable CalculateDifferences(Type type, object obj1, object obj2, IComparisonContext comparisonContext); } } \ No newline at end of file diff --git a/ObjectsComparer/ObjectsComparer/Context/IContextableComparer~1.cs b/ObjectsComparer/ObjectsComparer/Context/IContextableComparer~1.cs index 1e8d1fe..f5ee63e 100644 --- a/ObjectsComparer/ObjectsComparer/Context/IContextableComparer~1.cs +++ b/ObjectsComparer/ObjectsComparer/Context/IContextableComparer~1.cs @@ -8,6 +8,6 @@ namespace ObjectsComparer.ContextExtensions /// public interface IContextableComparer { - IEnumerable CalculateDifferences(T obj1, T obj2, IComparisonContext comparisonContext); + IEnumerable CalculateDifferences(T obj1, T obj2, IComparisonContext comparisonContext); } } diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractDynamicObjectsComprer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractDynamicObjectsComprer.cs index cd996ff..e19bf02 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractDynamicObjectsComprer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractDynamicObjectsComprer.cs @@ -15,15 +15,21 @@ protected AbstractDynamicObjectsComprer(ComparisonSettings settings, BaseCompare public override IEnumerable CalculateDifferences(Type type, object obj1, object obj2) { - return CalculateDifferences(type, obj1, obj2, ComparisonContextProvider.CreateImplicitRootContext(Settings)); + return AsContextableComparer().CalculateDifferences(type, obj1, obj2, ComparisonContextProvider.CreateImplicitRootContext(Settings)) + .Select(differenceLocation => differenceLocation.Difference); } - public virtual IEnumerable CalculateDifferences(T obj1, T obj2, IComparisonContext comparisonContext) + IEnumerable IContextableComparer.CalculateDifferences(T obj1, T obj2, IComparisonContext comparisonContext) { - return CalculateDifferences(typeof(T), obj1, obj2, ComparisonContextProvider.CreateImplicitRootContext(Settings)); + return AsContextableComparer().CalculateDifferences(typeof(T), obj1, obj2, ComparisonContextProvider.CreateImplicitRootContext(Settings)); } - public virtual IEnumerable CalculateDifferences(Type type, object obj1, object obj2, IComparisonContext comparisonContext) + IContextableComparer AsContextableComparer() + { + return this; + } + + IEnumerable IContextableComparer.CalculateDifferences(Type type, object obj1, object obj2, IComparisonContext comparisonContext) { var castedObject1 = (T)obj1; var castedObject2 = (T)obj2; @@ -76,7 +82,7 @@ public virtual IEnumerable CalculateDifferences(Type type, object ob { if (!existsInObject1) { - var difference = AddDifferenceToComparisonContext( + var difference = AddDifferenceToTree( new Difference(propertyKey, string.Empty, valueComparer.ToString(value2), DifferenceTypes.MissedMemberInFirstObject), keyComparisonContext); @@ -86,7 +92,7 @@ public virtual IEnumerable CalculateDifferences(Type type, object ob if (!existsInObject2) { - var difference = AddDifferenceToComparisonContext( + var difference = AddDifferenceToTree( new Difference(propertyKey, valueComparer.ToString(value1), string.Empty, DifferenceTypes.MissedMemberInSecondObject), keyComparisonContext); @@ -101,7 +107,7 @@ public virtual IEnumerable CalculateDifferences(Type type, object ob OverridesCollection.GetComparer(propertyKey) ?? DefaultValueComparer; - var difference = AddDifferenceToComparisonContext( + var difference = AddDifferenceToTree( new Difference(propertyKey, valueComparer.ToString(value1), valueComparer2.ToString(value2), DifferenceTypes.TypeMismatch), keyComparisonContext); @@ -117,7 +123,7 @@ public virtual IEnumerable CalculateDifferences(Type type, object ob OverridesCollection.GetComparer(value2.GetType()) ?? OverridesCollection.GetComparer(propertyKey) ?? DefaultValueComparer : DefaultValueComparer; - var difference = AddDifferenceToComparisonContext( + var difference = AddDifferenceToTree( new Difference(propertyKey, valueComparer.ToString(value1), valueComparer2.ToString(value2), DifferenceTypes.TypeMismatch), keyComparisonContext); @@ -129,11 +135,11 @@ public virtual IEnumerable CalculateDifferences(Type type, object ob { if (!customComparer.Compare(value1, value2, Settings)) { - var difference = AddDifferenceToComparisonContext( + var differenceLocation = AddDifferenceToTree( new Difference(propertyKey, customComparer.ToString(value1), customComparer.ToString(value2)), keyComparisonContext); - yield return difference; + yield return differenceLocation; } continue; @@ -142,7 +148,8 @@ public virtual IEnumerable CalculateDifferences(Type type, object ob var comparer = Factory.GetObjectsComparer(propertyType, Settings, this); foreach (var failure in comparer.CalculateDifferences(propertyType, value1, value2, comparisonContext)) { - yield return failure.InsertPath(propertyKey); + failure.Difference.InsertPath(propertyKey); + yield return failure; } } } diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractEnumerablesComparer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractEnumerablesComparer.cs index 849607a..6a5a431 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractEnumerablesComparer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractEnumerablesComparer.cs @@ -4,6 +4,7 @@ using System.Reflection; using ObjectsComparer.Utils; using System.Collections; +using ObjectsComparer.ContextExtensions; namespace ObjectsComparer { @@ -59,6 +60,6 @@ public virtual bool SkipMember(Type type, MemberInfo member) public abstract bool IsMatch(Type type, object obj1, object obj2); - public abstract IEnumerable CalculateDifferences(Type type, object obj1, object obj2, IComparisonContext comparisonContext); + public abstract IEnumerable CalculateDifferences(Type type, object obj1, object obj2, IComparisonContext comparisonContext); } } \ No newline at end of file diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs index 1eee6e4..76ad055 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs @@ -4,6 +4,7 @@ using System.Diagnostics; using System.Linq; using System.Reflection; +using ObjectsComparer.ContextExtensions; using ObjectsComparer.Exceptions; using ObjectsComparer.Utils; @@ -17,10 +18,13 @@ public EnumerablesComparer(ComparisonSettings settings, BaseComparer parentCompa public override IEnumerable CalculateDifferences(Type type, object obj1, object obj2) { - return CalculateDifferences(type, obj1, obj2, ComparisonContextProvider.CreateImplicitRootContext(Settings)); + return AsContextable().CalculateDifferences(type, obj1, obj2, ComparisonContextProvider.CreateImplicitRootContext(Settings)) + .Select(differenceLocation => differenceLocation.Difference); } - public IEnumerable CalculateDifferences(Type type, object obj1, object obj2, IComparisonContext listComparisonContext) + IContextableComparer AsContextable() => this; + + IEnumerable IContextableComparer.CalculateDifferences(Type type, object obj1, object obj2, IComparisonContext listComparisonContext) { Debug.WriteLine($"{GetType().Name}.{nameof(CalculateDifferences)}: {type.Name}"); @@ -32,7 +36,7 @@ public IEnumerable CalculateDifferences(Type type, object obj1, obje if (!Settings.EmptyAndNullEnumerablesEqual && (obj1 == null || obj2 == null) && obj1 != obj2) { - yield return AddDifferenceToComparisonContext(new Difference("[]", obj1?.ToString() ?? string.Empty, obj2?.ToString() ?? string.Empty), listComparisonContext); + yield return AddDifferenceToTree(new Difference("[]", obj1?.ToString() ?? string.Empty, obj2?.ToString() ?? string.Empty), listComparisonContext); yield break; } @@ -62,7 +66,7 @@ public IEnumerable CalculateDifferences(Type type, object obj1, obje if (array1.Length != array2.Length) { - yield return AddDifferenceToComparisonContext(new Difference("", array1.Length.ToString(), array2.Length.ToString(), DifferenceTypes.NumberOfElementsMismatch), listComparisonContext); + yield return AddDifferenceToTree(new Difference("", array1.Length.ToString(), array2.Length.ToString(), DifferenceTypes.NumberOfElementsMismatch), listComparisonContext); if (listComparisonOptions.UnequalListsComparisonEnabled == false) { @@ -70,7 +74,7 @@ public IEnumerable CalculateDifferences(Type type, object obj1, obje } } - IEnumerable failrues = CalculateDifferences(array1, array2, listComparisonContext, listComparisonOptions); + var failrues = CalculateDifferences(array1, array2, listComparisonContext, listComparisonOptions); foreach (var failrue in failrues) { diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparerBase.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparerBase.cs index 188203c..02ac55a 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparerBase.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparerBase.cs @@ -16,7 +16,7 @@ public EnumerablesComparerBase(ComparisonSettings settings, BaseComparer parentC /// /// Selects calculation operation based on the current value of the property. /// - protected virtual IEnumerable CalculateDifferences(IList list1, IList list2, IComparisonContext listComparisonContext, ListComparisonOptions listComparisonOptions) + protected virtual IEnumerable CalculateDifferences(IList list1, IList list2, IComparisonContext listComparisonContext, ListComparisonOptions listComparisonOptions) { if (listComparisonOptions.ElementSearchMode == ListElementSearchMode.Key) { @@ -35,7 +35,7 @@ protected virtual IEnumerable CalculateDifferences(IList list1 /// /// Calculates differences using comparison mode. /// - protected virtual IEnumerable CalculateDifferencesByKey(IList array1, IList array2, IComparisonContext listComparisonContext, ListComparisonOptions listComparisonOptions) + protected virtual IEnumerable CalculateDifferencesByKey(IList array1, IList array2, IComparisonContext listComparisonContext, ListComparisonOptions listComparisonOptions) { Debug.WriteLine($"{GetType().Name}.{nameof(CalculateDifferencesByKey)}: {array1?.GetType().Name}"); @@ -57,7 +57,7 @@ protected virtual IEnumerable CalculateDifferencesByKey(IList var nullElementIdentifier = keyOptions.GetNullElementIdentifier(new FormatNullElementIdentifierArgs(element1Index)); - yield return AddDifferenceToComparisonContext(new Difference($"[{nullElementIdentifier}]", string.Empty, string.Empty, DifferenceTypes.MissedElementInSecondObject), elementComparisonContext); + yield return AddDifferenceToTree(new Difference($"[{nullElementIdentifier}]", string.Empty, string.Empty, DifferenceTypes.MissedElementInSecondObject), elementComparisonContext); continue; } @@ -82,13 +82,14 @@ protected virtual IEnumerable CalculateDifferencesByKey(IList foreach (var failure in comparer.CalculateDifferences(element1.GetType(), element1, element2, elementComparisonContext)) { - yield return failure.InsertPath($"[{formattedElement1Key}]"); + failure.Difference.InsertPath($"[{formattedElement1Key}]"); + yield return failure; } } else { var valueComparer1 = OverridesCollection.GetComparer(element1.GetType()) ?? DefaultValueComparer; - yield return AddDifferenceToComparisonContext(new Difference($"[{formattedElement1Key}]", valueComparer1.ToString(element1), string.Empty, DifferenceTypes.MissedElementInSecondObject), elementComparisonContext); + yield return AddDifferenceToTree(new Difference($"[{formattedElement1Key}]", valueComparer1.ToString(element1), string.Empty, DifferenceTypes.MissedElementInSecondObject), elementComparisonContext); } } @@ -107,7 +108,7 @@ protected virtual IEnumerable CalculateDifferencesByKey(IList var nullElementIdentifier = keyOptions.GetNullElementIdentifier(new FormatNullElementIdentifierArgs(element2Index)); - yield return AddDifferenceToComparisonContext(new Difference($"[{nullElementIdentifier}]", string.Empty, string.Empty, DifferenceTypes.MissedElementInFirstObject), elementComparisonContext); + yield return AddDifferenceToTree(new Difference($"[{nullElementIdentifier}]", string.Empty, string.Empty, DifferenceTypes.MissedElementInFirstObject), elementComparisonContext); continue; } @@ -127,7 +128,7 @@ protected virtual IEnumerable CalculateDifferencesByKey(IList { var formattedElement2Key = keyOptions.GetFormattedElementKey(new FormatListElementKeyArgs(element2Index, element2Key, element2)); var valueComparer2 = OverridesCollection.GetComparer(element2.GetType()) ?? DefaultValueComparer; - yield return AddDifferenceToComparisonContext(new Difference($"[{formattedElement2Key}]", string.Empty, valueComparer2.ToString(element2), DifferenceTypes.MissedElementInFirstObject), elementComparisonContext); + yield return AddDifferenceToTree(new Difference($"[{formattedElement2Key}]", string.Empty, valueComparer2.ToString(element2), DifferenceTypes.MissedElementInFirstObject), elementComparisonContext); } } } @@ -135,7 +136,7 @@ protected virtual IEnumerable CalculateDifferencesByKey(IList /// /// Calculates differences using comparison mode. /// - protected virtual IEnumerable CalculateDifferencesByIndex(IList array1, IList array2, IComparisonContext listComparisonContext, ListComparisonOptions listComparisonOptions) + protected virtual IEnumerable CalculateDifferencesByIndex(IList array1, IList array2, IComparisonContext listComparisonContext, ListComparisonOptions listComparisonOptions) { Debug.WriteLine($"{GetType().Name}.{nameof(CalculateDifferencesByIndex)}: {array1?.GetType().Name}"); @@ -159,19 +160,19 @@ protected virtual IEnumerable CalculateDifferencesByIndex(IList CalculateDifferencesByIndex(IList CalculateDifferencesByIndex(IList array2Count ? DifferenceTypes.MissedElementInSecondObject : DifferenceTypes.MissedElementInFirstObject); //yield return AddDifferenceToComparisonContext(difference, new ComparisonContext(new ComparisonContextMember(), listComparisonContext)); - yield return AddDifferenceToComparisonContext(difference, ComparisonContextProvider.CreateContext(Settings, listComparisonContext)); + yield return AddDifferenceToTree(difference, ComparisonContextProvider.CreateContext(Settings, listComparisonContext)); } } } diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer~1.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer~1.cs index 602b2dc..d23f409 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer~1.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer~1.cs @@ -3,6 +3,7 @@ using System.Diagnostics; using System.Linq; using System.Reflection; +using ObjectsComparer.ContextExtensions; using ObjectsComparer.Utils; namespace ObjectsComparer @@ -18,10 +19,11 @@ public EnumerablesComparer(ComparisonSettings settings, BaseComparer parentCompa public override IEnumerable CalculateDifferences(Type type, object obj1, object obj2) { - return CalculateDifferences(type, obj1, obj2, ComparisonContextProvider.CreateImplicitRootContext(Settings)); + return CalculateDifferences(type, obj1, obj2, ComparisonContextProvider.CreateImplicitRootContext(Settings)) + .Select(differeneLocation => differeneLocation.Difference); } - public IEnumerable CalculateDifferences(Type type, object obj1, object obj2, IComparisonContext listComparisonContext) + public IEnumerable CalculateDifferences(Type type, object obj1, object obj2, IComparisonContext listComparisonContext) { Debug.WriteLine($"{GetType().Name}.{nameof(CalculateDifferences)}: {type.Name}"); @@ -64,7 +66,7 @@ public IEnumerable CalculateDifferences(Type type, object obj1, obje { if (!type.GetTypeInfo().IsArray) { - yield return AddDifferenceToComparisonContext(new Difference("", list1.Count().ToString(), list2.Count().ToString(), DifferenceTypes.NumberOfElementsMismatch), listComparisonContext); + yield return AddDifferenceToTree(new Difference("", list1.Count().ToString(), list2.Count().ToString(), DifferenceTypes.NumberOfElementsMismatch), listComparisonContext); } if (listComparisonOptions.UnequalListsComparisonEnabled == false) @@ -73,7 +75,7 @@ public IEnumerable CalculateDifferences(Type type, object obj1, obje } } - IEnumerable failrues = CalculateDifferences(list1, list2, listComparisonContext, listComparisonOptions); + var failrues = CalculateDifferences(list1, list2, listComparisonContext, listComparisonOptions); foreach (var failrue in failrues) { @@ -81,7 +83,7 @@ public IEnumerable CalculateDifferences(Type type, object obj1, obje } } - public IEnumerable CalculateDifferences(T obj1, T obj2, IComparisonContext listComparisonContext) + public IEnumerable CalculateDifferences(T obj1, T obj2, IComparisonContext listComparisonContext) { return CalculateDifferences(((object)obj1 ?? obj2).GetType(), obj1, obj2, listComparisonContext); } diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/GenericEnumerablesComparer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/GenericEnumerablesComparer.cs index 91fe169..5d4b9c3 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/GenericEnumerablesComparer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/GenericEnumerablesComparer.cs @@ -18,10 +18,11 @@ public GenericEnumerablesComparer(ComparisonSettings settings, BaseComparer pare public override IEnumerable CalculateDifferences(Type type, object obj1, object obj2) { - return CalculateDifferences(type, obj1, obj2, ComparisonContextProvider.CreateImplicitRootContext(Settings)); + return CalculateDifferences(type, obj1, obj2, ComparisonContextProvider.CreateImplicitRootContext(Settings)) + .Select(differenceLocation => differenceLocation.Difference); } - public override IEnumerable CalculateDifferences(Type type, object obj1, object obj2, IComparisonContext comparisonContext) + public override IEnumerable CalculateDifferences(Type type, object obj1, object obj2, IComparisonContext comparisonContext) { if (obj1 == null && obj2 == null) { diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/HashSetsComparer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/HashSetsComparer.cs index 9b3aec2..d8ddfd1 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/HashSetsComparer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/HashSetsComparer.cs @@ -16,10 +16,11 @@ public HashSetsComparer(ComparisonSettings settings, BaseComparer parentComparer public override IEnumerable CalculateDifferences(Type type, object obj1, object obj2) { - return CalculateDifferences(type, obj1, obj2, ComparisonContextProvider.CreateImplicitRootContext(Settings)); + return CalculateDifferences(type, obj1, obj2, ComparisonContextProvider.CreateImplicitRootContext(Settings)) + .Select(differenceLocation => differenceLocation.Difference); } - public override IEnumerable CalculateDifferences(Type type, object obj1, object obj2, IComparisonContext comparisonContext) + public override IEnumerable CalculateDifferences(Type type, object obj1, object obj2, IComparisonContext comparisonContext) { if (obj1 == null && obj2 == null) { diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/HashSetsComparer~1.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/HashSetsComparer~1.cs index f415964..2ddb280 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/HashSetsComparer~1.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/HashSetsComparer~1.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using ObjectsComparer.ContextExtensions; using ObjectsComparer.Utils; namespace ObjectsComparer @@ -12,17 +13,18 @@ public HashSetsComparer(ComparisonSettings settings, BaseComparer parentComparer { } - public IEnumerable CalculateDifferences(T obj1, T obj2, IComparisonContext comparisonContext) + public IEnumerable CalculateDifferences(T obj1, T obj2, IComparisonContext comparisonContext) { return CalculateDifferences(typeof(T), obj1, obj2, comparisonContext); } public override IEnumerable CalculateDifferences(Type type, object obj1, object obj2) { - return CalculateDifferences(type, obj1, obj2, ComparisonContextProvider.CreateImplicitRootContext(Settings)); + return CalculateDifferences(type, obj1, obj2, ComparisonContextProvider.CreateImplicitRootContext(Settings)) + .Select(differenceLocation => differenceLocation.Difference); } - public IEnumerable CalculateDifferences(Type type, object obj1, object obj2, IComparisonContext comparisonContext) + public IEnumerable CalculateDifferences(Type type, object obj1, object obj2, IComparisonContext comparisonContext) { if (comparisonContext is null) { @@ -61,7 +63,7 @@ public IEnumerable CalculateDifferences(Type type, object obj1, obje { if (!hashSet2.Contains(element)) { - var difference = AddDifferenceToComparisonContext( + var difference = AddDifferenceToTree( new Difference("", valueComparer.ToString(element), string.Empty, DifferenceTypes.MissedElementInSecondObject), comparisonContext); @@ -73,7 +75,7 @@ public IEnumerable CalculateDifferences(Type type, object obj1, obje { if (!hashSet1.Contains(element)) { - var difference = AddDifferenceToComparisonContext(new Difference("", string.Empty, valueComparer.ToString(element), + var difference = AddDifferenceToTree(new Difference("", string.Empty, valueComparer.ToString(element), DifferenceTypes.MissedElementInFirstObject), comparisonContext); yield return difference; diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/MultidimensionalArrayComparer~1.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/MultidimensionalArrayComparer~1.cs index 5ff2447..4a05031 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/MultidimensionalArrayComparer~1.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/MultidimensionalArrayComparer~1.cs @@ -18,15 +18,16 @@ public MultidimensionalArrayComparer(ComparisonSettings settings, BaseComparer p public override IEnumerable CalculateDifferences(Type type, object obj1, object obj2) { - return CalculateDifferences(type, obj1, obj2, ComparisonContextProvider.CreateImplicitRootContext(Settings)); + return CalculateDifferences(type, obj1, obj2, ComparisonContextProvider.CreateImplicitRootContext(Settings)) + .Select(differenceLocation => differenceLocation.Difference); } - public IEnumerable CalculateDifferences(T obj1, T obj2, IComparisonContext comparisonContext) + public IEnumerable CalculateDifferences(T obj1, T obj2, IComparisonContext comparisonContext) { return CalculateDifferences(typeof(T), obj1, obj2, comparisonContext); } - public IEnumerable CalculateDifferences(Type type, object obj1, object obj2, IComparisonContext comparisonContext) + public IEnumerable CalculateDifferences(Type type, object obj1, object obj2, IComparisonContext comparisonContext) { if (comparisonContext is null) { @@ -59,7 +60,7 @@ public IEnumerable CalculateDifferences(Type type, object obj1, obje if (array1.Rank != array2.Rank) { - var difference = AddDifferenceToComparisonContext(new Difference("Rank", array1.Rank.ToString(), array2.Rank.ToString()), comparisonContext); + var difference = AddDifferenceToTree(new Difference("Rank", array1.Rank.ToString(), array2.Rank.ToString()), comparisonContext); yield return difference; yield break; } @@ -74,7 +75,7 @@ public IEnumerable CalculateDifferences(Type type, object obj1, obje if (length1 != length2) { dimensionsFailure = true; - var difference = AddDifferenceToComparisonContext(new Difference($"Dimension{i}", length1.ToString(), length2.ToString()), comparisonContext); + var difference = AddDifferenceToTree(new Difference($"Dimension{i}", length1.ToString(), length2.ToString()), comparisonContext); yield return difference; } } @@ -90,7 +91,8 @@ public IEnumerable CalculateDifferences(Type type, object obj1, obje foreach (var failure in _comparer.CalculateDifferences((T)array1.GetValue(indecies), (T)array2.GetValue(indecies), comparisonContext)) { - yield return failure.InsertPath($"[{string.Join(",", indecies)}]"); + failure.Difference.InsertPath($"[{string.Join(",", indecies)}]"); + yield return failure; } } } diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/MultidimensionalArraysComparer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/MultidimensionalArraysComparer.cs index be1bee2..773cba0 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/MultidimensionalArraysComparer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/MultidimensionalArraysComparer.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Reflection; using ObjectsComparer.ContextExtensions; using ObjectsComparer.Utils; @@ -16,10 +17,11 @@ public MultidimensionalArraysComparer(ComparisonSettings settings, BaseComparer public override IEnumerable CalculateDifferences(Type type, object obj1, object obj2) { - return CalculateDifferences(type, obj1, obj2, ComparisonContextProvider.CreateImplicitRootContext(Settings)); + return CalculateDifferences(type, obj1, obj2, ComparisonContextProvider.CreateImplicitRootContext(Settings)) + .Select(differenceLocation => differenceLocation.Difference); } - public override IEnumerable CalculateDifferences(Type type, object obj1, object obj2, IComparisonContext comparisonContext) + public override IEnumerable CalculateDifferences(Type type, object obj1, object obj2, IComparisonContext comparisonContext) { if (obj1 == null && obj2 == null) { diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/TypesComparer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/TypesComparer.cs index ca40342..1797e81 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/TypesComparer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/TypesComparer.cs @@ -1,6 +1,8 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Reflection; +using ObjectsComparer.ContextExtensions; using ObjectsComparer.Utils; namespace ObjectsComparer @@ -15,10 +17,11 @@ public TypesComparer(ComparisonSettings settings, BaseComparer parentComparer, public override IEnumerable CalculateDifferences(Type type, object obj1, object obj2) { - return CalculateDifferences(type, obj1, obj2, ComparisonContextProvider.CreateImplicitRootContext(Settings)); + return CalculateDifferences(type, obj1, obj2, ComparisonContextProvider.CreateImplicitRootContext(Settings)) + .Select(differenceLocation => differenceLocation.Difference); } - public IEnumerable CalculateDifferences(Type type, object obj1, object obj2, IComparisonContext comparisonContext) + public IEnumerable CalculateDifferences(Type type, object obj1, object obj2, IComparisonContext comparisonContext) { if (comparisonContext is null) { @@ -46,7 +49,7 @@ public IEnumerable CalculateDifferences(Type type, object obj1, obje if (type1Str != type2Str) { //yield return new Difference(string.Empty, type1Str, type2Str); - yield return AddDifferenceToComparisonContext(new Difference(string.Empty, type1Str, type2Str), comparisonContext); + yield return AddDifferenceToTree(new Difference(string.Empty, type1Str, type2Str), comparisonContext); } } From 4a2438b49b8c9681a4ea0b30618cb96a4c958a92 Mon Sep 17 00:00:00 2001 From: Daniel Nemec Date: Sun, 3 Apr 2022 10:32:28 +0200 Subject: [PATCH 118/181] Review comparison context test methods. --- .../Example4/Example4Tests_BuiltInKeyComparison.cs | 7 ++----- .../Comparer_CompilerGeneratedObjectsTests.cs | 14 ++++---------- ObjectsComparer/ObjectsComparer/Comparer.cs | 6 ++++-- ObjectsComparer/ObjectsComparer/Comparer~1.cs | 2 +- .../ObjectsComparer/Context/ComparerExtensions.cs | 2 +- .../Context/ContextableExtensions.cs | 4 ++++ 6 files changed, 16 insertions(+), 19 deletions(-) diff --git a/ObjectsComparer/ObjectsComparer.Examples/Example4/Example4Tests_BuiltInKeyComparison.cs b/ObjectsComparer/ObjectsComparer.Examples/Example4/Example4Tests_BuiltInKeyComparison.cs index a2a367e..4c9fe90 100644 --- a/ObjectsComparer/ObjectsComparer.Examples/Example4/Example4Tests_BuiltInKeyComparison.cs +++ b/ObjectsComparer/ObjectsComparer.Examples/Example4/Example4Tests_BuiltInKeyComparison.cs @@ -289,14 +289,11 @@ public void List_Of_Different_Sizes_But_Is_Inequality_FormatKey_CheckComparisonC .FormatElementKey(formatKeyArgs => $"Id={formatKeyArgs.ElementKey}"))); var comparer = new Comparer(settings); - var rootContext = new ComparisonContext(); - var differences = comparer.CalculateDifferences(formula1, formula2, rootContext).ToArray(); - rootContext.Shrink(); + var rootDifferenceNode = comparer.CalculateContextableDifferences(formula1, formula2); + var differences = rootDifferenceNode.GetDifferences(recursive: true).ToArray(); bool isEqual = differences.Any() == false; ResultToOutput(isEqual, differences); - CollectionAssert.AreEquivalent(differences, rootContext.GetDifferences(true)); - Assert.IsFalse(isEqual); Assert.AreEqual(5, differences.Count()); Assert.IsTrue(differences.Any(d => d.MemberPath == "Items" && d.Value1 == "1" && d.Value2 == "2" && d.DifferenceType == DifferenceTypes.NumberOfElementsMismatch)); diff --git a/ObjectsComparer/ObjectsComparer.Tests/Comparer_CompilerGeneratedObjectsTests.cs b/ObjectsComparer/ObjectsComparer.Tests/Comparer_CompilerGeneratedObjectsTests.cs index fe76fac..11f3fa6 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/Comparer_CompilerGeneratedObjectsTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/Comparer_CompilerGeneratedObjectsTests.cs @@ -79,16 +79,13 @@ public void MissedFields_CheckComparisonContext() var comparer = new Comparer(); - var comparisonContext = new ComparisonContext(); - IEnumerable calculateDifferences = comparer.CalculateDifferences(typeof(object), (object)a1, (object)a2, comparisonContext).ToArray(); - var comparisonContextDifferences = comparisonContext.GetDifferences(true).ToArray(); + var rootDiffenenceNode = comparer.CalculateDifferencesTree(typeof(object), (object)a1, (object)a2); + var calculateDifferences = rootDiffenenceNode.GetDifferences(true).ToArray(); Assert.AreEqual(3, calculateDifferences.Count()); Assert.IsTrue(calculateDifferences.Any(d => d.MemberPath == "Field1" && d.Value1 == "A" && d.Value2 == "B")); Assert.IsTrue(calculateDifferences.Any(d => d.MemberPath == "Field2" && d.Value1 == "5" && d.Value2 == "8")); Assert.IsTrue(calculateDifferences.Any(d => d.DifferenceType == DifferenceTypes.MissedMemberInFirstObject && d.MemberPath == "Field3" && d.Value2 == "False")); - - CollectionAssert.AreEquivalent(calculateDifferences, comparisonContextDifferences); } [Test] @@ -220,9 +217,8 @@ public void NullAndMissedMemberAreNotEqual_CheckComparisonContext() var comparer = new Comparer(); - var comparisonContext = new ComparisonContext(); - var calculateDifferences = comparer.CalculateDifferences(typeof(object), (object)a1, (object)a2, comparisonContext).ToArray(); - var comparisonContextDifferences = comparisonContext.GetDifferences(true).ToArray(); + var rootDifferenceNode = comparer.CalculateDifferencesTree(typeof(object), (object)a1, (object)a2); + var calculateDifferences = rootDifferenceNode.GetDifferences(true); Assert.IsTrue(calculateDifferences.Any()); Assert.AreEqual(2, calculateDifferences.Count()); @@ -230,8 +226,6 @@ public void NullAndMissedMemberAreNotEqual_CheckComparisonContext() d => d.MemberPath == "Field1" && d.DifferenceType == DifferenceTypes.MissedMemberInSecondObject)); Assert.IsTrue(calculateDifferences.Any( d => d.MemberPath == "Field2" && d.DifferenceType == DifferenceTypes.MissedMemberInFirstObject)); - - CollectionAssert.AreEquivalent(calculateDifferences, comparisonContextDifferences); } [Test] diff --git a/ObjectsComparer/ObjectsComparer/Comparer.cs b/ObjectsComparer/ObjectsComparer/Comparer.cs index 2de2bbe..70a3ae4 100644 --- a/ObjectsComparer/ObjectsComparer/Comparer.cs +++ b/ObjectsComparer/ObjectsComparer/Comparer.cs @@ -30,11 +30,13 @@ public Comparer(ComparisonSettings settings = null, BaseComparer parentComparer public override IEnumerable CalculateDifferences(Type type, object obj1, object obj2) { - return CalculateDifferences(type, obj1, obj2, ComparisonContextProvider.CreateImplicitRootContext(Settings)) + return AsContextableComparer().CalculateDifferences(type, obj1, obj2, ComparisonContextProvider.CreateImplicitRootContext(Settings)) .Select(differenceLoccation => differenceLoccation.Difference); } - public IEnumerable CalculateDifferences(Type type, object obj1, object obj2, IComparisonContext comparisonContext) + IContextableComparer AsContextableComparer() => this; + + IEnumerable IContextableComparer.CalculateDifferences(Type type, object obj1, object obj2, IComparisonContext comparisonContext) { if (comparisonContext is null) { diff --git a/ObjectsComparer/ObjectsComparer/Comparer~1.cs b/ObjectsComparer/ObjectsComparer/Comparer~1.cs index 76573aa..0323564 100644 --- a/ObjectsComparer/ObjectsComparer/Comparer~1.cs +++ b/ObjectsComparer/ObjectsComparer/Comparer~1.cs @@ -57,7 +57,7 @@ public override IEnumerable CalculateDifferences(T obj1, T obj2) return CalculateDifferences(obj1, obj2, memberInfo: null); } - public IEnumerable CalculateDifferences(T obj1, T obj2, IComparisonContext comparisonContext) + IEnumerable IContextableComparer.CalculateDifferences(T obj1, T obj2, IComparisonContext comparisonContext) { return CalculateDifferences(obj1, obj2, memberInfo: null, comparisonContext); } diff --git a/ObjectsComparer/ObjectsComparer/Context/ComparerExtensions.cs b/ObjectsComparer/ObjectsComparer/Context/ComparerExtensions.cs index b5ffca7..f630c16 100644 --- a/ObjectsComparer/ObjectsComparer/Context/ComparerExtensions.cs +++ b/ObjectsComparer/ObjectsComparer/Context/ComparerExtensions.cs @@ -10,7 +10,7 @@ public static class ComparerExtensions /// /// Calculates list of differences between objects. Accepts comparison context. /// - public static IComparisonContext CalculateDifferences(this IComparer comparer, Type type, object obj1, object obj2, Func findNextDifference = null, Action contextCompleted = null) + public static IComparisonContext CalculateDifferencesTree(this IComparer comparer, Type type, object obj1, object obj2, Func findNextDifference = null, Action contextCompleted = null) { if (comparer is null) { diff --git a/ObjectsComparer/ObjectsComparer/Context/ContextableExtensions.cs b/ObjectsComparer/ObjectsComparer/Context/ContextableExtensions.cs index 9d802b3..112a3c2 100644 --- a/ObjectsComparer/ObjectsComparer/Context/ContextableExtensions.cs +++ b/ObjectsComparer/ObjectsComparer/Context/ContextableExtensions.cs @@ -37,6 +37,8 @@ public static IEnumerable CalculateDifferences(this ICompare { yield return differenceTreeNodeInfo; } + + yield break; } ThrowContextableComparerNotImplemented(comparisonContext, comparer.Settings, comparer, nameof(IContextableComparer)); @@ -74,6 +76,8 @@ public static IEnumerable CalculateDifferences(this IComp { yield return differenceTreeNodeInfo; } + + yield break; } ThrowContextableComparerNotImplemented(comparisonContext, comparer.Settings, comparer, $"{nameof(IContextableComparer)}<{typeof(T).FullName}>"); From 8b092a01f87bd0d90693f85cf57bcf64bef31e6d Mon Sep 17 00:00:00 2001 From: nemec Date: Tue, 5 Apr 2022 23:24:32 +0200 Subject: [PATCH 119/181] Remove comparison context as argument of CalculateDifferences. --- .../Example4/Example4Tests.cs | 17 ++++----- .../Example4Tests_BuiltInKeyComparison.cs | 2 +- .../ObjectsComparer.Tests/ComparerTests.cs | 3 ++ .../Comparer_ExpandoObjectsTests.cs | 31 +++++++-------- .../Comparer_GenericEnumerableTests.cs | 12 ++---- .../Comparer_MultidimensionalArraysTests.cs | 10 +---- .../Comparer_NonGenericEnumerableTests.cs | 10 ++--- .../ComparisonSettingsTests.cs | 13 +++---- ObjectsComparer/ObjectsComparer/Comparer.cs | 38 ++++++++++++++++++- .../Context/ComparerExtensions.cs | 5 ++- .../Context/ContextableExtensions.cs | 3 +- 11 files changed, 83 insertions(+), 61 deletions(-) diff --git a/ObjectsComparer/ObjectsComparer.Examples/Example4/Example4Tests.cs b/ObjectsComparer/ObjectsComparer.Examples/Example4/Example4Tests.cs index 48cfd10..d689d41 100644 --- a/ObjectsComparer/ObjectsComparer.Examples/Example4/Example4Tests.cs +++ b/ObjectsComparer/ObjectsComparer.Examples/Example4/Example4Tests.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using System.Linq; using NUnit.Framework; +using ObjectsComparer.Exceptions; using static ObjectsComparer.Examples.OutputHelper; // ReSharper disable PossibleMultipleEnumeration @@ -66,8 +67,8 @@ public void List_Of_Equal_Sizes_But_Is_Inequality() } [Test] - public void List_Of_Equal_Sizes_But_Is_Inequality_Test_Ctx() - { + public void CalculateDifferencesTree_Throw_ContextableComparerNotImplemented() + { var formula1 = new Formula { Id = 1, @@ -100,13 +101,11 @@ public void List_Of_Equal_Sizes_But_Is_Inequality_Test_Ctx() } }; - var rootContext = _comparer.CalculateContextableDifferences(formula1, formula2); - var differences = rootContext.GetDifferences(true); - - Assert.AreEqual(3, differences.Count()); - Assert.IsTrue(differences.Any(d => d.MemberPath == "Items[Id=1].Delay" && d.Value1 == "60" && d.Value2 == "80")); - Assert.IsTrue(differences.Any(d => d.MemberPath == "Items[Id=1].Name" && d.Value1 == "Item 1" && d.Value2 == "Item One")); - Assert.IsTrue(differences.Any(d => d.MemberPath == "Items[Id=1].Instruction" && d.Value1 == "Instruction 1" && d.Value2 == "Instruction One")); + Assert.Throws(() => + { + var rootNode = _comparer.CalculateDifferencesTree(formula1, formula2); + var differences = rootNode.GetDifferences(true).ToArray(); + }); } [Test] diff --git a/ObjectsComparer/ObjectsComparer.Examples/Example4/Example4Tests_BuiltInKeyComparison.cs b/ObjectsComparer/ObjectsComparer.Examples/Example4/Example4Tests_BuiltInKeyComparison.cs index 4c9fe90..7f7d12a 100644 --- a/ObjectsComparer/ObjectsComparer.Examples/Example4/Example4Tests_BuiltInKeyComparison.cs +++ b/ObjectsComparer/ObjectsComparer.Examples/Example4/Example4Tests_BuiltInKeyComparison.cs @@ -289,7 +289,7 @@ public void List_Of_Different_Sizes_But_Is_Inequality_FormatKey_CheckComparisonC .FormatElementKey(formatKeyArgs => $"Id={formatKeyArgs.ElementKey}"))); var comparer = new Comparer(settings); - var rootDifferenceNode = comparer.CalculateContextableDifferences(formula1, formula2); + var rootDifferenceNode = comparer.CalculateDifferencesTree(formula1, formula2); var differences = rootDifferenceNode.GetDifferences(recursive: true).ToArray(); bool isEqual = differences.Any() == false; ResultToOutput(isEqual, differences); diff --git a/ObjectsComparer/ObjectsComparer.Tests/ComparerTests.cs b/ObjectsComparer/ObjectsComparer.Tests/ComparerTests.cs index bf55943..07775fc 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/ComparerTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/ComparerTests.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.Linq; using NSubstitute; using NUnit.Framework; @@ -59,6 +60,8 @@ public void ReadOnlyPropertyEquality() [Test] public void ReadOnlyPropertyInequality() { + CultureInfo.CurrentCulture = new CultureInfo("en"); + var a1 = new A(1.99); var a2 = new A(0.89); var comparer = new Comparer(); diff --git a/ObjectsComparer/ObjectsComparer.Tests/Comparer_ExpandoObjectsTests.cs b/ObjectsComparer/ObjectsComparer.Tests/Comparer_ExpandoObjectsTests.cs index 556996d..289678f 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/Comparer_ExpandoObjectsTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/Comparer_ExpandoObjectsTests.cs @@ -120,12 +120,9 @@ public void Hierarchy_CheckComparisonContext() Assert.AreEqual(1, differences.Count); Assert.IsTrue(differences.Any(d => d.MemberPath == "FieldSub1.Field1" && d.Value1 == "10" && d.Value2 == "8")); - var ctx = new ComparisonContext(); - var calcDifferences = comparer.CalculateDifferences(typeof(object), (object)a1, (object)a2, ctx).ToArray(); - var ctxDifferences = ctx.GetDifferences(true).ToArray(); - - Assert.IsTrue(differences.AreEquivalent(calcDifferences)); - Assert.IsTrue(differences.AreEquivalent(ctxDifferences)); + var rootNode = comparer.CalculateDifferencesTree(typeof(object), (object)a1, (object)a2); + var treeDifferences = rootNode.GetDifferences(true).ToList(); + Assert.IsTrue(treeDifferences.Any(d => d.MemberPath == "FieldSub1.Field1" && d.Value1 == "10" && d.Value2 == "8")); } [Test] @@ -296,13 +293,14 @@ public void UseDefaultValuesWhenSubclassNotSpecified_CheckComparisonContext() dynamic a2 = new ExpandoObject(); var comparer = new Comparer(new ComparisonSettings { UseDefaultIfMemberNotExist = true }); - var rootComparisonContext = new ComparisonContext(); - IEnumerable diffs = comparer.CalculateDifferences(((object)a1).GetType(), a1, a2, rootComparisonContext); + var obja1 = (object)a1; + var obja2 = (object)a2; + + var rootNode = comparer.CalculateDifferencesTree(((object)a1).GetType(), obja1, obja2); + IEnumerable diffs = rootNode.GetDifferences(true); var differences = diffs.ToArray(); - var comparisonContextDifferences = rootComparisonContext.GetDifferences(recursive: true).ToList(); CollectionAssert.IsEmpty(differences); - CollectionAssert.IsEmpty(comparisonContextDifferences); } [Test] @@ -344,12 +342,15 @@ public void DifferenceWhenSubclassNotSpecified_CheckComparisonContext() Assert.IsTrue(compareDifferences.Any( d => d.MemberPath == "Field1" && d.DifferenceType == DifferenceTypes.MissedMemberInSecondObject)); - var rootComparisonContext = new ComparisonContext(); - IEnumerable calculateDiffs = comparer.CalculateDifferences(((object)a1).GetType(), a1, a2, rootComparisonContext); - var calculateDifferences = calculateDiffs.ToList(); - var comparisonContextDifferences = rootComparisonContext.GetDifferences(recursive: true).ToList(); + var obja1 = (object)a1; + var obja2 = (object)a2; - CollectionAssert.AreEquivalent(calculateDifferences, comparisonContextDifferences); + var rootNode = comparer.CalculateDifferencesTree(((object)a1).GetType(), obja1, obja2); + var calculateDifferences = rootNode.GetDifferences(true).ToList(); + + Assert.AreEqual(1, calculateDifferences.Count); + Assert.IsTrue(calculateDifferences.Any( + d => d.MemberPath == "Field1" && d.DifferenceType == DifferenceTypes.MissedMemberInSecondObject)); } [Test] diff --git a/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs b/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs index 95eb89c..232647e 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs @@ -65,11 +65,12 @@ public void PrimitiveTypeArrayInequalityCount_CompareUnequalLists() var a2 = new A { IntArray = new[] { 1, 2, 3 } }; var settings = new ComparisonSettings(); - settings.ConfigureListComparison(listOptions => listOptions.CompareUnequalLists(true)); + settings.ConfigureListComparison(compareUnequalLists: true); var comparer = new Comparer(settings); - var rootCtx = new ComparisonContext(); - var differences = comparer.CalculateDifferences(a1, a2, rootCtx).ToList(); + + var rootNode = comparer.CalculateDifferencesTree(a1, a2); + var differences = rootNode.GetDifferences(true).ToList(); CollectionAssert.IsNotEmpty(differences); Assert.AreEqual(2, differences.Count); @@ -82,11 +83,6 @@ public void PrimitiveTypeArrayInequalityCount_CompareUnequalLists() Assert.AreEqual("IntArray.Length", differences[1].MemberPath); Assert.AreEqual("2", differences[1].Value1); Assert.AreEqual("3", differences[1].Value2); - - var diffsFromCtx = rootCtx.GetDifferences(recursive: true).ToList(); - Assert.AreEqual(2, diffsFromCtx.Count); - Assert.AreEqual(differences[0], diffsFromCtx[0]); - Assert.AreEqual(differences[1], diffsFromCtx[1]); } [Test] diff --git a/ObjectsComparer/ObjectsComparer.Tests/Comparer_MultidimensionalArraysTests.cs b/ObjectsComparer/ObjectsComparer.Tests/Comparer_MultidimensionalArraysTests.cs index 6ad5684..3d34338 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/Comparer_MultidimensionalArraysTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/Comparer_MultidimensionalArraysTests.cs @@ -412,20 +412,14 @@ public void IntIntInequality7_CheckComparisonContext() var a2 = new MultidimensionalArrays { IntInt = null }; var comparer = new Comparer(); - var rootComparisonContext = new ComparisonContext(); - var differences = comparer.CalculateDifferences(a1, a2, rootComparisonContext).ToList(); + var rootNode = comparer.CalculateDifferencesTree(a1, a2); + var differences = rootNode.GetDifferences(true).ToList(); CollectionAssert.IsNotEmpty(differences); Assert.AreEqual(1, differences.Count()); Assert.AreEqual("IntInt", differences[0].MemberPath); Assert.AreEqual(typeof(int[,]).FullName, differences[0].Value1); Assert.AreEqual(string.Empty, differences[0].Value2); - - var comparisonContextDifferences = rootComparisonContext.GetDifferences(recursive: true).ToList(); - - comparisonContextDifferences.ForEach(ctxDiff => CollectionAssert.Contains(differences, ctxDiff)); - - differences.ForEach(diff => CollectionAssert.Contains(comparisonContextDifferences, diff)); } [Test] diff --git a/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs b/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs index a998e07..0779652 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs @@ -183,22 +183,18 @@ public void InequalityProperty_CompareByKey() var a2 = new A { NonGenericEnumerable = new ArrayList { new B { Property1 = "Str3", Id = 2 }, new B { Property1 = "Str1", Id = 1 } } }; var settings = new ComparisonSettings(); - settings.ConfigureListComparison(listOptions => listOptions.CompareElementsByKey()); + settings.ConfigureListComparison(compareElementsByKey: true); var comparer = new Comparer(settings); - var rootCtx = new ComparisonContext(); - var differences = comparer.CalculateDifferences(a1, a2, rootCtx).ToList(); + var rootNode = comparer.CalculateDifferencesTree(a1, a2); + var differences = rootNode.GetDifferences(true); CollectionAssert.IsNotEmpty(differences); var diff = differences.First(); Assert.AreEqual("NonGenericEnumerable[2].Property1", diff.MemberPath); Assert.AreEqual("Str2", diff.Value1); Assert.AreEqual("Str3", diff.Value2); - - var diffFromCtx = rootCtx.GetDifferences(recursive: true).FirstOrDefault(); - Assert.NotNull(diffFromCtx); - Assert.AreEqual(diff, diffFromCtx); } [Test] diff --git a/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs b/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs index 0ac4689..b73ecb2 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs @@ -113,8 +113,8 @@ public void FluentTest_CompareUnequalLists() settings.ConfigureListComparison(compareUnequalLists: true); var comparer = new Comparer(settings); - var ctx = new ComparisonContext(); - var differences = comparer.CalculateDifferences(a1.GetType(), a1, a2, ctx).ToList(); + var rootNode = comparer.CalculateDifferencesTree(a1.GetType(), a1, a2); + var differences = rootNode.GetDifferences(true).ToList(); Assert.AreEqual(4, differences.Count); @@ -137,8 +137,6 @@ public void FluentTest_CompareUnequalLists() Assert.AreEqual("Length", differences[3].MemberPath); Assert.AreEqual("3", differences[3].Value1); Assert.AreEqual("4", differences[3].Value2); - - Assert.IsTrue(differences.AreEquivalent(ctx.GetDifferences(true))); } [Test] @@ -151,8 +149,9 @@ public void FluentTest_CompareUnequalLists_ByKey() settings.ConfigureListComparison(compareUnequalLists: true, compareElementsByKey: true); var comparer = new Comparer(settings); - var ctx = new ComparisonContext(); - var differences = comparer.CalculateDifferences(a1.GetType(), a1, a2, ctx).ToList(); + + var rootNode = comparer.CalculateDifferencesTree(a1.GetType(), a1, a2); + var differences = rootNode.GetDifferences(true).ToList(); Assert.AreEqual(2, differences.Count); @@ -165,8 +164,6 @@ public void FluentTest_CompareUnequalLists_ByKey() Assert.AreEqual("Length", differences[1].MemberPath); Assert.AreEqual("3", differences[1].Value1); Assert.AreEqual("4", differences[1].Value2); - - Assert.IsTrue(differences.AreEquivalent(ctx.GetDifferences(true))); } [Test] diff --git a/ObjectsComparer/ObjectsComparer/Comparer.cs b/ObjectsComparer/ObjectsComparer/Comparer.cs index 70a3ae4..4b4c430 100644 --- a/ObjectsComparer/ObjectsComparer/Comparer.cs +++ b/ObjectsComparer/ObjectsComparer/Comparer.cs @@ -54,17 +54,51 @@ IEnumerable IContextableComparer.CalculateDifferences(Type t { if (comparer is IContextableComparer contextableComparer) { - return contextableComparer.CalculateDifferences(type, obj1, obj2, comparisonContext); + var diffLocationList = contextableComparer.CalculateDifferences(type, obj1, obj2, comparisonContext); + + foreach (var diffLocation in diffLocationList) + { + yield return diffLocation; + } + + yield break; } } + ContextableExtensions.ThrowContextableComparerNotImplemented(comparisonContext, Settings, comparer, $"{nameof(IContextableComparer)}<{type.FullName}>"); + var genericType = comparerIsIContextableComparerT ? typeof(IContextableComparer<>).MakeGenericType(type) : typeof(IComparer<>).MakeGenericType(type); var genericMethodParameterTypes = comparerIsIContextableComparerT ? new[] { type, type, typeof(IComparisonContext) } : new[] { type, type }; var genericMethod = genericType.GetTypeInfo().GetMethod(CalculateDifferencesMethodName, genericMethodParameterTypes); var genericMethodParameters = comparerIsIContextableComparerT ? new[] { obj1, obj2, comparisonContext } : new[] { obj1, obj2 }; // ReSharper disable once PossibleNullReferenceException - return (IEnumerable)genericMethod.Invoke(comparer, genericMethodParameters); + //return (IEnumerable)genericMethod.Invoke(comparer, genericMethodParameters); + + var returnValue = genericMethod.Invoke(comparer, genericMethodParameters); + + if (returnValue is IEnumerable differenceLocationList) + { + foreach (var differenceLocation in differenceLocationList) + { + yield return differenceLocation; + } + + yield break; + } + + if (returnValue is IEnumerable differenceList) + { + foreach (var difference in differenceList) + { + yield return new DifferenceLocation(difference); + } + + yield break; + } + + //TODO: + throw new NotImplementedException(""); } } } diff --git a/ObjectsComparer/ObjectsComparer/Context/ComparerExtensions.cs b/ObjectsComparer/ObjectsComparer/Context/ComparerExtensions.cs index f630c16..b393882 100644 --- a/ObjectsComparer/ObjectsComparer/Context/ComparerExtensions.cs +++ b/ObjectsComparer/ObjectsComparer/Context/ComparerExtensions.cs @@ -22,6 +22,9 @@ public static IComparisonContext CalculateDifferencesTree(this IComparer compare throw new ArgumentNullException(nameof(type)); } + findNextDifference = findNextDifference ?? ((_) => true); + + //Anything but ImplicitComparisonContext (ImplicitDifferenceTreeNode). var rootCtx = ComparisonContextProvider.CreateContext(comparer.Settings, ancestor: null); var differenceLocationList = comparer.CalculateDifferences(type, obj1, obj2, rootCtx); @@ -39,7 +42,7 @@ public static IComparisonContext CalculateDifferencesTree(this IComparer compare /// /// Calculates list of differences between objects. Accepts comparison context. /// - public static IComparisonContext CalculateContextableDifferences(this IComparer comparer, T obj1, T obj2, Func findNextDifference = null, Action contextCompleted = null) + public static IComparisonContext CalculateDifferencesTree(this IComparer comparer, T obj1, T obj2, Func findNextDifference = null, Action contextCompleted = null) { if (comparer is null) { diff --git a/ObjectsComparer/ObjectsComparer/Context/ContextableExtensions.cs b/ObjectsComparer/ObjectsComparer/Context/ContextableExtensions.cs index 112a3c2..93741ca 100644 --- a/ObjectsComparer/ObjectsComparer/Context/ContextableExtensions.cs +++ b/ObjectsComparer/ObjectsComparer/Context/ContextableExtensions.cs @@ -49,7 +49,6 @@ public static IEnumerable CalculateDifferences(this ICompare { yield return new DifferenceLocation(difference); } - } /// @@ -111,7 +110,7 @@ static bool HasComparisonContextImplicitRoot(IComparisonContext comparisonContex return false; } - static void ThrowContextableComparerNotImplemented(IComparisonContext comparisonContext, ComparisonSettings comparisonSettings, object comparer, string unImplementedInterface) + internal static void ThrowContextableComparerNotImplemented(IComparisonContext comparisonContext, ComparisonSettings comparisonSettings, object comparer, string unImplementedInterface) { if (comparisonContext is null) { From f6721a0582085e9c4b26be43ae00c8891e0b4025 Mon Sep 17 00:00:00 2001 From: Daniel Nemec Date: Wed, 6 Apr 2022 08:53:09 +0200 Subject: [PATCH 120/181] Edit ReadOnlyPropertyInequality test: Use the current decimal separator from current culture. Otherwise, the test may fail depending on the culture. --- ObjectsComparer/ObjectsComparer.Tests/ComparerTests.cs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/ObjectsComparer/ObjectsComparer.Tests/ComparerTests.cs b/ObjectsComparer/ObjectsComparer.Tests/ComparerTests.cs index 07775fc..b324e6b 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/ComparerTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/ComparerTests.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Globalization; using System.Linq; +using System.Threading; using NSubstitute; using NUnit.Framework; using ObjectsComparer.Tests.TestClasses; @@ -60,8 +61,6 @@ public void ReadOnlyPropertyEquality() [Test] public void ReadOnlyPropertyInequality() { - CultureInfo.CurrentCulture = new CultureInfo("en"); - var a1 = new A(1.99); var a2 = new A(0.89); var comparer = new Comparer(); @@ -70,8 +69,11 @@ public void ReadOnlyPropertyInequality() CollectionAssert.IsNotEmpty(differences); Assert.AreEqual("ReadOnlyProperty", differences.First().MemberPath); - Assert.AreEqual("1.99", differences.First().Value1); - Assert.AreEqual("0.89", differences.First().Value2); + //Assert.AreEqual("1.99", differences.First().Value1); + //Assert.AreEqual("0.89", differences.First().Value2); + NumberFormatInfo nfi = CultureInfo.CurrentCulture.NumberFormat; + Assert.AreEqual($"1{nfi.NumberDecimalSeparator}99", differences.First().Value1); + Assert.AreEqual($"0{nfi.NumberDecimalSeparator}89", differences.First().Value2); } [Test] From 9552c3bf6dfa27ba3fc11c79df244f1ff64352e7 Mon Sep 17 00:00:00 2001 From: nemec Date: Mon, 11 Apr 2022 19:37:54 +0200 Subject: [PATCH 121/181] Move ThrowContextableComparerNotImplemented. --- ObjectsComparer/ObjectsComparer/Comparer.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ObjectsComparer/ObjectsComparer/Comparer.cs b/ObjectsComparer/ObjectsComparer/Comparer.cs index 4b4c430..f74161c 100644 --- a/ObjectsComparer/ObjectsComparer/Comparer.cs +++ b/ObjectsComparer/ObjectsComparer/Comparer.cs @@ -63,9 +63,9 @@ IEnumerable IContextableComparer.CalculateDifferences(Type t yield break; } - } - ContextableExtensions.ThrowContextableComparerNotImplemented(comparisonContext, Settings, comparer, $"{nameof(IContextableComparer)}<{type.FullName}>"); + ContextableExtensions.ThrowContextableComparerNotImplemented(comparisonContext, Settings, comparer, $"{nameof(IContextableComparer)}<{type.FullName}>"); + } var genericType = comparerIsIContextableComparerT ? typeof(IContextableComparer<>).MakeGenericType(type) : typeof(IComparer<>).MakeGenericType(type); var genericMethodParameterTypes = comparerIsIContextableComparerT ? new[] { type, type, typeof(IComparisonContext) } : new[] { type, type }; From 007196610b8bb8a69e9f934ebb4c3b9dd074c9e7 Mon Sep 17 00:00:00 2001 From: nemec Date: Mon, 11 Apr 2022 19:54:43 +0200 Subject: [PATCH 122/181] Clean up (unused classes). --- .../Context/CreateComparisonContextArgs.cs | 64 ------------------- .../DefaultComparisonContextFactory.cs | 32 ---------- ...eTreeNodeInfo.cs => DifferenceLocation.cs} | 0 3 files changed, 96 deletions(-) delete mode 100644 ObjectsComparer/ObjectsComparer/Context/CreateComparisonContextArgs.cs delete mode 100644 ObjectsComparer/ObjectsComparer/Context/DefaultComparisonContextFactory.cs rename ObjectsComparer/ObjectsComparer/Context/{DifferenceTreeNodeInfo.cs => DifferenceLocation.cs} (100%) diff --git a/ObjectsComparer/ObjectsComparer/Context/CreateComparisonContextArgs.cs b/ObjectsComparer/ObjectsComparer/Context/CreateComparisonContextArgs.cs deleted file mode 100644 index 1c09d8e..0000000 --- a/ObjectsComparer/ObjectsComparer/Context/CreateComparisonContextArgs.cs +++ /dev/null @@ -1,64 +0,0 @@ -using System.Reflection; - -namespace ObjectsComparer -{ - /// - /// Arguments for factory method. See . - /// If all properties are null, the instance is probably intended to create a root context. - /// - public class CreateComparisonContextArgs - { - /// - /// Context without ancestor and without member. - /// - internal CreateComparisonContextArgs() - { - } - - /// - /// Context with ancestor but without a member. - /// - internal CreateComparisonContextArgs(IComparisonContext ancestor) - { - Ancestor = ancestor ?? throw new System.ArgumentNullException(nameof(ancestor)); - } - - /// - /// Context with ancestor and member. - /// - internal CreateComparisonContextArgs(IComparisonContext ancestor, MemberInfo member) - { - Ancestor = ancestor ?? throw new System.ArgumentNullException(nameof(ancestor)); - Member = member ?? throw new System.ArgumentNullException(nameof(member)); - } - - /// - /// Context with ancestor and member. - /// - internal CreateComparisonContextArgs(IComparisonContext ancestor, string memberName) - { - if (string.IsNullOrEmpty(memberName)) - { - throw new System.ArgumentException($"'{nameof(memberName)}' cannot be null or empty.", nameof(memberName)); - } - - Ancestor = ancestor ?? throw new System.ArgumentNullException(nameof(ancestor)); - MemberName = memberName; - } - - /// - /// Nullable. - /// - public IComparisonContext Ancestor { get; } - - /// - /// Nullable. - /// - public MemberInfo Member { get; } - - /// - /// Nullable. - /// - public string MemberName { get; } - } -} diff --git a/ObjectsComparer/ObjectsComparer/Context/DefaultComparisonContextFactory.cs b/ObjectsComparer/ObjectsComparer/Context/DefaultComparisonContextFactory.cs deleted file mode 100644 index a5c4ee0..0000000 --- a/ObjectsComparer/ObjectsComparer/Context/DefaultComparisonContextFactory.cs +++ /dev/null @@ -1,32 +0,0 @@ -//using System.Reflection; - -//namespace ObjectsComparer -//{ -// internal class DefaultComparisonContextFactory : IComparisonContextFactory -// { -// public IComparisonContext CreateContext(IComparisonContext ancestor = null, string memberName = null) -// { -// return new ComparisonContext(CreateMember(memberName, null), ancestor); -// } - -// public IComparisonContext CreateContext(IComparisonContext ancestor = null, MemberInfo member = null) -// { -// return new ComparisonContext(CreateMember(null, member), ancestor); -// } - -// internal static IComparisonContextMember CreateMember(string memberName, MemberInfo member) -// { -// if (member != null) -// { -// return new ComparisonContextMember(member); -// } - -// if (string.IsNullOrWhiteSpace(memberName)) -// { -// return new ComparisonContextMember(); -// } - -// return new ComparisonContextMember(memberName); -// } -// } -//} diff --git a/ObjectsComparer/ObjectsComparer/Context/DifferenceTreeNodeInfo.cs b/ObjectsComparer/ObjectsComparer/Context/DifferenceLocation.cs similarity index 100% rename from ObjectsComparer/ObjectsComparer/Context/DifferenceTreeNodeInfo.cs rename to ObjectsComparer/ObjectsComparer/Context/DifferenceLocation.cs From fc1c697f9c620781cc52ef7796a336d8bf8b9613 Mon Sep 17 00:00:00 2001 From: nemec Date: Mon, 11 Apr 2022 20:06:32 +0200 Subject: [PATCH 123/181] Edit comment. --- ObjectsComparer/ObjectsComparer/Context/DifferenceLocation.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ObjectsComparer/ObjectsComparer/Context/DifferenceLocation.cs b/ObjectsComparer/ObjectsComparer/Context/DifferenceLocation.cs index 1930d1b..094e690 100644 --- a/ObjectsComparer/ObjectsComparer/Context/DifferenceLocation.cs +++ b/ObjectsComparer/ObjectsComparer/Context/DifferenceLocation.cs @@ -3,7 +3,7 @@ namespace ObjectsComparer.ContextExtensions { /// - /// The location of the in the difference tree. + /// The location of the difference in the difference tree. /// public class DifferenceLocation { From 3ca3d92e3a5237b4cf2c3ff55563edaa46d50a75 Mon Sep 17 00:00:00 2001 From: nemec Date: Mon, 11 Apr 2022 23:11:40 +0200 Subject: [PATCH 124/181] Rename *context* with difference tree. --- .../ComparisonContextTests.cs | 10 +++---- .../ComparisonSettingsTests.cs | 2 +- ...omparisonContextSerializationExtensions.cs | 24 ++++++++-------- .../ObjectsComparer/BaseComparer.cs | 4 +-- ObjectsComparer/ObjectsComparer/Comparer.cs | 24 ++++++++++------ ObjectsComparer/ObjectsComparer/Comparer~1.cs | 6 ++-- .../ObjectsComparer/ComparisonSettings.cs | 8 +++--- .../Context/ComparerExtensions.cs | 4 +-- .../Context/ComparisonContext.cs | 19 ------------- .../Context/ComparisonContextOptions.cs | 12 ++++---- .../Context/ComparisonContextProvider.cs | 28 +++++++++---------- .../Context/ContextableExtensions.cs | 20 ++++++------- .../Context/DifferenceLocation.cs | 4 +-- .../Context/DifferenceTreeNode.cs | 19 +++++++++++++ ...ntextBase.cs => DifferenceTreeNodeBase.cs} | 22 +++++++-------- ...tMember.cs => DifferenceTreeNodeMember.cs} | 4 +-- .../Context/IContextableComparer.cs | 13 --------- .../Context/IContextableComparer~1.cs | 13 --------- .../Context/IDifferenceTreeBuilder.cs | 18 ++++++++++++ ...risonContext.cs => IDifferenceTreeNode.cs} | 16 +++++------ ...Member.cs => IDifferenceTreeNodeMember.cs} | 2 +- .../Context/IDifferencesTreeBuilder~1.cs | 18 ++++++++++++ .../Context/ImplicitComparisonContext.cs | 19 ------------- .../Context/ImplicitDifferenceTreeNode.cs | 19 +++++++++++++ .../AbstractDynamicObjectsComprer.cs | 8 +++--- .../AbstractEnumerablesComparer.cs | 4 +-- .../CustomComparers/EnumerablesComparer.cs | 6 ++-- .../EnumerablesComparerBase.cs | 6 ++-- .../CustomComparers/EnumerablesComparer~1.cs | 8 +++--- .../GenericEnumerablesComparer.cs | 2 +- .../CustomComparers/HashSetsComparer.cs | 2 +- .../CustomComparers/HashSetsComparer~1.cs | 6 ++-- .../MultidimensionalArrayComparer~1.cs | 6 ++-- .../MultidimensionalArraysComparer.cs | 2 +- .../CustomComparers/TypesComparer.cs | 4 +-- .../Exceptions/ElementKeyNotFoundException.cs | 6 ++-- 36 files changed, 202 insertions(+), 186 deletions(-) delete mode 100644 ObjectsComparer/ObjectsComparer/Context/ComparisonContext.cs create mode 100644 ObjectsComparer/ObjectsComparer/Context/DifferenceTreeNode.cs rename ObjectsComparer/ObjectsComparer/Context/{ComparisonContextBase.cs => DifferenceTreeNodeBase.cs} (75%) rename ObjectsComparer/ObjectsComparer/Context/{ComparisonContextMember.cs => DifferenceTreeNodeMember.cs} (59%) delete mode 100644 ObjectsComparer/ObjectsComparer/Context/IContextableComparer.cs delete mode 100644 ObjectsComparer/ObjectsComparer/Context/IContextableComparer~1.cs create mode 100644 ObjectsComparer/ObjectsComparer/Context/IDifferenceTreeBuilder.cs rename ObjectsComparer/ObjectsComparer/Context/{IComparisonContext.cs => IDifferenceTreeNode.cs} (76%) rename ObjectsComparer/ObjectsComparer/Context/{IComparisonContextMember.cs => IDifferenceTreeNodeMember.cs} (90%) create mode 100644 ObjectsComparer/ObjectsComparer/Context/IDifferencesTreeBuilder~1.cs delete mode 100644 ObjectsComparer/ObjectsComparer/Context/ImplicitComparisonContext.cs create mode 100644 ObjectsComparer/ObjectsComparer/Context/ImplicitDifferenceTreeNode.cs diff --git a/ObjectsComparer/ObjectsComparer.Tests/ComparisonContextTests.cs b/ObjectsComparer/ObjectsComparer.Tests/ComparisonContextTests.cs index 5dfde00..0a12875 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/ComparisonContextTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/ComparisonContextTests.cs @@ -16,7 +16,7 @@ internal class ComparisonContextTests [Test] public void ComparisonContextMember_Member_Correct_MemberName() { - var ctxMember = new ComparisonContextMember(name: "Property1"); + var ctxMember = new DifferenceTreeNodeMember(name: "Property1"); Assert.AreEqual("Property1", ctxMember.Name); Assert.AreEqual(null, ctxMember.Info); } @@ -25,7 +25,7 @@ public void ComparisonContextMember_Member_Correct_MemberName() public void ComparisonContextMember_Member_Correct_Member() { var memberInfo = typeof(Address).GetMember(nameof(Address.Country)).Single(); - var ctxMember = new ComparisonContextMember(memberInfo, memberInfo.Name); + var ctxMember = new DifferenceTreeNodeMember(memberInfo, memberInfo.Name); Assert.AreEqual(nameof(Address.Country), ctxMember.Info.Name); Assert.AreEqual(nameof(Address.Country), ctxMember.Name); } @@ -175,15 +175,15 @@ public override IEnumerable CalculateDifferences(string obj1, string } } - class CustomComparisonContext : ComparisonContextBase + class CustomComparisonContext : DifferenceTreeNodeBase { - public CustomComparisonContext(IComparisonContextMember member = null, IComparisonContext ancestor = null) : base(member, ancestor) + public CustomComparisonContext(IDifferenceTreeNodeMember member = null, IDifferenceTreeNode ancestor = null) : base(member, ancestor) { } } - class CustomComparisonContextMember : IComparisonContextMember + class CustomComparisonContextMember : IDifferenceTreeNodeMember { public CustomComparisonContextMember(string memberName) { diff --git a/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs b/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs index b73ecb2..5d3345d 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs @@ -81,7 +81,7 @@ public void CompareListElementsByKeyIsCorrectlySet() //Component side. var listComparisonOptions = ListComparisonOptions.Default(); - var ctx = new ComparisonContext(); + var ctx = new DifferenceTreeNode(); settings.ListComparisonOptionsAction(ctx, listComparisonOptions); var listElementComparisonByKeyOptions = ListElementComparisonByKeyOptions.Default(); listComparisonOptions.KeyOptionsAction(listElementComparisonByKeyOptions); diff --git a/ObjectsComparer/ObjectsComparer.Tests/Utils/ComparisonContextSerializationExtensions.cs b/ObjectsComparer/ObjectsComparer.Tests/Utils/ComparisonContextSerializationExtensions.cs index a6e3d71..30966bb 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/Utils/ComparisonContextSerializationExtensions.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/Utils/ComparisonContextSerializationExtensions.cs @@ -14,18 +14,18 @@ namespace ObjectsComparer.Tests.Utils internal static class ComparisonContextSerializationExtensions { /// - /// Serializes object to json string. + /// Serializes object to json string. /// /// /// /// /// - public static string ToJson(this ComparisonContext comparisonContext, bool skipEmptyList = true, bool skipNullReference = true) + public static string ToJson(this DifferenceTreeNode comparisonContext, bool skipEmptyList = true, bool skipNullReference = true) { return SerializeComparisonContext(comparisonContext, skipEmptyList, skipNullReference); } - static string SerializeComparisonContext(ComparisonContext context, bool skipEmptyList, bool skipNullReference) + static string SerializeComparisonContext(DifferenceTreeNode context, bool skipEmptyList, bool skipNullReference) { var settings = new JsonSerializerSettings() { @@ -76,29 +76,29 @@ protected override JsonProperty CreateProperty(MemberInfo member, MemberSerializ { JsonProperty property = base.CreateProperty(member, memberSerialization); - if (property.DeclaringType == typeof(ComparisonContext)) + if (property.DeclaringType == typeof(DifferenceTreeNode)) { property.ShouldSerialize = instance => { - ComparisonContext ctx = (ComparisonContext)instance; + DifferenceTreeNode ctx = (DifferenceTreeNode)instance; - if (property.PropertyName == nameof(ComparisonContext.Descendants)) + if (property.PropertyName == nameof(DifferenceTreeNode.Descendants)) { return _skipEmptyList == false || ctx.Descendants.Any(); } - if (property.PropertyName == nameof(ComparisonContext.Differences)) + if (property.PropertyName == nameof(DifferenceTreeNode.Differences)) { return _skipEmptyList == false || ctx.Differences.Any(); } - if (property.PropertyName == nameof(ComparisonContext.Member)) + if (property.PropertyName == nameof(DifferenceTreeNode.Member)) { return _skipNullReference == false || ctx.Member != null; } - if (property.PropertyName == nameof(ComparisonContext.Ancestor)) + if (property.PropertyName == nameof(DifferenceTreeNode.Ancestor)) { return _skipNullReference == false || ctx.Ancestor != null; } @@ -106,7 +106,7 @@ protected override JsonProperty CreateProperty(MemberInfo member, MemberSerializ return true; }; - //if (property.PropertyName == nameof(ComparisonContext.Ancestor)) + //if (property.PropertyName == nameof(DifferenceTreeNode.Ancestor)) //{ // property.ValueProvider = new AncestorValueProvider(); //} @@ -120,8 +120,8 @@ protected override JsonProperty CreateProperty(MemberInfo member, MemberSerializ //{ // public object GetValue(object target) // { - // var ancestor = (target as ComparisonContext).Ancestor; - // var newAncestor = new ComparisonContext(member: ancestor?.Member); + // var ancestor = (target as DifferenceTreeNode).Ancestor; + // var newAncestor = new DifferenceTreeNode(member: ancestor?.Member); // return newAncestor; // } diff --git a/ObjectsComparer/ObjectsComparer/BaseComparer.cs b/ObjectsComparer/ObjectsComparer/BaseComparer.cs index 95fc192..be505d6 100644 --- a/ObjectsComparer/ObjectsComparer/BaseComparer.cs +++ b/ObjectsComparer/ObjectsComparer/BaseComparer.cs @@ -186,10 +186,10 @@ public void IgnoreMember(Func filter) } /// - /// Adds an to the end of the 's . + /// Adds an to the end of the 's . /// /// The instance. - protected virtual DifferenceLocation AddDifferenceToTree(Difference difference, IComparisonContext comparisonContext) + protected virtual DifferenceLocation AddDifferenceToTree(Difference difference, IDifferenceTreeNode comparisonContext) { if (difference is null) { diff --git a/ObjectsComparer/ObjectsComparer/Comparer.cs b/ObjectsComparer/ObjectsComparer/Comparer.cs index f74161c..4e45e91 100644 --- a/ObjectsComparer/ObjectsComparer/Comparer.cs +++ b/ObjectsComparer/ObjectsComparer/Comparer.cs @@ -10,7 +10,7 @@ namespace ObjectsComparer /// /// Compares objects. /// - public class Comparer : AbstractComparer, IContextableComparer + public class Comparer : AbstractComparer, IDifferenceTreeBuilder { private static string CalculateDifferencesMethodName { @@ -18,6 +18,11 @@ private static string CalculateDifferencesMethodName get { return MemberInfoExtensions.GetMethodName>(x => x.CalculateDifferences(null, null)); } } + private static string BuildDifferencesTreeMethodName + { + get { return MemberInfoExtensions.GetMethodName>(x => x.BuildDifferencesTree(null, null, null)); } + } + /// /// Initializes a new instance of the class. /// @@ -34,9 +39,9 @@ public override IEnumerable CalculateDifferences(Type type, object o .Select(differenceLoccation => differenceLoccation.Difference); } - IContextableComparer AsContextableComparer() => this; + IDifferenceTreeBuilder AsContextableComparer() => this; - IEnumerable IContextableComparer.CalculateDifferences(Type type, object obj1, object obj2, IComparisonContext comparisonContext) + IEnumerable IDifferenceTreeBuilder.CalculateDifferences(Type type, object obj1, object obj2, IDifferenceTreeNode comparisonContext) { if (comparisonContext is null) { @@ -48,11 +53,11 @@ IEnumerable IContextableComparer.CalculateDifferences(Type t var comparer = getObjectsComparerGenericMethod.Invoke(Factory, new object[] { Settings, this }); bool comparerIsIContextableComparerT = comparer.GetType().GetTypeInfo().GetInterfaces() - .Any(intft => intft.GetTypeInfo().IsGenericType && intft.GetGenericTypeDefinition() == typeof(IContextableComparer<>)); + .Any(intft => intft.GetTypeInfo().IsGenericType && intft.GetGenericTypeDefinition() == typeof(IDifferenceTreeBuilder<>)); if (comparerIsIContextableComparerT == false) { - if (comparer is IContextableComparer contextableComparer) + if (comparer is IDifferenceTreeBuilder contextableComparer) { var diffLocationList = contextableComparer.CalculateDifferences(type, obj1, obj2, comparisonContext); @@ -64,12 +69,13 @@ IEnumerable IContextableComparer.CalculateDifferences(Type t yield break; } - ContextableExtensions.ThrowContextableComparerNotImplemented(comparisonContext, Settings, comparer, $"{nameof(IContextableComparer)}<{type.FullName}>"); + ContextableExtensions.ThrowContextableComparerNotImplemented(comparisonContext, Settings, comparer, $"{nameof(IDifferenceTreeBuilder)}<{type.FullName}>"); } - var genericType = comparerIsIContextableComparerT ? typeof(IContextableComparer<>).MakeGenericType(type) : typeof(IComparer<>).MakeGenericType(type); - var genericMethodParameterTypes = comparerIsIContextableComparerT ? new[] { type, type, typeof(IComparisonContext) } : new[] { type, type }; - var genericMethod = genericType.GetTypeInfo().GetMethod(CalculateDifferencesMethodName, genericMethodParameterTypes); + var genericType = comparerIsIContextableComparerT ? typeof(IDifferenceTreeBuilder<>).MakeGenericType(type) : typeof(IComparer<>).MakeGenericType(type); + var genericMethodName = comparerIsIContextableComparerT ? BuildDifferencesTreeMethodName : CalculateDifferencesMethodName; + var genericMethodParameterTypes = comparerIsIContextableComparerT ? new[] { type, type, typeof(IDifferenceTreeNode) } : new[] { type, type }; + var genericMethod = genericType.GetTypeInfo().GetMethod(genericMethodName, genericMethodParameterTypes); var genericMethodParameters = comparerIsIContextableComparerT ? new[] { obj1, obj2, comparisonContext } : new[] { obj1, obj2 }; // ReSharper disable once PossibleNullReferenceException diff --git a/ObjectsComparer/ObjectsComparer/Comparer~1.cs b/ObjectsComparer/ObjectsComparer/Comparer~1.cs index 0323564..0694e70 100644 --- a/ObjectsComparer/ObjectsComparer/Comparer~1.cs +++ b/ObjectsComparer/ObjectsComparer/Comparer~1.cs @@ -11,7 +11,7 @@ namespace ObjectsComparer /// /// Compares objects of type . /// - public class Comparer : AbstractComparer, IContextableComparer + public class Comparer : AbstractComparer, IDifferenceTreeBuilder { private readonly List _members; private readonly List _conditionalComparers; @@ -57,7 +57,7 @@ public override IEnumerable CalculateDifferences(T obj1, T obj2) return CalculateDifferences(obj1, obj2, memberInfo: null); } - IEnumerable IContextableComparer.CalculateDifferences(T obj1, T obj2, IComparisonContext comparisonContext) + IEnumerable IDifferenceTreeBuilder.BuildDifferencesTree(T obj1, T obj2, IDifferenceTreeNode comparisonContext) { return CalculateDifferences(obj1, obj2, memberInfo: null, comparisonContext); } @@ -68,7 +68,7 @@ internal IEnumerable CalculateDifferences(T obj1, T obj2, MemberInfo .Select(differenceLocation => differenceLocation.Difference); } - IEnumerable CalculateDifferences(T obj1, T obj2, MemberInfo memberInfo, IComparisonContext comparisonContext) + IEnumerable CalculateDifferences(T obj1, T obj2, MemberInfo memberInfo, IDifferenceTreeNode comparisonContext) { var comparer = memberInfo != null ? OverridesCollection.GetComparer(memberInfo) diff --git a/ObjectsComparer/ObjectsComparer/ComparisonSettings.cs b/ObjectsComparer/ObjectsComparer/ComparisonSettings.cs index 9f9fe5a..0042854 100644 --- a/ObjectsComparer/ObjectsComparer/ComparisonSettings.cs +++ b/ObjectsComparer/ObjectsComparer/ComparisonSettings.cs @@ -67,13 +67,13 @@ public T GetCustomSetting(string key = null) throw new KeyNotFoundException(); } - internal Action ListComparisonOptionsAction { get; private set; } = null; + internal Action ListComparisonOptionsAction { get; private set; } = null; /// /// Configures list comparison behavior, especially the type of the comparison. For more info, see . /// /// First parameter: Current list comparison context. - public ComparisonSettings ConfigureListComparison(Action comparisonOptions) + public ComparisonSettings ConfigureListComparison(Action comparisonOptions) { if (comparisonOptions is null) { @@ -117,9 +117,9 @@ public void ConfigureListComparison(bool compareElementsByKey = false, bool comp }); } - internal Action ComparisonContextOptionsAction { get; private set; } + internal Action ComparisonContextOptionsAction { get; private set; } - public void ConfigureComparisonContext(Action options) + public void ConfigureComparisonContext(Action options) { ComparisonContextOptionsAction = options ?? throw new ArgumentNullException(nameof(options)); } diff --git a/ObjectsComparer/ObjectsComparer/Context/ComparerExtensions.cs b/ObjectsComparer/ObjectsComparer/Context/ComparerExtensions.cs index b393882..7af178f 100644 --- a/ObjectsComparer/ObjectsComparer/Context/ComparerExtensions.cs +++ b/ObjectsComparer/ObjectsComparer/Context/ComparerExtensions.cs @@ -10,7 +10,7 @@ public static class ComparerExtensions /// /// Calculates list of differences between objects. Accepts comparison context. /// - public static IComparisonContext CalculateDifferencesTree(this IComparer comparer, Type type, object obj1, object obj2, Func findNextDifference = null, Action contextCompleted = null) + public static IDifferenceTreeNode CalculateDifferencesTree(this IComparer comparer, Type type, object obj1, object obj2, Func findNextDifference = null, Action contextCompleted = null) { if (comparer is null) { @@ -42,7 +42,7 @@ public static IComparisonContext CalculateDifferencesTree(this IComparer compare /// /// Calculates list of differences between objects. Accepts comparison context. /// - public static IComparisonContext CalculateDifferencesTree(this IComparer comparer, T obj1, T obj2, Func findNextDifference = null, Action contextCompleted = null) + public static IDifferenceTreeNode CalculateDifferencesTree(this IComparer comparer, T obj1, T obj2, Func findNextDifference = null, Action contextCompleted = null) { if (comparer is null) { diff --git a/ObjectsComparer/ObjectsComparer/Context/ComparisonContext.cs b/ObjectsComparer/ObjectsComparer/Context/ComparisonContext.cs deleted file mode 100644 index cb9b821..0000000 --- a/ObjectsComparer/ObjectsComparer/Context/ComparisonContext.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Linq; -using System.Reflection; - -namespace ObjectsComparer -{ - /// - /// Default implementation of . - /// - public sealed class ComparisonContext : ComparisonContextBase - { - public ComparisonContext(IComparisonContextMember member = null, IComparisonContext ancestor = null) : base(member, ancestor) - { - - } - } -} \ No newline at end of file diff --git a/ObjectsComparer/ObjectsComparer/Context/ComparisonContextOptions.cs b/ObjectsComparer/ObjectsComparer/Context/ComparisonContextOptions.cs index 93df834..d9db404 100644 --- a/ObjectsComparer/ObjectsComparer/Context/ComparisonContextOptions.cs +++ b/ObjectsComparer/ObjectsComparer/Context/ComparisonContextOptions.cs @@ -15,23 +15,23 @@ internal static ComparisonContextOptions Default() return new ComparisonContextOptions(); } - internal Func ComparisonContextFactory { get; private set; } + internal Func ComparisonContextFactory { get; private set; } - internal Func ComparisonContextMemberFactory { get; private set; } + internal Func ComparisonContextMemberFactory { get; private set; } /// - /// Factory for instances. + /// Factory for instances. /// /// - public void UseComparisonContextFactory(Func factory) + public void UseComparisonContextFactory(Func factory) { ComparisonContextFactory = factory ?? throw new ArgumentNullException(nameof(factory)); } /// - /// Factory for instances. + /// Factory for instances. /// - public void UseComparisonContextMemberFactory(Func factory) + public void UseComparisonContextMemberFactory(Func factory) { ComparisonContextMemberFactory = factory ?? throw new ArgumentNullException(nameof(factory)); } diff --git a/ObjectsComparer/ObjectsComparer/Context/ComparisonContextProvider.cs b/ObjectsComparer/ObjectsComparer/Context/ComparisonContextProvider.cs index df8abdf..d4513e0 100644 --- a/ObjectsComparer/ObjectsComparer/Context/ComparisonContextProvider.cs +++ b/ObjectsComparer/ObjectsComparer/Context/ComparisonContextProvider.cs @@ -5,39 +5,39 @@ namespace ObjectsComparer { public static class ComparisonContextProvider { - public static IComparisonContext CreateRootContext() + public static IDifferenceTreeNode CreateRootContext() { - return new ComparisonContext(new ComparisonContextMember()); + return new DifferenceTreeNode(new DifferenceTreeNodeMember()); } - internal static IComparisonContext CreateImplicitRootContext(ComparisonSettings comparisonSettings) + internal static IDifferenceTreeNode CreateImplicitRootContext(ComparisonSettings comparisonSettings) { _ = comparisonSettings ?? throw new ArgumentNullException(nameof(comparisonSettings)); - return new ImplicitComparisonContext(new ComparisonContextMember()); + return new ImplicitDifferenceTreeNode(new DifferenceTreeNodeMember()); } - public static IComparisonContext CreateContext(ComparisonSettings comparisonSettings, IComparisonContext ancestor) + public static IDifferenceTreeNode CreateContext(ComparisonSettings comparisonSettings, IDifferenceTreeNode ancestor) { - return CreateContext(comparisonSettings, new ComparisonContextMember(), ancestor); + return CreateContext(comparisonSettings, new DifferenceTreeNodeMember(), ancestor); } - public static IComparisonContext CreateContext(ComparisonSettings comparisonSettings, IComparisonContext ancestor, MemberInfo memberInfo) + public static IDifferenceTreeNode CreateContext(ComparisonSettings comparisonSettings, IDifferenceTreeNode ancestor, MemberInfo memberInfo) { - return CreateContext(comparisonSettings, new ComparisonContextMember(memberInfo, memberInfo?.Name), ancestor); + return CreateContext(comparisonSettings, new DifferenceTreeNodeMember(memberInfo, memberInfo?.Name), ancestor); } - public static IComparisonContext CreateContext(ComparisonSettings comparisonSettings, IComparisonContext ancestor, string memberName) + public static IDifferenceTreeNode CreateContext(ComparisonSettings comparisonSettings, IDifferenceTreeNode ancestor, string memberName) { - return CreateContext(comparisonSettings, new ComparisonContextMember(name: memberName), ancestor); + return CreateContext(comparisonSettings, new DifferenceTreeNodeMember(name: memberName), ancestor); } - public static IComparisonContext CreateContext(ComparisonSettings comparisonSettings, IComparisonContext ancestor, MemberInfo memberInfo, string memberName) + public static IDifferenceTreeNode CreateContext(ComparisonSettings comparisonSettings, IDifferenceTreeNode ancestor, MemberInfo memberInfo, string memberName) { - return CreateContext(comparisonSettings, new ComparisonContextMember(memberInfo, memberName), ancestor); + return CreateContext(comparisonSettings, new DifferenceTreeNodeMember(memberInfo, memberName), ancestor); } - public static IComparisonContext CreateContext(ComparisonSettings comparisonSettings, IComparisonContextMember comparisonContextMember, IComparisonContext ancestor) + public static IDifferenceTreeNode CreateContext(ComparisonSettings comparisonSettings, IDifferenceTreeNodeMember comparisonContextMember, IDifferenceTreeNode ancestor) { _ = comparisonSettings ?? throw new ArgumentNullException(nameof(comparisonSettings)); _ = comparisonContextMember ?? throw new ArgumentNullException(nameof(comparisonContextMember)); @@ -73,7 +73,7 @@ public static IComparisonContext CreateContext(ComparisonSettings comparisonSett } } - return new ComparisonContext(comparisonContextMember, ancestor); + return new DifferenceTreeNode(comparisonContextMember, ancestor); } } } diff --git a/ObjectsComparer/ObjectsComparer/Context/ContextableExtensions.cs b/ObjectsComparer/ObjectsComparer/Context/ContextableExtensions.cs index 93741ca..9332166 100644 --- a/ObjectsComparer/ObjectsComparer/Context/ContextableExtensions.cs +++ b/ObjectsComparer/ObjectsComparer/Context/ContextableExtensions.cs @@ -12,7 +12,7 @@ public static class ContextableExtensions /// /// The method is intended for IContextableComparer implementers. /// Current difference and its location in the difference tree. - public static IEnumerable CalculateDifferences(this IComparer comparer, Type type, object obj1, object obj2, IComparisonContext comparisonContext) + public static IEnumerable CalculateDifferences(this IComparer comparer, Type type, object obj1, object obj2, IDifferenceTreeNode comparisonContext) { if (comparer is null) { @@ -29,7 +29,7 @@ public static IEnumerable CalculateDifferences(this ICompare throw new ArgumentNullException(nameof(comparisonContext)); } - if (comparer is IContextableComparer contextableComparer) + if (comparer is IDifferenceTreeBuilder contextableComparer) { var differenceTreeNodeInfoList = contextableComparer.CalculateDifferences(type, obj1, obj2, comparisonContext); @@ -41,7 +41,7 @@ public static IEnumerable CalculateDifferences(this ICompare yield break; } - ThrowContextableComparerNotImplemented(comparisonContext, comparer.Settings, comparer, nameof(IContextableComparer)); + ThrowContextableComparerNotImplemented(comparisonContext, comparer.Settings, comparer, nameof(IDifferenceTreeBuilder)); var differences = comparer.CalculateDifferences(type, obj1, obj2); @@ -55,7 +55,7 @@ public static IEnumerable CalculateDifferences(this ICompare /// Calculates list of differences between objects. Accepts comparison context. /// /// The method is intended for IContextableComparer implementers. - public static IEnumerable CalculateDifferences(this IComparer comparer, T obj1, T obj2, IComparisonContext comparisonContext) + public static IEnumerable CalculateDifferences(this IComparer comparer, T obj1, T obj2, IDifferenceTreeNode comparisonContext) { if (comparer is null) { @@ -67,9 +67,9 @@ public static IEnumerable CalculateDifferences(this IComp throw new ArgumentNullException(nameof(comparisonContext)); } - if (comparer is IContextableComparer contextableComparer) + if (comparer is IDifferenceTreeBuilder contextableComparer) { - var differenceTreeNodeInfoList = contextableComparer.CalculateDifferences(obj1, obj2, comparisonContext); + var differenceTreeNodeInfoList = contextableComparer.BuildDifferencesTree(obj1, obj2, comparisonContext); foreach (var differenceTreeNodeInfo in differenceTreeNodeInfoList) { @@ -79,7 +79,7 @@ public static IEnumerable CalculateDifferences(this IComp yield break; } - ThrowContextableComparerNotImplemented(comparisonContext, comparer.Settings, comparer, $"{nameof(IContextableComparer)}<{typeof(T).FullName}>"); + ThrowContextableComparerNotImplemented(comparisonContext, comparer.Settings, comparer, $"{nameof(IDifferenceTreeBuilder)}<{typeof(T).FullName}>"); var differences = comparer.CalculateDifferences(obj1, obj2); @@ -89,7 +89,7 @@ public static IEnumerable CalculateDifferences(this IComp } } - static bool HasComparisonContextImplicitRoot(IComparisonContext comparisonContext) + static bool HasComparisonContextImplicitRoot(IDifferenceTreeNode comparisonContext) { if (comparisonContext is null) { @@ -98,7 +98,7 @@ static bool HasComparisonContextImplicitRoot(IComparisonContext comparisonContex do { - if (comparisonContext.Ancestor == null && comparisonContext is ImplicitComparisonContext) + if (comparisonContext.Ancestor == null && comparisonContext is ImplicitDifferenceTreeNode) { return true; } @@ -110,7 +110,7 @@ static bool HasComparisonContextImplicitRoot(IComparisonContext comparisonContex return false; } - internal static void ThrowContextableComparerNotImplemented(IComparisonContext comparisonContext, ComparisonSettings comparisonSettings, object comparer, string unImplementedInterface) + internal static void ThrowContextableComparerNotImplemented(IDifferenceTreeNode comparisonContext, ComparisonSettings comparisonSettings, object comparer, string unImplementedInterface) { if (comparisonContext is null) { diff --git a/ObjectsComparer/ObjectsComparer/Context/DifferenceLocation.cs b/ObjectsComparer/ObjectsComparer/Context/DifferenceLocation.cs index 094e690..c43260d 100644 --- a/ObjectsComparer/ObjectsComparer/Context/DifferenceLocation.cs +++ b/ObjectsComparer/ObjectsComparer/Context/DifferenceLocation.cs @@ -7,7 +7,7 @@ namespace ObjectsComparer.ContextExtensions /// public class DifferenceLocation { - public DifferenceLocation(Difference difference, IComparisonContext treeNode = null) + public DifferenceLocation(Difference difference, IDifferenceTreeNode treeNode = null) { Difference = difference ?? throw new ArgumentNullException(nameof(difference)); TreeNode = treeNode; @@ -15,6 +15,6 @@ public DifferenceLocation(Difference difference, IComparisonContext treeNode = n public Difference Difference { get; } - public IComparisonContext TreeNode { get; } + public IDifferenceTreeNode TreeNode { get; } } } \ No newline at end of file diff --git a/ObjectsComparer/ObjectsComparer/Context/DifferenceTreeNode.cs b/ObjectsComparer/ObjectsComparer/Context/DifferenceTreeNode.cs new file mode 100644 index 0000000..fd7bfb3 --- /dev/null +++ b/ObjectsComparer/ObjectsComparer/Context/DifferenceTreeNode.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using System.Reflection; + +namespace ObjectsComparer +{ + /// + /// Default implementation of . + /// + public sealed class DifferenceTreeNode : DifferenceTreeNodeBase + { + public DifferenceTreeNode(IDifferenceTreeNodeMember member = null, IDifferenceTreeNode ancestor = null) : base(member, ancestor) + { + + } + } +} \ No newline at end of file diff --git a/ObjectsComparer/ObjectsComparer/Context/ComparisonContextBase.cs b/ObjectsComparer/ObjectsComparer/Context/DifferenceTreeNodeBase.cs similarity index 75% rename from ObjectsComparer/ObjectsComparer/Context/ComparisonContextBase.cs rename to ObjectsComparer/ObjectsComparer/Context/DifferenceTreeNodeBase.cs index fdcd75c..e003a61 100644 --- a/ObjectsComparer/ObjectsComparer/Context/ComparisonContextBase.cs +++ b/ObjectsComparer/ObjectsComparer/Context/DifferenceTreeNodeBase.cs @@ -5,23 +5,23 @@ namespace ObjectsComparer { /// - /// Base class for implementors. + /// Base class for implementors. /// - public abstract class ComparisonContextBase : IComparisonContext + public abstract class DifferenceTreeNodeBase : IDifferenceTreeNode { - readonly List _descendants = new List(); + readonly List _descendants = new List(); readonly List _differences = new List(); - public ComparisonContextBase(IComparisonContextMember member = null, IComparisonContext ancestor = null) + public DifferenceTreeNodeBase(IDifferenceTreeNodeMember member = null, IDifferenceTreeNode ancestor = null) { ancestor?.AddDescendant(this); Member = member; } - IComparisonContext _ancestor; + IDifferenceTreeNode _ancestor; - public virtual IComparisonContext Ancestor + public virtual IDifferenceTreeNode Ancestor { get { @@ -38,13 +38,13 @@ public virtual IComparisonContext Ancestor } } - public IEnumerable Descendants => _descendants.AsReadOnly(); + public IEnumerable Descendants => _descendants.AsReadOnly(); public IEnumerable Differences => _differences.AsReadOnly(); - public IComparisonContextMember Member { get; } + public IDifferenceTreeNodeMember Member { get; } - public void AddDescendant(IComparisonContext descendant) + public void AddDescendant(IDifferenceTreeNode descendant) { if (descendant is null) { @@ -90,9 +90,9 @@ public bool HasDifferences(bool recursive) return GetDifferences(recursive).Any(); } - public IComparisonContext Shrink() + public IDifferenceTreeNode Shrink() { - List removeDescendants = new List(); + List removeDescendants = new List(); _descendants.ForEach(descendantContext => { diff --git a/ObjectsComparer/ObjectsComparer/Context/ComparisonContextMember.cs b/ObjectsComparer/ObjectsComparer/Context/DifferenceTreeNodeMember.cs similarity index 59% rename from ObjectsComparer/ObjectsComparer/Context/ComparisonContextMember.cs rename to ObjectsComparer/ObjectsComparer/Context/DifferenceTreeNodeMember.cs index d2f5aa2..aec9bff 100644 --- a/ObjectsComparer/ObjectsComparer/Context/ComparisonContextMember.cs +++ b/ObjectsComparer/ObjectsComparer/Context/DifferenceTreeNodeMember.cs @@ -3,9 +3,9 @@ namespace ObjectsComparer { - public class ComparisonContextMember : IComparisonContextMember + public class DifferenceTreeNodeMember : IDifferenceTreeNodeMember { - public ComparisonContextMember(MemberInfo info = null, string name = null) + public DifferenceTreeNodeMember(MemberInfo info = null, string name = null) { Info = info; Name = name; diff --git a/ObjectsComparer/ObjectsComparer/Context/IContextableComparer.cs b/ObjectsComparer/ObjectsComparer/Context/IContextableComparer.cs deleted file mode 100644 index d01874d..0000000 --- a/ObjectsComparer/ObjectsComparer/Context/IContextableComparer.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System; -using System.Collections.Generic; - -namespace ObjectsComparer.ContextExtensions -{ - /// - /// Comparer accepting . - /// - public interface IContextableComparer - { - IEnumerable CalculateDifferences(Type type, object obj1, object obj2, IComparisonContext comparisonContext); - } -} \ No newline at end of file diff --git a/ObjectsComparer/ObjectsComparer/Context/IContextableComparer~1.cs b/ObjectsComparer/ObjectsComparer/Context/IContextableComparer~1.cs deleted file mode 100644 index f5ee63e..0000000 --- a/ObjectsComparer/ObjectsComparer/Context/IContextableComparer~1.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System; -using System.Collections.Generic; - -namespace ObjectsComparer.ContextExtensions -{ - /// - /// Comparer accepting . - /// - public interface IContextableComparer - { - IEnumerable CalculateDifferences(T obj1, T obj2, IComparisonContext comparisonContext); - } -} diff --git a/ObjectsComparer/ObjectsComparer/Context/IDifferenceTreeBuilder.cs b/ObjectsComparer/ObjectsComparer/Context/IDifferenceTreeBuilder.cs new file mode 100644 index 0000000..89d8d2b --- /dev/null +++ b/ObjectsComparer/ObjectsComparer/Context/IDifferenceTreeBuilder.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; + +namespace ObjectsComparer.ContextExtensions +{ + /// + /// Builds the difference tree. + /// + public interface IDifferenceTreeBuilder + { + /// + /// Finds the difference, adds it to the difference tree and returns it, including its location. + /// + /// Intended for implementers. To avoid side effects, consumers should call extension method instead. + /// The location of the difference in the difference tree. + IEnumerable CalculateDifferences(Type type, object obj1, object obj2, IDifferenceTreeNode comparisonContext); + } +} \ No newline at end of file diff --git a/ObjectsComparer/ObjectsComparer/Context/IComparisonContext.cs b/ObjectsComparer/ObjectsComparer/Context/IDifferenceTreeNode.cs similarity index 76% rename from ObjectsComparer/ObjectsComparer/Context/IComparisonContext.cs rename to ObjectsComparer/ObjectsComparer/Context/IDifferenceTreeNode.cs index 61d4a16..d7bd0f3 100644 --- a/ObjectsComparer/ObjectsComparer/Context/IComparisonContext.cs +++ b/ObjectsComparer/ObjectsComparer/Context/IDifferenceTreeNode.cs @@ -9,20 +9,20 @@ namespace ObjectsComparer //TODO: Edit "Once the comparison process is completed, it is possible to traverse " /// - /// Context of comparison process. Each instance wraps compared , which is typically property. Each context has its ancestor and descendants the same way as its compared has its ancestor and descendant members. + /// Context of comparison process. Each instance wraps compared , which is typically property. Each context has its ancestor and descendants the same way as its compared has its ancestor and descendant members. /// Once the comparison process is completed, it is possible to traverse the comparison context graph and see differences at particular members. /// - public interface IComparisonContext + public interface IDifferenceTreeNode { /// /// Ancestor context. /// - IComparisonContext Ancestor { get; set; } + IDifferenceTreeNode Ancestor { get; set; } /// /// Children contexts. /// - IEnumerable Descendants { get; } + IEnumerable Descendants { get; } /// /// A list of differences directly related to the context. @@ -30,16 +30,16 @@ public interface IComparisonContext IEnumerable Differences { get; } /// - /// Compared member, for more info see . + /// Compared member, for more info see . /// It should be null for the root context (the starting point of the comparison) and for the list element context. A list element context never has a member, but it has an ancestor context which is the list and that list has its member. /// - IComparisonContextMember Member { get; } + IDifferenceTreeNodeMember Member { get; } /// /// Adds descendant to the context. /// /// - void AddDescendant(IComparisonContext descendant); + void AddDescendant(IDifferenceTreeNode descendant); /// /// Adds the difference to the context. @@ -62,6 +62,6 @@ public interface IComparisonContext /// /// Removes all which have no directly or indirectly in their . /// - IComparisonContext Shrink(); + IDifferenceTreeNode Shrink(); } } diff --git a/ObjectsComparer/ObjectsComparer/Context/IComparisonContextMember.cs b/ObjectsComparer/ObjectsComparer/Context/IDifferenceTreeNodeMember.cs similarity index 90% rename from ObjectsComparer/ObjectsComparer/Context/IComparisonContextMember.cs rename to ObjectsComparer/ObjectsComparer/Context/IDifferenceTreeNodeMember.cs index 376f3ed..22d4609 100644 --- a/ObjectsComparer/ObjectsComparer/Context/IComparisonContextMember.cs +++ b/ObjectsComparer/ObjectsComparer/Context/IDifferenceTreeNodeMember.cs @@ -5,7 +5,7 @@ namespace ObjectsComparer /// /// The member in the comparison process, usually a property. /// - public interface IComparisonContextMember + public interface IDifferenceTreeNodeMember { /// /// Member. It should never be empty. diff --git a/ObjectsComparer/ObjectsComparer/Context/IDifferencesTreeBuilder~1.cs b/ObjectsComparer/ObjectsComparer/Context/IDifferencesTreeBuilder~1.cs new file mode 100644 index 0000000..22694ae --- /dev/null +++ b/ObjectsComparer/ObjectsComparer/Context/IDifferencesTreeBuilder~1.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; + +namespace ObjectsComparer.ContextExtensions +{ + /// + /// Builds the difference tree. + /// + public interface IDifferenceTreeBuilder + { + /// + /// Finds the difference, adds it to the difference tree and returns it, including its location. + /// + /// Intended for implementers. To avoid side effects, consumers should call extension method instead. + /// The location of the difference in the difference tree. + IEnumerable BuildDifferencesTree(T obj1, T obj2, IDifferenceTreeNode comparisonContext); + } +} diff --git a/ObjectsComparer/ObjectsComparer/Context/ImplicitComparisonContext.cs b/ObjectsComparer/ObjectsComparer/Context/ImplicitComparisonContext.cs deleted file mode 100644 index 4271038..0000000 --- a/ObjectsComparer/ObjectsComparer/Context/ImplicitComparisonContext.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System.Collections.Generic; -using System.Linq; - -namespace ObjectsComparer -{ - /// - /// Root compariosin context for cases where the consumer does not create and pass his own root context at the beginning of the comparison. - /// - internal class ImplicitComparisonContext : ComparisonContextBase - { - public ImplicitComparisonContext(IComparisonContextMember member = null, IComparisonContext ancestor = null) : base(member, ancestor) - { - } - - public override void AddDifference(Difference difference) - { - } - } -} diff --git a/ObjectsComparer/ObjectsComparer/Context/ImplicitDifferenceTreeNode.cs b/ObjectsComparer/ObjectsComparer/Context/ImplicitDifferenceTreeNode.cs new file mode 100644 index 0000000..6d384dc --- /dev/null +++ b/ObjectsComparer/ObjectsComparer/Context/ImplicitDifferenceTreeNode.cs @@ -0,0 +1,19 @@ +using System.Collections.Generic; +using System.Linq; + +namespace ObjectsComparer +{ + /// + /// Root comparison context for cases where the consumer does not create and pass his own root context at the beginning of the comparison. + /// + internal class ImplicitDifferenceTreeNode : DifferenceTreeNodeBase + { + public ImplicitDifferenceTreeNode(IDifferenceTreeNodeMember member = null, IDifferenceTreeNode ancestor = null) : base(member, ancestor) + { + } + + public override void AddDifference(Difference difference) + { + } + } +} diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractDynamicObjectsComprer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractDynamicObjectsComprer.cs index e19bf02..68ec3ef 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractDynamicObjectsComprer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractDynamicObjectsComprer.cs @@ -7,7 +7,7 @@ namespace ObjectsComparer { - internal abstract class AbstractDynamicObjectsComprer: AbstractComparer, IComparerWithCondition, IContextableComparer, IContextableComparer + internal abstract class AbstractDynamicObjectsComprer: AbstractComparer, IComparerWithCondition, IDifferenceTreeBuilder, IDifferenceTreeBuilder { protected AbstractDynamicObjectsComprer(ComparisonSettings settings, BaseComparer parentComparer, IComparersFactory factory) : base(settings, parentComparer, factory) { @@ -19,17 +19,17 @@ public override IEnumerable CalculateDifferences(Type type, object o .Select(differenceLocation => differenceLocation.Difference); } - IEnumerable IContextableComparer.CalculateDifferences(T obj1, T obj2, IComparisonContext comparisonContext) + IEnumerable IDifferenceTreeBuilder.BuildDifferencesTree(T obj1, T obj2, IDifferenceTreeNode comparisonContext) { return AsContextableComparer().CalculateDifferences(typeof(T), obj1, obj2, ComparisonContextProvider.CreateImplicitRootContext(Settings)); } - IContextableComparer AsContextableComparer() + IDifferenceTreeBuilder AsContextableComparer() { return this; } - IEnumerable IContextableComparer.CalculateDifferences(Type type, object obj1, object obj2, IComparisonContext comparisonContext) + IEnumerable IDifferenceTreeBuilder.CalculateDifferences(Type type, object obj1, object obj2, IDifferenceTreeNode comparisonContext) { var castedObject1 = (T)obj1; var castedObject2 = (T)obj2; diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractEnumerablesComparer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractEnumerablesComparer.cs index 6a5a431..a11d227 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractEnumerablesComparer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractEnumerablesComparer.cs @@ -8,7 +8,7 @@ namespace ObjectsComparer { - internal abstract class AbstractEnumerablesComparer: AbstractComparer, IComparerWithCondition, IContextableComparer + internal abstract class AbstractEnumerablesComparer: AbstractComparer, IComparerWithCondition, IDifferenceTreeBuilder { ///// ///// member names that will be skipped from comaprison. @@ -60,6 +60,6 @@ public virtual bool SkipMember(Type type, MemberInfo member) public abstract bool IsMatch(Type type, object obj1, object obj2); - public abstract IEnumerable CalculateDifferences(Type type, object obj1, object obj2, IComparisonContext comparisonContext); + public abstract IEnumerable CalculateDifferences(Type type, object obj1, object obj2, IDifferenceTreeNode comparisonContext); } } \ No newline at end of file diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs index 76ad055..4ae44fa 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs @@ -10,7 +10,7 @@ namespace ObjectsComparer { - internal class EnumerablesComparer : EnumerablesComparerBase, IComparerWithCondition, IContextableComparer + internal class EnumerablesComparer : EnumerablesComparerBase, IComparerWithCondition, IDifferenceTreeBuilder { public EnumerablesComparer(ComparisonSettings settings, BaseComparer parentComparer, IComparersFactory factory) : base(settings, parentComparer, factory) { @@ -22,9 +22,9 @@ public override IEnumerable CalculateDifferences(Type type, object o .Select(differenceLocation => differenceLocation.Difference); } - IContextableComparer AsContextable() => this; + IDifferenceTreeBuilder AsContextable() => this; - IEnumerable IContextableComparer.CalculateDifferences(Type type, object obj1, object obj2, IComparisonContext listComparisonContext) + IEnumerable IDifferenceTreeBuilder.CalculateDifferences(Type type, object obj1, object obj2, IDifferenceTreeNode listComparisonContext) { Debug.WriteLine($"{GetType().Name}.{nameof(CalculateDifferences)}: {type.Name}"); diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparerBase.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparerBase.cs index 02ac55a..d3d90c0 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparerBase.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparerBase.cs @@ -16,7 +16,7 @@ public EnumerablesComparerBase(ComparisonSettings settings, BaseComparer parentC /// /// Selects calculation operation based on the current value of the property. /// - protected virtual IEnumerable CalculateDifferences(IList list1, IList list2, IComparisonContext listComparisonContext, ListComparisonOptions listComparisonOptions) + protected virtual IEnumerable CalculateDifferences(IList list1, IList list2, IDifferenceTreeNode listComparisonContext, ListComparisonOptions listComparisonOptions) { if (listComparisonOptions.ElementSearchMode == ListElementSearchMode.Key) { @@ -35,7 +35,7 @@ protected virtual IEnumerable CalculateDifferences(IList< /// /// Calculates differences using comparison mode. /// - protected virtual IEnumerable CalculateDifferencesByKey(IList array1, IList array2, IComparisonContext listComparisonContext, ListComparisonOptions listComparisonOptions) + protected virtual IEnumerable CalculateDifferencesByKey(IList array1, IList array2, IDifferenceTreeNode listComparisonContext, ListComparisonOptions listComparisonOptions) { Debug.WriteLine($"{GetType().Name}.{nameof(CalculateDifferencesByKey)}: {array1?.GetType().Name}"); @@ -136,7 +136,7 @@ protected virtual IEnumerable CalculateDifferencesByKey(I /// /// Calculates differences using comparison mode. /// - protected virtual IEnumerable CalculateDifferencesByIndex(IList array1, IList array2, IComparisonContext listComparisonContext, ListComparisonOptions listComparisonOptions) + protected virtual IEnumerable CalculateDifferencesByIndex(IList array1, IList array2, IDifferenceTreeNode listComparisonContext, ListComparisonOptions listComparisonOptions) { Debug.WriteLine($"{GetType().Name}.{nameof(CalculateDifferencesByIndex)}: {array1?.GetType().Name}"); diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer~1.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer~1.cs index d23f409..73b586e 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer~1.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer~1.cs @@ -8,7 +8,7 @@ namespace ObjectsComparer { - internal class EnumerablesComparer : EnumerablesComparerBase, IContextableComparer, IContextableComparer + internal class EnumerablesComparer : EnumerablesComparerBase, IDifferenceTreeBuilder, IDifferenceTreeBuilder { private readonly IComparer _comparer; @@ -23,9 +23,9 @@ public override IEnumerable CalculateDifferences(Type type, object o .Select(differeneLocation => differeneLocation.Difference); } - public IEnumerable CalculateDifferences(Type type, object obj1, object obj2, IComparisonContext listComparisonContext) + public IEnumerable CalculateDifferences(Type type, object obj1, object obj2, IDifferenceTreeNode listComparisonContext) { - Debug.WriteLine($"{GetType().Name}.{nameof(CalculateDifferences)}: {type.Name}"); + Debug.WriteLine($"{GetType().Name}.{nameof(BuildDifferencesTree)}: {type.Name}"); if (listComparisonContext is null) { @@ -83,7 +83,7 @@ public IEnumerable CalculateDifferences(Type type, object ob } } - public IEnumerable CalculateDifferences(T obj1, T obj2, IComparisonContext listComparisonContext) + public IEnumerable BuildDifferencesTree(T obj1, T obj2, IDifferenceTreeNode listComparisonContext) { return CalculateDifferences(((object)obj1 ?? obj2).GetType(), obj1, obj2, listComparisonContext); } diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/GenericEnumerablesComparer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/GenericEnumerablesComparer.cs index 5d4b9c3..287e4d1 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/GenericEnumerablesComparer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/GenericEnumerablesComparer.cs @@ -22,7 +22,7 @@ public override IEnumerable CalculateDifferences(Type type, object o .Select(differenceLocation => differenceLocation.Difference); } - public override IEnumerable CalculateDifferences(Type type, object obj1, object obj2, IComparisonContext comparisonContext) + public override IEnumerable CalculateDifferences(Type type, object obj1, object obj2, IDifferenceTreeNode comparisonContext) { if (obj1 == null && obj2 == null) { diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/HashSetsComparer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/HashSetsComparer.cs index d8ddfd1..e6e9936 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/HashSetsComparer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/HashSetsComparer.cs @@ -20,7 +20,7 @@ public override IEnumerable CalculateDifferences(Type type, object o .Select(differenceLocation => differenceLocation.Difference); } - public override IEnumerable CalculateDifferences(Type type, object obj1, object obj2, IComparisonContext comparisonContext) + public override IEnumerable CalculateDifferences(Type type, object obj1, object obj2, IDifferenceTreeNode comparisonContext) { if (obj1 == null && obj2 == null) { diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/HashSetsComparer~1.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/HashSetsComparer~1.cs index 2ddb280..7263c9f 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/HashSetsComparer~1.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/HashSetsComparer~1.cs @@ -6,14 +6,14 @@ namespace ObjectsComparer { - internal class HashSetsComparer : AbstractComparer, IContextableComparer, IContextableComparer + internal class HashSetsComparer : AbstractComparer, IDifferenceTreeBuilder, IDifferenceTreeBuilder { public HashSetsComparer(ComparisonSettings settings, BaseComparer parentComparer, IComparersFactory factory) :base(settings, parentComparer, factory) { } - public IEnumerable CalculateDifferences(T obj1, T obj2, IComparisonContext comparisonContext) + public IEnumerable BuildDifferencesTree(T obj1, T obj2, IDifferenceTreeNode comparisonContext) { return CalculateDifferences(typeof(T), obj1, obj2, comparisonContext); } @@ -24,7 +24,7 @@ public override IEnumerable CalculateDifferences(Type type, object o .Select(differenceLocation => differenceLocation.Difference); } - public IEnumerable CalculateDifferences(Type type, object obj1, object obj2, IComparisonContext comparisonContext) + public IEnumerable CalculateDifferences(Type type, object obj1, object obj2, IDifferenceTreeNode comparisonContext) { if (comparisonContext is null) { diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/MultidimensionalArrayComparer~1.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/MultidimensionalArrayComparer~1.cs index 4a05031..9e204a7 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/MultidimensionalArrayComparer~1.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/MultidimensionalArrayComparer~1.cs @@ -6,7 +6,7 @@ namespace ObjectsComparer { - internal class MultidimensionalArrayComparer : AbstractComparer, IContextableComparer, IContextableComparer + internal class MultidimensionalArrayComparer : AbstractComparer, IDifferenceTreeBuilder, IDifferenceTreeBuilder { private readonly IComparer _comparer; @@ -22,12 +22,12 @@ public override IEnumerable CalculateDifferences(Type type, object o .Select(differenceLocation => differenceLocation.Difference); } - public IEnumerable CalculateDifferences(T obj1, T obj2, IComparisonContext comparisonContext) + public IEnumerable BuildDifferencesTree(T obj1, T obj2, IDifferenceTreeNode comparisonContext) { return CalculateDifferences(typeof(T), obj1, obj2, comparisonContext); } - public IEnumerable CalculateDifferences(Type type, object obj1, object obj2, IComparisonContext comparisonContext) + public IEnumerable CalculateDifferences(Type type, object obj1, object obj2, IDifferenceTreeNode comparisonContext) { if (comparisonContext is null) { diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/MultidimensionalArraysComparer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/MultidimensionalArraysComparer.cs index 773cba0..d178d11 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/MultidimensionalArraysComparer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/MultidimensionalArraysComparer.cs @@ -21,7 +21,7 @@ public override IEnumerable CalculateDifferences(Type type, object o .Select(differenceLocation => differenceLocation.Difference); } - public override IEnumerable CalculateDifferences(Type type, object obj1, object obj2, IComparisonContext comparisonContext) + public override IEnumerable CalculateDifferences(Type type, object obj1, object obj2, IDifferenceTreeNode comparisonContext) { if (obj1 == null && obj2 == null) { diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/TypesComparer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/TypesComparer.cs index 1797e81..23b5022 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/TypesComparer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/TypesComparer.cs @@ -7,7 +7,7 @@ namespace ObjectsComparer { - internal class TypesComparer : AbstractComparer, IComparerWithCondition, IContextableComparer + internal class TypesComparer : AbstractComparer, IComparerWithCondition, IDifferenceTreeBuilder { public TypesComparer(ComparisonSettings settings, BaseComparer parentComparer, IComparersFactory factory) @@ -21,7 +21,7 @@ public override IEnumerable CalculateDifferences(Type type, object o .Select(differenceLocation => differenceLocation.Difference); } - public IEnumerable CalculateDifferences(Type type, object obj1, object obj2, IComparisonContext comparisonContext) + public IEnumerable CalculateDifferences(Type type, object obj1, object obj2, IDifferenceTreeNode comparisonContext) { if (comparisonContext is null) { diff --git a/ObjectsComparer/ObjectsComparer/Exceptions/ElementKeyNotFoundException.cs b/ObjectsComparer/ObjectsComparer/Exceptions/ElementKeyNotFoundException.cs index a9b8f34..a99ca63 100644 --- a/ObjectsComparer/ObjectsComparer/Exceptions/ElementKeyNotFoundException.cs +++ b/ObjectsComparer/ObjectsComparer/Exceptions/ElementKeyNotFoundException.cs @@ -16,7 +16,7 @@ public class ElementKeyNotFoundException : Exception /// /// An element that is missing a key. /// - internal ElementKeyNotFoundException(object keylessElement, IComparisonContext keylessElementComparisonContext, string message = ElementKeyNotFoundExceptionMsg) : base(message) + internal ElementKeyNotFoundException(object keylessElement, IDifferenceTreeNode keylessElementComparisonContext, string message = ElementKeyNotFoundExceptionMsg) : base(message) { KeylessElement = keylessElement ?? throw new ArgumentNullException(nameof(keylessElement)); KeylessElementComparisonContext = keylessElementComparisonContext ?? throw new ArgumentNullException(nameof(keylessElementComparisonContext)); @@ -28,8 +28,8 @@ internal ElementKeyNotFoundException(object keylessElement, IComparisonContext k public object KeylessElement { get; } /// - /// The current in which the exception occurred. + /// The current in which the exception occurred. /// - public IComparisonContext KeylessElementComparisonContext { get; } + public IDifferenceTreeNode KeylessElementComparisonContext { get; } } } From fe639028c65896ee73e6e2ee0f379c64975b2858 Mon Sep 17 00:00:00 2001 From: Daniel Nemec Date: Tue, 12 Apr 2022 06:22:46 +0200 Subject: [PATCH 125/181] Rename IDifferencesTreeBuilder~1.cs with IDifferenceTreeBuilder~1.cs. --- .../{IDifferencesTreeBuilder~1.cs => IDifferenceTreeBuilder~1.cs} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename ObjectsComparer/ObjectsComparer/Context/{IDifferencesTreeBuilder~1.cs => IDifferenceTreeBuilder~1.cs} (100%) diff --git a/ObjectsComparer/ObjectsComparer/Context/IDifferencesTreeBuilder~1.cs b/ObjectsComparer/ObjectsComparer/Context/IDifferenceTreeBuilder~1.cs similarity index 100% rename from ObjectsComparer/ObjectsComparer/Context/IDifferencesTreeBuilder~1.cs rename to ObjectsComparer/ObjectsComparer/Context/IDifferenceTreeBuilder~1.cs From 9b4cfb45b74b2228c65012a0c415b2bd36279b7b Mon Sep 17 00:00:00 2001 From: Daniel Nemec Date: Tue, 12 Apr 2022 06:45:27 +0200 Subject: [PATCH 126/181] Rename CalculateDifferences with BuildDifferenceTree. --- .../Example4/Example4Tests.cs | 4 ++-- .../Example4/Example4Tests_BuiltInKeyComparison.cs | 2 +- .../Comparer_CompilerGeneratedObjectsTests.cs | 4 ++-- .../Comparer_ExpandoObjectsTests.cs | 6 +++--- .../Comparer_GenericEnumerableTests.cs | 2 +- .../Comparer_MultidimensionalArraysTests.cs | 2 +- .../Comparer_NonGenericEnumerableTests.cs | 2 +- .../ObjectsComparer.Tests/ComparisonSettingsTests.cs | 4 ++-- ObjectsComparer/ObjectsComparer/Comparer.cs | 12 ++++++------ ObjectsComparer/ObjectsComparer/Comparer~1.cs | 2 +- .../ObjectsComparer/Context/ComparerExtensions.cs | 4 ++-- .../ObjectsComparer/Context/ContextableExtensions.cs | 4 ++-- .../Context/IDifferenceTreeBuilder.cs | 4 ++-- .../Context/IDifferenceTreeBuilder~1.cs | 4 ++-- .../CustomComparers/AbstractDynamicObjectsComprer.cs | 8 ++++---- .../CustomComparers/AbstractEnumerablesComparer.cs | 2 +- .../CustomComparers/EnumerablesComparer.cs | 4 ++-- .../CustomComparers/EnumerablesComparer~1.cs | 10 +++++----- .../CustomComparers/GenericEnumerablesComparer.cs | 4 ++-- .../CustomComparers/HashSetsComparer.cs | 4 ++-- .../CustomComparers/HashSetsComparer~1.cs | 8 ++++---- .../MultidimensionalArrayComparer~1.cs | 8 ++++---- .../MultidimensionalArraysComparer.cs | 4 ++-- .../ObjectsComparer/CustomComparers/TypesComparer.cs | 4 ++-- 24 files changed, 56 insertions(+), 56 deletions(-) diff --git a/ObjectsComparer/ObjectsComparer.Examples/Example4/Example4Tests.cs b/ObjectsComparer/ObjectsComparer.Examples/Example4/Example4Tests.cs index d689d41..a1a2fb6 100644 --- a/ObjectsComparer/ObjectsComparer.Examples/Example4/Example4Tests.cs +++ b/ObjectsComparer/ObjectsComparer.Examples/Example4/Example4Tests.cs @@ -67,7 +67,7 @@ public void List_Of_Equal_Sizes_But_Is_Inequality() } [Test] - public void CalculateDifferencesTree_Throw_ContextableComparerNotImplemented() + public void CalculateDifferenceTree_Throw_ContextableComparerNotImplemented() { var formula1 = new Formula { @@ -103,7 +103,7 @@ public void CalculateDifferencesTree_Throw_ContextableComparerNotImplemented() Assert.Throws(() => { - var rootNode = _comparer.CalculateDifferencesTree(formula1, formula2); + var rootNode = _comparer.CalculateDifferenceTree(formula1, formula2); var differences = rootNode.GetDifferences(true).ToArray(); }); } diff --git a/ObjectsComparer/ObjectsComparer.Examples/Example4/Example4Tests_BuiltInKeyComparison.cs b/ObjectsComparer/ObjectsComparer.Examples/Example4/Example4Tests_BuiltInKeyComparison.cs index 7f7d12a..0e418e5 100644 --- a/ObjectsComparer/ObjectsComparer.Examples/Example4/Example4Tests_BuiltInKeyComparison.cs +++ b/ObjectsComparer/ObjectsComparer.Examples/Example4/Example4Tests_BuiltInKeyComparison.cs @@ -289,7 +289,7 @@ public void List_Of_Different_Sizes_But_Is_Inequality_FormatKey_CheckComparisonC .FormatElementKey(formatKeyArgs => $"Id={formatKeyArgs.ElementKey}"))); var comparer = new Comparer(settings); - var rootDifferenceNode = comparer.CalculateDifferencesTree(formula1, formula2); + var rootDifferenceNode = comparer.CalculateDifferenceTree(formula1, formula2); var differences = rootDifferenceNode.GetDifferences(recursive: true).ToArray(); bool isEqual = differences.Any() == false; ResultToOutput(isEqual, differences); diff --git a/ObjectsComparer/ObjectsComparer.Tests/Comparer_CompilerGeneratedObjectsTests.cs b/ObjectsComparer/ObjectsComparer.Tests/Comparer_CompilerGeneratedObjectsTests.cs index 11f3fa6..3c4b8ad 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/Comparer_CompilerGeneratedObjectsTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/Comparer_CompilerGeneratedObjectsTests.cs @@ -79,7 +79,7 @@ public void MissedFields_CheckComparisonContext() var comparer = new Comparer(); - var rootDiffenenceNode = comparer.CalculateDifferencesTree(typeof(object), (object)a1, (object)a2); + var rootDiffenenceNode = comparer.CalculateDifferenceTree(typeof(object), (object)a1, (object)a2); var calculateDifferences = rootDiffenenceNode.GetDifferences(true).ToArray(); Assert.AreEqual(3, calculateDifferences.Count()); @@ -217,7 +217,7 @@ public void NullAndMissedMemberAreNotEqual_CheckComparisonContext() var comparer = new Comparer(); - var rootDifferenceNode = comparer.CalculateDifferencesTree(typeof(object), (object)a1, (object)a2); + var rootDifferenceNode = comparer.CalculateDifferenceTree(typeof(object), (object)a1, (object)a2); var calculateDifferences = rootDifferenceNode.GetDifferences(true); Assert.IsTrue(calculateDifferences.Any()); diff --git a/ObjectsComparer/ObjectsComparer.Tests/Comparer_ExpandoObjectsTests.cs b/ObjectsComparer/ObjectsComparer.Tests/Comparer_ExpandoObjectsTests.cs index 289678f..032a1dc 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/Comparer_ExpandoObjectsTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/Comparer_ExpandoObjectsTests.cs @@ -120,7 +120,7 @@ public void Hierarchy_CheckComparisonContext() Assert.AreEqual(1, differences.Count); Assert.IsTrue(differences.Any(d => d.MemberPath == "FieldSub1.Field1" && d.Value1 == "10" && d.Value2 == "8")); - var rootNode = comparer.CalculateDifferencesTree(typeof(object), (object)a1, (object)a2); + var rootNode = comparer.CalculateDifferenceTree(typeof(object), (object)a1, (object)a2); var treeDifferences = rootNode.GetDifferences(true).ToList(); Assert.IsTrue(treeDifferences.Any(d => d.MemberPath == "FieldSub1.Field1" && d.Value1 == "10" && d.Value2 == "8")); } @@ -296,7 +296,7 @@ public void UseDefaultValuesWhenSubclassNotSpecified_CheckComparisonContext() var obja1 = (object)a1; var obja2 = (object)a2; - var rootNode = comparer.CalculateDifferencesTree(((object)a1).GetType(), obja1, obja2); + var rootNode = comparer.CalculateDifferenceTree(((object)a1).GetType(), obja1, obja2); IEnumerable diffs = rootNode.GetDifferences(true); var differences = diffs.ToArray(); @@ -345,7 +345,7 @@ public void DifferenceWhenSubclassNotSpecified_CheckComparisonContext() var obja1 = (object)a1; var obja2 = (object)a2; - var rootNode = comparer.CalculateDifferencesTree(((object)a1).GetType(), obja1, obja2); + var rootNode = comparer.CalculateDifferenceTree(((object)a1).GetType(), obja1, obja2); var calculateDifferences = rootNode.GetDifferences(true).ToList(); Assert.AreEqual(1, calculateDifferences.Count); diff --git a/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs b/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs index 232647e..216424e 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs @@ -69,7 +69,7 @@ public void PrimitiveTypeArrayInequalityCount_CompareUnequalLists() var comparer = new Comparer(settings); - var rootNode = comparer.CalculateDifferencesTree(a1, a2); + var rootNode = comparer.CalculateDifferenceTree(a1, a2); var differences = rootNode.GetDifferences(true).ToList(); CollectionAssert.IsNotEmpty(differences); diff --git a/ObjectsComparer/ObjectsComparer.Tests/Comparer_MultidimensionalArraysTests.cs b/ObjectsComparer/ObjectsComparer.Tests/Comparer_MultidimensionalArraysTests.cs index 3d34338..93d85c9 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/Comparer_MultidimensionalArraysTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/Comparer_MultidimensionalArraysTests.cs @@ -412,7 +412,7 @@ public void IntIntInequality7_CheckComparisonContext() var a2 = new MultidimensionalArrays { IntInt = null }; var comparer = new Comparer(); - var rootNode = comparer.CalculateDifferencesTree(a1, a2); + var rootNode = comparer.CalculateDifferenceTree(a1, a2); var differences = rootNode.GetDifferences(true).ToList(); CollectionAssert.IsNotEmpty(differences); diff --git a/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs b/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs index 0779652..791b15a 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs @@ -187,7 +187,7 @@ public void InequalityProperty_CompareByKey() var comparer = new Comparer(settings); - var rootNode = comparer.CalculateDifferencesTree(a1, a2); + var rootNode = comparer.CalculateDifferenceTree(a1, a2); var differences = rootNode.GetDifferences(true); CollectionAssert.IsNotEmpty(differences); diff --git a/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs b/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs index 5d3345d..6cc3622 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs @@ -113,7 +113,7 @@ public void FluentTest_CompareUnequalLists() settings.ConfigureListComparison(compareUnequalLists: true); var comparer = new Comparer(settings); - var rootNode = comparer.CalculateDifferencesTree(a1.GetType(), a1, a2); + var rootNode = comparer.CalculateDifferenceTree(a1.GetType(), a1, a2); var differences = rootNode.GetDifferences(true).ToList(); Assert.AreEqual(4, differences.Count); @@ -150,7 +150,7 @@ public void FluentTest_CompareUnequalLists_ByKey() var comparer = new Comparer(settings); - var rootNode = comparer.CalculateDifferencesTree(a1.GetType(), a1, a2); + var rootNode = comparer.CalculateDifferenceTree(a1.GetType(), a1, a2); var differences = rootNode.GetDifferences(true).ToList(); Assert.AreEqual(2, differences.Count); diff --git a/ObjectsComparer/ObjectsComparer/Comparer.cs b/ObjectsComparer/ObjectsComparer/Comparer.cs index 4e45e91..e97747d 100644 --- a/ObjectsComparer/ObjectsComparer/Comparer.cs +++ b/ObjectsComparer/ObjectsComparer/Comparer.cs @@ -18,9 +18,9 @@ private static string CalculateDifferencesMethodName get { return MemberInfoExtensions.GetMethodName>(x => x.CalculateDifferences(null, null)); } } - private static string BuildDifferencesTreeMethodName + private static string BuildDifferenceTreeMethodName { - get { return MemberInfoExtensions.GetMethodName>(x => x.BuildDifferencesTree(null, null, null)); } + get { return MemberInfoExtensions.GetMethodName>(x => x.BuildDifferenceTree(null, null, null)); } } /// @@ -35,13 +35,13 @@ public Comparer(ComparisonSettings settings = null, BaseComparer parentComparer public override IEnumerable CalculateDifferences(Type type, object obj1, object obj2) { - return AsContextableComparer().CalculateDifferences(type, obj1, obj2, ComparisonContextProvider.CreateImplicitRootContext(Settings)) + return AsContextableComparer().BuildDifferenceTree(type, obj1, obj2, ComparisonContextProvider.CreateImplicitRootContext(Settings)) .Select(differenceLoccation => differenceLoccation.Difference); } IDifferenceTreeBuilder AsContextableComparer() => this; - IEnumerable IDifferenceTreeBuilder.CalculateDifferences(Type type, object obj1, object obj2, IDifferenceTreeNode comparisonContext) + IEnumerable IDifferenceTreeBuilder.BuildDifferenceTree(Type type, object obj1, object obj2, IDifferenceTreeNode comparisonContext) { if (comparisonContext is null) { @@ -59,7 +59,7 @@ IEnumerable IDifferenceTreeBuilder.CalculateDifferences(Type { if (comparer is IDifferenceTreeBuilder contextableComparer) { - var diffLocationList = contextableComparer.CalculateDifferences(type, obj1, obj2, comparisonContext); + var diffLocationList = contextableComparer.BuildDifferenceTree(type, obj1, obj2, comparisonContext); foreach (var diffLocation in diffLocationList) { @@ -73,7 +73,7 @@ IEnumerable IDifferenceTreeBuilder.CalculateDifferences(Type } var genericType = comparerIsIContextableComparerT ? typeof(IDifferenceTreeBuilder<>).MakeGenericType(type) : typeof(IComparer<>).MakeGenericType(type); - var genericMethodName = comparerIsIContextableComparerT ? BuildDifferencesTreeMethodName : CalculateDifferencesMethodName; + var genericMethodName = comparerIsIContextableComparerT ? BuildDifferenceTreeMethodName : CalculateDifferencesMethodName; var genericMethodParameterTypes = comparerIsIContextableComparerT ? new[] { type, type, typeof(IDifferenceTreeNode) } : new[] { type, type }; var genericMethod = genericType.GetTypeInfo().GetMethod(genericMethodName, genericMethodParameterTypes); var genericMethodParameters = comparerIsIContextableComparerT ? new[] { obj1, obj2, comparisonContext } : new[] { obj1, obj2 }; diff --git a/ObjectsComparer/ObjectsComparer/Comparer~1.cs b/ObjectsComparer/ObjectsComparer/Comparer~1.cs index 0694e70..660c86a 100644 --- a/ObjectsComparer/ObjectsComparer/Comparer~1.cs +++ b/ObjectsComparer/ObjectsComparer/Comparer~1.cs @@ -57,7 +57,7 @@ public override IEnumerable CalculateDifferences(T obj1, T obj2) return CalculateDifferences(obj1, obj2, memberInfo: null); } - IEnumerable IDifferenceTreeBuilder.BuildDifferencesTree(T obj1, T obj2, IDifferenceTreeNode comparisonContext) + IEnumerable IDifferenceTreeBuilder.BuildDifferenceTree(T obj1, T obj2, IDifferenceTreeNode comparisonContext) { return CalculateDifferences(obj1, obj2, memberInfo: null, comparisonContext); } diff --git a/ObjectsComparer/ObjectsComparer/Context/ComparerExtensions.cs b/ObjectsComparer/ObjectsComparer/Context/ComparerExtensions.cs index 7af178f..87b9198 100644 --- a/ObjectsComparer/ObjectsComparer/Context/ComparerExtensions.cs +++ b/ObjectsComparer/ObjectsComparer/Context/ComparerExtensions.cs @@ -10,7 +10,7 @@ public static class ComparerExtensions /// /// Calculates list of differences between objects. Accepts comparison context. /// - public static IDifferenceTreeNode CalculateDifferencesTree(this IComparer comparer, Type type, object obj1, object obj2, Func findNextDifference = null, Action contextCompleted = null) + public static IDifferenceTreeNode CalculateDifferenceTree(this IComparer comparer, Type type, object obj1, object obj2, Func findNextDifference = null, Action contextCompleted = null) { if (comparer is null) { @@ -42,7 +42,7 @@ public static IDifferenceTreeNode CalculateDifferencesTree(this IComparer compar /// /// Calculates list of differences between objects. Accepts comparison context. /// - public static IDifferenceTreeNode CalculateDifferencesTree(this IComparer comparer, T obj1, T obj2, Func findNextDifference = null, Action contextCompleted = null) + public static IDifferenceTreeNode CalculateDifferenceTree(this IComparer comparer, T obj1, T obj2, Func findNextDifference = null, Action contextCompleted = null) { if (comparer is null) { diff --git a/ObjectsComparer/ObjectsComparer/Context/ContextableExtensions.cs b/ObjectsComparer/ObjectsComparer/Context/ContextableExtensions.cs index 9332166..3aa488a 100644 --- a/ObjectsComparer/ObjectsComparer/Context/ContextableExtensions.cs +++ b/ObjectsComparer/ObjectsComparer/Context/ContextableExtensions.cs @@ -31,7 +31,7 @@ public static IEnumerable CalculateDifferences(this ICompare if (comparer is IDifferenceTreeBuilder contextableComparer) { - var differenceTreeNodeInfoList = contextableComparer.CalculateDifferences(type, obj1, obj2, comparisonContext); + var differenceTreeNodeInfoList = contextableComparer.BuildDifferenceTree(type, obj1, obj2, comparisonContext); foreach (var differenceTreeNodeInfo in differenceTreeNodeInfoList) { @@ -69,7 +69,7 @@ public static IEnumerable CalculateDifferences(this IComp if (comparer is IDifferenceTreeBuilder contextableComparer) { - var differenceTreeNodeInfoList = contextableComparer.BuildDifferencesTree(obj1, obj2, comparisonContext); + var differenceTreeNodeInfoList = contextableComparer.BuildDifferenceTree(obj1, obj2, comparisonContext); foreach (var differenceTreeNodeInfo in differenceTreeNodeInfoList) { diff --git a/ObjectsComparer/ObjectsComparer/Context/IDifferenceTreeBuilder.cs b/ObjectsComparer/ObjectsComparer/Context/IDifferenceTreeBuilder.cs index 89d8d2b..3a78f28 100644 --- a/ObjectsComparer/ObjectsComparer/Context/IDifferenceTreeBuilder.cs +++ b/ObjectsComparer/ObjectsComparer/Context/IDifferenceTreeBuilder.cs @@ -11,8 +11,8 @@ public interface IDifferenceTreeBuilder /// /// Finds the difference, adds it to the difference tree and returns it, including its location. /// - /// Intended for implementers. To avoid side effects, consumers should call extension method instead. + /// Intended for implementers. To avoid side effects, consumers should call extension method instead. /// The location of the difference in the difference tree. - IEnumerable CalculateDifferences(Type type, object obj1, object obj2, IDifferenceTreeNode comparisonContext); + IEnumerable BuildDifferenceTree(Type type, object obj1, object obj2, IDifferenceTreeNode comparisonContext); } } \ No newline at end of file diff --git a/ObjectsComparer/ObjectsComparer/Context/IDifferenceTreeBuilder~1.cs b/ObjectsComparer/ObjectsComparer/Context/IDifferenceTreeBuilder~1.cs index 22694ae..14cd6cc 100644 --- a/ObjectsComparer/ObjectsComparer/Context/IDifferenceTreeBuilder~1.cs +++ b/ObjectsComparer/ObjectsComparer/Context/IDifferenceTreeBuilder~1.cs @@ -11,8 +11,8 @@ public interface IDifferenceTreeBuilder /// /// Finds the difference, adds it to the difference tree and returns it, including its location. /// - /// Intended for implementers. To avoid side effects, consumers should call extension method instead. + /// Intended for implementers. To avoid side effects, consumers should call extension method instead. /// The location of the difference in the difference tree. - IEnumerable BuildDifferencesTree(T obj1, T obj2, IDifferenceTreeNode comparisonContext); + IEnumerable BuildDifferenceTree(T obj1, T obj2, IDifferenceTreeNode comparisonContext); } } diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractDynamicObjectsComprer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractDynamicObjectsComprer.cs index 68ec3ef..2428ad2 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractDynamicObjectsComprer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractDynamicObjectsComprer.cs @@ -15,13 +15,13 @@ protected AbstractDynamicObjectsComprer(ComparisonSettings settings, BaseCompare public override IEnumerable CalculateDifferences(Type type, object obj1, object obj2) { - return AsContextableComparer().CalculateDifferences(type, obj1, obj2, ComparisonContextProvider.CreateImplicitRootContext(Settings)) + return AsContextableComparer().BuildDifferenceTree(type, obj1, obj2, ComparisonContextProvider.CreateImplicitRootContext(Settings)) .Select(differenceLocation => differenceLocation.Difference); } - IEnumerable IDifferenceTreeBuilder.BuildDifferencesTree(T obj1, T obj2, IDifferenceTreeNode comparisonContext) + IEnumerable IDifferenceTreeBuilder.BuildDifferenceTree(T obj1, T obj2, IDifferenceTreeNode comparisonContext) { - return AsContextableComparer().CalculateDifferences(typeof(T), obj1, obj2, ComparisonContextProvider.CreateImplicitRootContext(Settings)); + return AsContextableComparer().BuildDifferenceTree(typeof(T), obj1, obj2, ComparisonContextProvider.CreateImplicitRootContext(Settings)); } IDifferenceTreeBuilder AsContextableComparer() @@ -29,7 +29,7 @@ IDifferenceTreeBuilder AsContextableComparer() return this; } - IEnumerable IDifferenceTreeBuilder.CalculateDifferences(Type type, object obj1, object obj2, IDifferenceTreeNode comparisonContext) + IEnumerable IDifferenceTreeBuilder.BuildDifferenceTree(Type type, object obj1, object obj2, IDifferenceTreeNode comparisonContext) { var castedObject1 = (T)obj1; var castedObject2 = (T)obj2; diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractEnumerablesComparer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractEnumerablesComparer.cs index a11d227..c46dd0f 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractEnumerablesComparer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractEnumerablesComparer.cs @@ -60,6 +60,6 @@ public virtual bool SkipMember(Type type, MemberInfo member) public abstract bool IsMatch(Type type, object obj1, object obj2); - public abstract IEnumerable CalculateDifferences(Type type, object obj1, object obj2, IDifferenceTreeNode comparisonContext); + public abstract IEnumerable BuildDifferenceTree(Type type, object obj1, object obj2, IDifferenceTreeNode comparisonContext); } } \ No newline at end of file diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs index 4ae44fa..c2dac8f 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs @@ -18,13 +18,13 @@ public EnumerablesComparer(ComparisonSettings settings, BaseComparer parentCompa public override IEnumerable CalculateDifferences(Type type, object obj1, object obj2) { - return AsContextable().CalculateDifferences(type, obj1, obj2, ComparisonContextProvider.CreateImplicitRootContext(Settings)) + return AsContextable().BuildDifferenceTree(type, obj1, obj2, ComparisonContextProvider.CreateImplicitRootContext(Settings)) .Select(differenceLocation => differenceLocation.Difference); } IDifferenceTreeBuilder AsContextable() => this; - IEnumerable IDifferenceTreeBuilder.CalculateDifferences(Type type, object obj1, object obj2, IDifferenceTreeNode listComparisonContext) + IEnumerable IDifferenceTreeBuilder.BuildDifferenceTree(Type type, object obj1, object obj2, IDifferenceTreeNode listComparisonContext) { Debug.WriteLine($"{GetType().Name}.{nameof(CalculateDifferences)}: {type.Name}"); diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer~1.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer~1.cs index 73b586e..4d6855b 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer~1.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer~1.cs @@ -19,13 +19,13 @@ public EnumerablesComparer(ComparisonSettings settings, BaseComparer parentCompa public override IEnumerable CalculateDifferences(Type type, object obj1, object obj2) { - return CalculateDifferences(type, obj1, obj2, ComparisonContextProvider.CreateImplicitRootContext(Settings)) + return BuildDifferenceTree(type, obj1, obj2, ComparisonContextProvider.CreateImplicitRootContext(Settings)) .Select(differeneLocation => differeneLocation.Difference); } - public IEnumerable CalculateDifferences(Type type, object obj1, object obj2, IDifferenceTreeNode listComparisonContext) + public IEnumerable BuildDifferenceTree(Type type, object obj1, object obj2, IDifferenceTreeNode listComparisonContext) { - Debug.WriteLine($"{GetType().Name}.{nameof(BuildDifferencesTree)}: {type.Name}"); + Debug.WriteLine($"{GetType().Name}.{nameof(BuildDifferenceTree)}: {type.Name}"); if (listComparisonContext is null) { @@ -83,9 +83,9 @@ public IEnumerable CalculateDifferences(Type type, object ob } } - public IEnumerable BuildDifferencesTree(T obj1, T obj2, IDifferenceTreeNode listComparisonContext) + public IEnumerable BuildDifferenceTree(T obj1, T obj2, IDifferenceTreeNode listComparisonContext) { - return CalculateDifferences(((object)obj1 ?? obj2).GetType(), obj1, obj2, listComparisonContext); + return BuildDifferenceTree(((object)obj1 ?? obj2).GetType(), obj1, obj2, listComparisonContext); } } } diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/GenericEnumerablesComparer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/GenericEnumerablesComparer.cs index 287e4d1..37ac78f 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/GenericEnumerablesComparer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/GenericEnumerablesComparer.cs @@ -18,11 +18,11 @@ public GenericEnumerablesComparer(ComparisonSettings settings, BaseComparer pare public override IEnumerable CalculateDifferences(Type type, object obj1, object obj2) { - return CalculateDifferences(type, obj1, obj2, ComparisonContextProvider.CreateImplicitRootContext(Settings)) + return BuildDifferenceTree(type, obj1, obj2, ComparisonContextProvider.CreateImplicitRootContext(Settings)) .Select(differenceLocation => differenceLocation.Difference); } - public override IEnumerable CalculateDifferences(Type type, object obj1, object obj2, IDifferenceTreeNode comparisonContext) + public override IEnumerable BuildDifferenceTree(Type type, object obj1, object obj2, IDifferenceTreeNode comparisonContext) { if (obj1 == null && obj2 == null) { diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/HashSetsComparer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/HashSetsComparer.cs index e6e9936..bfe81cc 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/HashSetsComparer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/HashSetsComparer.cs @@ -16,11 +16,11 @@ public HashSetsComparer(ComparisonSettings settings, BaseComparer parentComparer public override IEnumerable CalculateDifferences(Type type, object obj1, object obj2) { - return CalculateDifferences(type, obj1, obj2, ComparisonContextProvider.CreateImplicitRootContext(Settings)) + return BuildDifferenceTree(type, obj1, obj2, ComparisonContextProvider.CreateImplicitRootContext(Settings)) .Select(differenceLocation => differenceLocation.Difference); } - public override IEnumerable CalculateDifferences(Type type, object obj1, object obj2, IDifferenceTreeNode comparisonContext) + public override IEnumerable BuildDifferenceTree(Type type, object obj1, object obj2, IDifferenceTreeNode comparisonContext) { if (obj1 == null && obj2 == null) { diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/HashSetsComparer~1.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/HashSetsComparer~1.cs index 7263c9f..aa949eb 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/HashSetsComparer~1.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/HashSetsComparer~1.cs @@ -13,18 +13,18 @@ public HashSetsComparer(ComparisonSettings settings, BaseComparer parentComparer { } - public IEnumerable BuildDifferencesTree(T obj1, T obj2, IDifferenceTreeNode comparisonContext) + public IEnumerable BuildDifferenceTree(T obj1, T obj2, IDifferenceTreeNode comparisonContext) { - return CalculateDifferences(typeof(T), obj1, obj2, comparisonContext); + return BuildDifferenceTree(typeof(T), obj1, obj2, comparisonContext); } public override IEnumerable CalculateDifferences(Type type, object obj1, object obj2) { - return CalculateDifferences(type, obj1, obj2, ComparisonContextProvider.CreateImplicitRootContext(Settings)) + return BuildDifferenceTree(type, obj1, obj2, ComparisonContextProvider.CreateImplicitRootContext(Settings)) .Select(differenceLocation => differenceLocation.Difference); } - public IEnumerable CalculateDifferences(Type type, object obj1, object obj2, IDifferenceTreeNode comparisonContext) + public IEnumerable BuildDifferenceTree(Type type, object obj1, object obj2, IDifferenceTreeNode comparisonContext) { if (comparisonContext is null) { diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/MultidimensionalArrayComparer~1.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/MultidimensionalArrayComparer~1.cs index 9e204a7..d932ec9 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/MultidimensionalArrayComparer~1.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/MultidimensionalArrayComparer~1.cs @@ -18,16 +18,16 @@ public MultidimensionalArrayComparer(ComparisonSettings settings, BaseComparer p public override IEnumerable CalculateDifferences(Type type, object obj1, object obj2) { - return CalculateDifferences(type, obj1, obj2, ComparisonContextProvider.CreateImplicitRootContext(Settings)) + return BuildDifferenceTree(type, obj1, obj2, ComparisonContextProvider.CreateImplicitRootContext(Settings)) .Select(differenceLocation => differenceLocation.Difference); } - public IEnumerable BuildDifferencesTree(T obj1, T obj2, IDifferenceTreeNode comparisonContext) + public IEnumerable BuildDifferenceTree(T obj1, T obj2, IDifferenceTreeNode comparisonContext) { - return CalculateDifferences(typeof(T), obj1, obj2, comparisonContext); + return BuildDifferenceTree(typeof(T), obj1, obj2, comparisonContext); } - public IEnumerable CalculateDifferences(Type type, object obj1, object obj2, IDifferenceTreeNode comparisonContext) + public IEnumerable BuildDifferenceTree(Type type, object obj1, object obj2, IDifferenceTreeNode comparisonContext) { if (comparisonContext is null) { diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/MultidimensionalArraysComparer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/MultidimensionalArraysComparer.cs index d178d11..102cf8a 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/MultidimensionalArraysComparer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/MultidimensionalArraysComparer.cs @@ -17,11 +17,11 @@ public MultidimensionalArraysComparer(ComparisonSettings settings, BaseComparer public override IEnumerable CalculateDifferences(Type type, object obj1, object obj2) { - return CalculateDifferences(type, obj1, obj2, ComparisonContextProvider.CreateImplicitRootContext(Settings)) + return BuildDifferenceTree(type, obj1, obj2, ComparisonContextProvider.CreateImplicitRootContext(Settings)) .Select(differenceLocation => differenceLocation.Difference); } - public override IEnumerable CalculateDifferences(Type type, object obj1, object obj2, IDifferenceTreeNode comparisonContext) + public override IEnumerable BuildDifferenceTree(Type type, object obj1, object obj2, IDifferenceTreeNode comparisonContext) { if (obj1 == null && obj2 == null) { diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/TypesComparer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/TypesComparer.cs index 23b5022..1bbe424 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/TypesComparer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/TypesComparer.cs @@ -17,11 +17,11 @@ public TypesComparer(ComparisonSettings settings, BaseComparer parentComparer, public override IEnumerable CalculateDifferences(Type type, object obj1, object obj2) { - return CalculateDifferences(type, obj1, obj2, ComparisonContextProvider.CreateImplicitRootContext(Settings)) + return BuildDifferenceTree(type, obj1, obj2, ComparisonContextProvider.CreateImplicitRootContext(Settings)) .Select(differenceLocation => differenceLocation.Difference); } - public IEnumerable CalculateDifferences(Type type, object obj1, object obj2, IDifferenceTreeNode comparisonContext) + public IEnumerable BuildDifferenceTree(Type type, object obj1, object obj2, IDifferenceTreeNode comparisonContext) { if (comparisonContext is null) { From ff5648182fd7d7beb8c8ea842aa1172893652ef0 Mon Sep 17 00:00:00 2001 From: Daniel Nemec Date: Tue, 12 Apr 2022 07:25:31 +0200 Subject: [PATCH 127/181] Rename nms ObjectsComparer.ContextExtensions with ObjectsComparer.DifferenceTreeExtensions. --- ObjectsComparer/ObjectsComparer/BaseComparer.cs | 2 +- ObjectsComparer/ObjectsComparer/Comparer.cs | 2 +- ObjectsComparer/ObjectsComparer/Comparer~1.cs | 2 +- .../CustomComparers/AbstractDynamicObjectsComprer.cs | 2 +- .../CustomComparers/AbstractEnumerablesComparer.cs | 2 +- .../ObjectsComparer/CustomComparers/EnumerablesComparer.cs | 2 +- .../ObjectsComparer/CustomComparers/EnumerablesComparerBase.cs | 2 +- .../ObjectsComparer/CustomComparers/EnumerablesComparer~1.cs | 2 +- .../CustomComparers/GenericEnumerablesComparer.cs | 2 +- .../ObjectsComparer/CustomComparers/HashSetsComparer.cs | 2 +- .../ObjectsComparer/CustomComparers/HashSetsComparer~1.cs | 2 +- .../CustomComparers/MultidimensionalArrayComparer~1.cs | 2 +- .../CustomComparers/MultidimensionalArraysComparer.cs | 2 +- .../ObjectsComparer/CustomComparers/TypesComparer.cs | 2 +- .../{Context => DifferenceTree}/ComparerExtensions.cs | 2 +- .../{Context => DifferenceTree}/ComparisonContextOptions.cs | 0 .../{Context => DifferenceTree}/ComparisonContextProvider.cs | 0 .../{Context => DifferenceTree}/ContextableExtensions.cs | 2 +- .../{Context => DifferenceTree}/DifferenceLocation.cs | 2 +- .../{Context => DifferenceTree}/DifferenceTreeNode.cs | 0 .../{Context => DifferenceTree}/DifferenceTreeNodeBase.cs | 0 .../{Context => DifferenceTree}/DifferenceTreeNodeMember.cs | 0 .../{Context => DifferenceTree}/IDifferenceTreeBuilder.cs | 2 +- .../{Context => DifferenceTree}/IDifferenceTreeBuilder~1.cs | 2 +- .../{Context => DifferenceTree}/IDifferenceTreeNode.cs | 0 .../{Context => DifferenceTree}/IDifferenceTreeNodeMember.cs | 0 .../{Context => DifferenceTree}/ImplicitDifferenceTreeNode.cs | 0 27 files changed, 19 insertions(+), 19 deletions(-) rename ObjectsComparer/ObjectsComparer/{Context => DifferenceTree}/ComparerExtensions.cs (98%) rename ObjectsComparer/ObjectsComparer/{Context => DifferenceTree}/ComparisonContextOptions.cs (100%) rename ObjectsComparer/ObjectsComparer/{Context => DifferenceTree}/ComparisonContextProvider.cs (100%) rename ObjectsComparer/ObjectsComparer/{Context => DifferenceTree}/ContextableExtensions.cs (99%) rename ObjectsComparer/ObjectsComparer/{Context => DifferenceTree}/DifferenceLocation.cs (91%) rename ObjectsComparer/ObjectsComparer/{Context => DifferenceTree}/DifferenceTreeNode.cs (100%) rename ObjectsComparer/ObjectsComparer/{Context => DifferenceTree}/DifferenceTreeNodeBase.cs (100%) rename ObjectsComparer/ObjectsComparer/{Context => DifferenceTree}/DifferenceTreeNodeMember.cs (100%) rename ObjectsComparer/ObjectsComparer/{Context => DifferenceTree}/IDifferenceTreeBuilder.cs (94%) rename ObjectsComparer/ObjectsComparer/{Context => DifferenceTree}/IDifferenceTreeBuilder~1.cs (94%) rename ObjectsComparer/ObjectsComparer/{Context => DifferenceTree}/IDifferenceTreeNode.cs (100%) rename ObjectsComparer/ObjectsComparer/{Context => DifferenceTree}/IDifferenceTreeNodeMember.cs (100%) rename ObjectsComparer/ObjectsComparer/{Context => DifferenceTree}/ImplicitDifferenceTreeNode.cs (100%) diff --git a/ObjectsComparer/ObjectsComparer/BaseComparer.cs b/ObjectsComparer/ObjectsComparer/BaseComparer.cs index be505d6..211af86 100644 --- a/ObjectsComparer/ObjectsComparer/BaseComparer.cs +++ b/ObjectsComparer/ObjectsComparer/BaseComparer.cs @@ -2,7 +2,7 @@ using System.Linq.Expressions; using System.Reflection; using ObjectsComparer.Utils; -using ObjectsComparer.ContextExtensions; +using ObjectsComparer.DifferenceTreeExtensions; namespace ObjectsComparer { diff --git a/ObjectsComparer/ObjectsComparer/Comparer.cs b/ObjectsComparer/ObjectsComparer/Comparer.cs index e97747d..875c0b0 100644 --- a/ObjectsComparer/ObjectsComparer/Comparer.cs +++ b/ObjectsComparer/ObjectsComparer/Comparer.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.Linq; using System.Reflection; -using ObjectsComparer.ContextExtensions; +using ObjectsComparer.DifferenceTreeExtensions; using ObjectsComparer.Utils; namespace ObjectsComparer diff --git a/ObjectsComparer/ObjectsComparer/Comparer~1.cs b/ObjectsComparer/ObjectsComparer/Comparer~1.cs index 660c86a..d9623ed 100644 --- a/ObjectsComparer/ObjectsComparer/Comparer~1.cs +++ b/ObjectsComparer/ObjectsComparer/Comparer~1.cs @@ -3,7 +3,7 @@ using System.Linq; using System.Reflection; using System.Text; -using ObjectsComparer.ContextExtensions; +using ObjectsComparer.DifferenceTreeExtensions; using ObjectsComparer.Utils; namespace ObjectsComparer diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractDynamicObjectsComprer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractDynamicObjectsComprer.cs index 2428ad2..3eb8b0c 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractDynamicObjectsComprer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractDynamicObjectsComprer.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.Linq; using System.Reflection; -using ObjectsComparer.ContextExtensions; +using ObjectsComparer.DifferenceTreeExtensions; using ObjectsComparer.Utils; namespace ObjectsComparer diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractEnumerablesComparer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractEnumerablesComparer.cs index c46dd0f..8f79f5b 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractEnumerablesComparer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractEnumerablesComparer.cs @@ -4,7 +4,7 @@ using System.Reflection; using ObjectsComparer.Utils; using System.Collections; -using ObjectsComparer.ContextExtensions; +using ObjectsComparer.DifferenceTreeExtensions; namespace ObjectsComparer { diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs index c2dac8f..c1a4012 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs @@ -4,7 +4,7 @@ using System.Diagnostics; using System.Linq; using System.Reflection; -using ObjectsComparer.ContextExtensions; +using ObjectsComparer.DifferenceTreeExtensions; using ObjectsComparer.Exceptions; using ObjectsComparer.Utils; diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparerBase.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparerBase.cs index d3d90c0..40de07a 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparerBase.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparerBase.cs @@ -1,4 +1,4 @@ -using ObjectsComparer.ContextExtensions; +using ObjectsComparer.DifferenceTreeExtensions; using ObjectsComparer.Exceptions; using System; using System.Collections.Generic; diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer~1.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer~1.cs index 4d6855b..bfc6f25 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer~1.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer~1.cs @@ -3,7 +3,7 @@ using System.Diagnostics; using System.Linq; using System.Reflection; -using ObjectsComparer.ContextExtensions; +using ObjectsComparer.DifferenceTreeExtensions; using ObjectsComparer.Utils; namespace ObjectsComparer diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/GenericEnumerablesComparer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/GenericEnumerablesComparer.cs index 37ac78f..d4f48ff 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/GenericEnumerablesComparer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/GenericEnumerablesComparer.cs @@ -3,7 +3,7 @@ using System.Collections.ObjectModel; using System.Linq; using System.Reflection; -using ObjectsComparer.ContextExtensions; +using ObjectsComparer.DifferenceTreeExtensions; using ObjectsComparer.Utils; namespace ObjectsComparer diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/HashSetsComparer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/HashSetsComparer.cs index bfe81cc..055f091 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/HashSetsComparer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/HashSetsComparer.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.Linq; using System.Reflection; -using ObjectsComparer.ContextExtensions; +using ObjectsComparer.DifferenceTreeExtensions; using ObjectsComparer.Utils; namespace ObjectsComparer diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/HashSetsComparer~1.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/HashSetsComparer~1.cs index aa949eb..bc57202 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/HashSetsComparer~1.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/HashSetsComparer~1.cs @@ -1,7 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; -using ObjectsComparer.ContextExtensions; +using ObjectsComparer.DifferenceTreeExtensions; using ObjectsComparer.Utils; namespace ObjectsComparer diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/MultidimensionalArrayComparer~1.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/MultidimensionalArrayComparer~1.cs index d932ec9..cb250a3 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/MultidimensionalArrayComparer~1.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/MultidimensionalArrayComparer~1.cs @@ -1,7 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; -using ObjectsComparer.ContextExtensions; +using ObjectsComparer.DifferenceTreeExtensions; using ObjectsComparer.Utils; namespace ObjectsComparer diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/MultidimensionalArraysComparer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/MultidimensionalArraysComparer.cs index 102cf8a..8450d22 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/MultidimensionalArraysComparer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/MultidimensionalArraysComparer.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.Linq; using System.Reflection; -using ObjectsComparer.ContextExtensions; +using ObjectsComparer.DifferenceTreeExtensions; using ObjectsComparer.Utils; namespace ObjectsComparer diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/TypesComparer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/TypesComparer.cs index 1bbe424..de1ba9b 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/TypesComparer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/TypesComparer.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.Linq; using System.Reflection; -using ObjectsComparer.ContextExtensions; +using ObjectsComparer.DifferenceTreeExtensions; using ObjectsComparer.Utils; namespace ObjectsComparer diff --git a/ObjectsComparer/ObjectsComparer/Context/ComparerExtensions.cs b/ObjectsComparer/ObjectsComparer/DifferenceTree/ComparerExtensions.cs similarity index 98% rename from ObjectsComparer/ObjectsComparer/Context/ComparerExtensions.cs rename to ObjectsComparer/ObjectsComparer/DifferenceTree/ComparerExtensions.cs index 87b9198..c1332b4 100644 --- a/ObjectsComparer/ObjectsComparer/Context/ComparerExtensions.cs +++ b/ObjectsComparer/ObjectsComparer/DifferenceTree/ComparerExtensions.cs @@ -1,4 +1,4 @@ -using ObjectsComparer.ContextExtensions; +using ObjectsComparer.DifferenceTreeExtensions; using ObjectsComparer.Exceptions; using System; using System.Collections.Generic; diff --git a/ObjectsComparer/ObjectsComparer/Context/ComparisonContextOptions.cs b/ObjectsComparer/ObjectsComparer/DifferenceTree/ComparisonContextOptions.cs similarity index 100% rename from ObjectsComparer/ObjectsComparer/Context/ComparisonContextOptions.cs rename to ObjectsComparer/ObjectsComparer/DifferenceTree/ComparisonContextOptions.cs diff --git a/ObjectsComparer/ObjectsComparer/Context/ComparisonContextProvider.cs b/ObjectsComparer/ObjectsComparer/DifferenceTree/ComparisonContextProvider.cs similarity index 100% rename from ObjectsComparer/ObjectsComparer/Context/ComparisonContextProvider.cs rename to ObjectsComparer/ObjectsComparer/DifferenceTree/ComparisonContextProvider.cs diff --git a/ObjectsComparer/ObjectsComparer/Context/ContextableExtensions.cs b/ObjectsComparer/ObjectsComparer/DifferenceTree/ContextableExtensions.cs similarity index 99% rename from ObjectsComparer/ObjectsComparer/Context/ContextableExtensions.cs rename to ObjectsComparer/ObjectsComparer/DifferenceTree/ContextableExtensions.cs index 3aa488a..6093191 100644 --- a/ObjectsComparer/ObjectsComparer/Context/ContextableExtensions.cs +++ b/ObjectsComparer/ObjectsComparer/DifferenceTree/ContextableExtensions.cs @@ -3,7 +3,7 @@ using System.Linq; using System.Collections.Generic; -namespace ObjectsComparer.ContextExtensions +namespace ObjectsComparer.DifferenceTreeExtensions { public static class ContextableExtensions { diff --git a/ObjectsComparer/ObjectsComparer/Context/DifferenceLocation.cs b/ObjectsComparer/ObjectsComparer/DifferenceTree/DifferenceLocation.cs similarity index 91% rename from ObjectsComparer/ObjectsComparer/Context/DifferenceLocation.cs rename to ObjectsComparer/ObjectsComparer/DifferenceTree/DifferenceLocation.cs index c43260d..895247e 100644 --- a/ObjectsComparer/ObjectsComparer/Context/DifferenceLocation.cs +++ b/ObjectsComparer/ObjectsComparer/DifferenceTree/DifferenceLocation.cs @@ -1,6 +1,6 @@ using System; -namespace ObjectsComparer.ContextExtensions +namespace ObjectsComparer.DifferenceTreeExtensions { /// /// The location of the difference in the difference tree. diff --git a/ObjectsComparer/ObjectsComparer/Context/DifferenceTreeNode.cs b/ObjectsComparer/ObjectsComparer/DifferenceTree/DifferenceTreeNode.cs similarity index 100% rename from ObjectsComparer/ObjectsComparer/Context/DifferenceTreeNode.cs rename to ObjectsComparer/ObjectsComparer/DifferenceTree/DifferenceTreeNode.cs diff --git a/ObjectsComparer/ObjectsComparer/Context/DifferenceTreeNodeBase.cs b/ObjectsComparer/ObjectsComparer/DifferenceTree/DifferenceTreeNodeBase.cs similarity index 100% rename from ObjectsComparer/ObjectsComparer/Context/DifferenceTreeNodeBase.cs rename to ObjectsComparer/ObjectsComparer/DifferenceTree/DifferenceTreeNodeBase.cs diff --git a/ObjectsComparer/ObjectsComparer/Context/DifferenceTreeNodeMember.cs b/ObjectsComparer/ObjectsComparer/DifferenceTree/DifferenceTreeNodeMember.cs similarity index 100% rename from ObjectsComparer/ObjectsComparer/Context/DifferenceTreeNodeMember.cs rename to ObjectsComparer/ObjectsComparer/DifferenceTree/DifferenceTreeNodeMember.cs diff --git a/ObjectsComparer/ObjectsComparer/Context/IDifferenceTreeBuilder.cs b/ObjectsComparer/ObjectsComparer/DifferenceTree/IDifferenceTreeBuilder.cs similarity index 94% rename from ObjectsComparer/ObjectsComparer/Context/IDifferenceTreeBuilder.cs rename to ObjectsComparer/ObjectsComparer/DifferenceTree/IDifferenceTreeBuilder.cs index 3a78f28..a55f8d2 100644 --- a/ObjectsComparer/ObjectsComparer/Context/IDifferenceTreeBuilder.cs +++ b/ObjectsComparer/ObjectsComparer/DifferenceTree/IDifferenceTreeBuilder.cs @@ -1,7 +1,7 @@ using System; using System.Collections.Generic; -namespace ObjectsComparer.ContextExtensions +namespace ObjectsComparer.DifferenceTreeExtensions { /// /// Builds the difference tree. diff --git a/ObjectsComparer/ObjectsComparer/Context/IDifferenceTreeBuilder~1.cs b/ObjectsComparer/ObjectsComparer/DifferenceTree/IDifferenceTreeBuilder~1.cs similarity index 94% rename from ObjectsComparer/ObjectsComparer/Context/IDifferenceTreeBuilder~1.cs rename to ObjectsComparer/ObjectsComparer/DifferenceTree/IDifferenceTreeBuilder~1.cs index 14cd6cc..83ed967 100644 --- a/ObjectsComparer/ObjectsComparer/Context/IDifferenceTreeBuilder~1.cs +++ b/ObjectsComparer/ObjectsComparer/DifferenceTree/IDifferenceTreeBuilder~1.cs @@ -1,7 +1,7 @@ using System; using System.Collections.Generic; -namespace ObjectsComparer.ContextExtensions +namespace ObjectsComparer.DifferenceTreeExtensions { /// /// Builds the difference tree. diff --git a/ObjectsComparer/ObjectsComparer/Context/IDifferenceTreeNode.cs b/ObjectsComparer/ObjectsComparer/DifferenceTree/IDifferenceTreeNode.cs similarity index 100% rename from ObjectsComparer/ObjectsComparer/Context/IDifferenceTreeNode.cs rename to ObjectsComparer/ObjectsComparer/DifferenceTree/IDifferenceTreeNode.cs diff --git a/ObjectsComparer/ObjectsComparer/Context/IDifferenceTreeNodeMember.cs b/ObjectsComparer/ObjectsComparer/DifferenceTree/IDifferenceTreeNodeMember.cs similarity index 100% rename from ObjectsComparer/ObjectsComparer/Context/IDifferenceTreeNodeMember.cs rename to ObjectsComparer/ObjectsComparer/DifferenceTree/IDifferenceTreeNodeMember.cs diff --git a/ObjectsComparer/ObjectsComparer/Context/ImplicitDifferenceTreeNode.cs b/ObjectsComparer/ObjectsComparer/DifferenceTree/ImplicitDifferenceTreeNode.cs similarity index 100% rename from ObjectsComparer/ObjectsComparer/Context/ImplicitDifferenceTreeNode.cs rename to ObjectsComparer/ObjectsComparer/DifferenceTree/ImplicitDifferenceTreeNode.cs From fc8d0a31f9fa77ff6fc562fb091e5d2bac103478 Mon Sep 17 00:00:00 2001 From: Daniel Nemec Date: Tue, 12 Apr 2022 08:44:39 +0200 Subject: [PATCH 128/181] Rename operation CalculateDifferences. Rename CalculateDifferences with TryBuildDifferenceTree. Edit comments. --- .../ComparisonContextTests.cs | 2 +- ObjectsComparer/ObjectsComparer/Comparer~1.cs | 10 +++++----- .../AbstractDynamicObjectsComprer.cs | 2 +- .../CustomComparers/EnumerablesComparerBase.cs | 4 ++-- .../GenericEnumerablesComparer.cs | 2 +- .../CustomComparers/HashSetsComparer.cs | 2 +- .../MultidimensionalArrayComparer~1.cs | 2 +- .../MultidimensionalArraysComparer.cs | 2 +- .../DifferenceTree/ComparerExtensions.cs | 12 ++++++------ .../DifferenceTree/ContextableExtensions.cs | 17 ++++++++++------- 10 files changed, 29 insertions(+), 26 deletions(-) diff --git a/ObjectsComparer/ObjectsComparer.Tests/ComparisonContextTests.cs b/ObjectsComparer/ObjectsComparer.Tests/ComparisonContextTests.cs index 0a12875..e093e3d 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/ComparisonContextTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/ComparisonContextTests.cs @@ -74,7 +74,7 @@ public void CustomComparisonContextMember() // var comparer = factory.GetObjectsComparer(); // var rootCtx = ComparisonContextProvider.CreateRootContext(); - // var diffs = comparer.CalculateDifferences("hello", "hi", rootCtx).ToArray(); + // var diffs = comparer.TryBuildDifferenceTree("hello", "hi", rootCtx).ToArray(); //} [Test] diff --git a/ObjectsComparer/ObjectsComparer/Comparer~1.cs b/ObjectsComparer/ObjectsComparer/Comparer~1.cs index d9623ed..263ea60 100644 --- a/ObjectsComparer/ObjectsComparer/Comparer~1.cs +++ b/ObjectsComparer/ObjectsComparer/Comparer~1.cs @@ -59,16 +59,16 @@ public override IEnumerable CalculateDifferences(T obj1, T obj2) IEnumerable IDifferenceTreeBuilder.BuildDifferenceTree(T obj1, T obj2, IDifferenceTreeNode comparisonContext) { - return CalculateDifferences(obj1, obj2, memberInfo: null, comparisonContext); + return BuildDifferenceTree(obj1, obj2, memberInfo: null, comparisonContext); } internal IEnumerable CalculateDifferences(T obj1, T obj2, MemberInfo memberInfo) { - return CalculateDifferences(obj1, obj2, memberInfo, ComparisonContextProvider.CreateImplicitRootContext(Settings)) + return BuildDifferenceTree(obj1, obj2, memberInfo, ComparisonContextProvider.CreateImplicitRootContext(Settings)) .Select(differenceLocation => differenceLocation.Difference); } - IEnumerable CalculateDifferences(T obj1, T obj2, MemberInfo memberInfo, IDifferenceTreeNode comparisonContext) + IEnumerable BuildDifferenceTree(T obj1, T obj2, MemberInfo memberInfo, IDifferenceTreeNode comparisonContext) { var comparer = memberInfo != null ? OverridesCollection.GetComparer(memberInfo) @@ -89,7 +89,7 @@ IEnumerable CalculateDifferences(T obj1, T obj2, MemberInfo var conditionalComparer = _conditionalComparers.FirstOrDefault(c => c.IsMatch(typeof(T), obj1, obj2)); if (conditionalComparer != null) { - foreach (var difference in conditionalComparer.CalculateDifferences(typeof(T), obj1, obj2, comparisonContext)) + foreach (var difference in conditionalComparer.TryBuildDifferenceTree(typeof(T), obj1, obj2, comparisonContext)) { yield return difference; } @@ -143,7 +143,7 @@ IEnumerable CalculateDifferences(T obj1, T obj2, MemberInfo { var objectDataComparer = Factory.GetObjectsComparer(type, Settings, this); - foreach (var failure in objectDataComparer.CalculateDifferences(type, value1, value2, memberContext)) + foreach (var failure in objectDataComparer.TryBuildDifferenceTree(type, value1, value2, memberContext)) { failure.Difference.InsertPath(member.Name); yield return failure; diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractDynamicObjectsComprer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractDynamicObjectsComprer.cs index 3eb8b0c..50eb653 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractDynamicObjectsComprer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractDynamicObjectsComprer.cs @@ -146,7 +146,7 @@ IEnumerable IDifferenceTreeBuilder.BuildDifferenceTree(Type } var comparer = Factory.GetObjectsComparer(propertyType, Settings, this); - foreach (var failure in comparer.CalculateDifferences(propertyType, value1, value2, comparisonContext)) + foreach (var failure in comparer.TryBuildDifferenceTree(propertyType, value1, value2, comparisonContext)) { failure.Difference.InsertPath(propertyKey); yield return failure; diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparerBase.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparerBase.cs index 40de07a..97a2088 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparerBase.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparerBase.cs @@ -80,7 +80,7 @@ protected virtual IEnumerable CalculateDifferencesByKey(I var element2 = array2.First(elm2 => elm2 != null && object.Equals(element1Key, keyOptions.ElementKeyProviderAction(new ListElementKeyProviderArgs(elm2)))); var comparer = Factory.GetObjectsComparer(element1.GetType(), Settings, this); - foreach (var failure in comparer.CalculateDifferences(element1.GetType(), element1, element2, elementComparisonContext)) + foreach (var failure in comparer.TryBuildDifferenceTree(element1.GetType(), element1, element2, elementComparisonContext)) { failure.Difference.InsertPath($"[{formattedElement1Key}]"); yield return failure; @@ -178,7 +178,7 @@ protected virtual IEnumerable CalculateDifferencesByIndex var comparer = Factory.GetObjectsComparer(array1[i].GetType(), Settings, this); - foreach (var failure in comparer.CalculateDifferences(array1[i].GetType(), array1[i], array2[i], elementComparisonContext)) + foreach (var failure in comparer.TryBuildDifferenceTree(array1[i].GetType(), array1[i], array2[i], elementComparisonContext)) { failure.Difference.InsertPath($"[{i}]"); yield return failure; diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/GenericEnumerablesComparer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/GenericEnumerablesComparer.cs index d4f48ff..b52460f 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/GenericEnumerablesComparer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/GenericEnumerablesComparer.cs @@ -51,7 +51,7 @@ public override IEnumerable BuildDifferenceTree(Type type, o var enumerablesComparerType = typeof(EnumerablesComparer<>).MakeGenericType(elementType); var comparer = (IComparer)Activator.CreateInstance(enumerablesComparerType, Settings, this, Factory); - foreach (var difference in comparer.CalculateDifferences(type, obj1, obj2, comparisonContext)) + foreach (var difference in comparer.TryBuildDifferenceTree(type, obj1, obj2, comparisonContext)) { yield return difference; } diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/HashSetsComparer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/HashSetsComparer.cs index 055f091..5faa697 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/HashSetsComparer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/HashSetsComparer.cs @@ -40,7 +40,7 @@ public override IEnumerable BuildDifferenceTree(Type type, o var enumerablesComparerType = typeof(HashSetsComparer<>).MakeGenericType(elementType); var comparer = (IComparer)Activator.CreateInstance(enumerablesComparerType, Settings, this, Factory); - foreach (var difference in comparer.CalculateDifferences(type, obj1, obj2, comparisonContext)) + foreach (var difference in comparer.TryBuildDifferenceTree(type, obj1, obj2, comparisonContext)) { yield return difference; } diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/MultidimensionalArrayComparer~1.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/MultidimensionalArrayComparer~1.cs index cb250a3..76eeeb7 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/MultidimensionalArrayComparer~1.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/MultidimensionalArrayComparer~1.cs @@ -89,7 +89,7 @@ public IEnumerable BuildDifferenceTree(Type type, object obj { var indecies = IndexToCoordinates(array1, i); - foreach (var failure in _comparer.CalculateDifferences((T)array1.GetValue(indecies), (T)array2.GetValue(indecies), comparisonContext)) + foreach (var failure in _comparer.TryBuildDifferenceTree((T)array1.GetValue(indecies), (T)array2.GetValue(indecies), comparisonContext)) { failure.Difference.InsertPath($"[{string.Join(",", indecies)}]"); yield return failure; diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/MultidimensionalArraysComparer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/MultidimensionalArraysComparer.cs index 8450d22..0bb7058 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/MultidimensionalArraysComparer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/MultidimensionalArraysComparer.cs @@ -32,7 +32,7 @@ public override IEnumerable BuildDifferenceTree(Type type, o var enumerablesComparerType = typeof(MultidimensionalArrayComparer<>).MakeGenericType(typeInfo.GetElementType()); var comparer = (IComparer)Activator.CreateInstance(enumerablesComparerType, Settings, this, Factory); - foreach (var difference in comparer.CalculateDifferences(type, obj1, obj2, comparisonContext)) + foreach (var difference in comparer.TryBuildDifferenceTree(type, obj1, obj2, comparisonContext)) { yield return difference; } diff --git a/ObjectsComparer/ObjectsComparer/DifferenceTree/ComparerExtensions.cs b/ObjectsComparer/ObjectsComparer/DifferenceTree/ComparerExtensions.cs index c1332b4..77f4da2 100644 --- a/ObjectsComparer/ObjectsComparer/DifferenceTree/ComparerExtensions.cs +++ b/ObjectsComparer/ObjectsComparer/DifferenceTree/ComparerExtensions.cs @@ -8,7 +8,7 @@ namespace ObjectsComparer public static class ComparerExtensions { /// - /// Calculates list of differences between objects. Accepts comparison context. + /// XXX /// public static IDifferenceTreeNode CalculateDifferenceTree(this IComparer comparer, Type type, object obj1, object obj2, Func findNextDifference = null, Action contextCompleted = null) { @@ -25,9 +25,9 @@ public static IDifferenceTreeNode CalculateDifferenceTree(this IComparer compare findNextDifference = findNextDifference ?? ((_) => true); //Anything but ImplicitComparisonContext (ImplicitDifferenceTreeNode). - var rootCtx = ComparisonContextProvider.CreateContext(comparer.Settings, ancestor: null); + var rootNode = ComparisonContextProvider.CreateContext(comparer.Settings, ancestor: null); - var differenceLocationList = comparer.CalculateDifferences(type, obj1, obj2, rootCtx); + var differenceLocationList = comparer.TryBuildDifferenceTree(type, obj1, obj2, rootNode); differenceLocationList.EnumerateConditional( currentLocation => @@ -36,11 +36,11 @@ public static IDifferenceTreeNode CalculateDifferenceTree(this IComparer compare }, contextCompleted); - return rootCtx; + return rootNode; } /// - /// Calculates list of differences between objects. Accepts comparison context. + /// XXX /// public static IDifferenceTreeNode CalculateDifferenceTree(this IComparer comparer, T obj1, T obj2, Func findNextDifference = null, Action contextCompleted = null) { @@ -53,7 +53,7 @@ public static IDifferenceTreeNode CalculateDifferenceTree(this IComparer c var rootCtx = ComparisonContextProvider.CreateContext(comparer.Settings, ancestor: null); - var differenceLocationList = comparer.CalculateDifferences(obj1, obj2, rootCtx); + var differenceLocationList = comparer.TryBuildDifferenceTree(obj1, obj2, rootCtx); differenceLocationList.EnumerateConditional( currentLocation => diff --git a/ObjectsComparer/ObjectsComparer/DifferenceTree/ContextableExtensions.cs b/ObjectsComparer/ObjectsComparer/DifferenceTree/ContextableExtensions.cs index 6093191..09f1750 100644 --- a/ObjectsComparer/ObjectsComparer/DifferenceTree/ContextableExtensions.cs +++ b/ObjectsComparer/ObjectsComparer/DifferenceTree/ContextableExtensions.cs @@ -8,11 +8,12 @@ namespace ObjectsComparer.DifferenceTreeExtensions public static class ContextableExtensions { /// - /// Calculates list of differences between objects. Accepts comparison context. + /// If is , it looks for the difference, adds it to the difference tree and returns it, including its location. + /// If not, it only looks for the difference and returns it with empty location. /// - /// The method is intended for IContextableComparer implementers. - /// Current difference and its location in the difference tree. - public static IEnumerable CalculateDifferences(this IComparer comparer, Type type, object obj1, object obj2, IDifferenceTreeNode comparisonContext) + /// Intended for implementers. To avoid side effects, consumers should call extension method instead. + /// The location of the difference in the difference tree. + public static IEnumerable TryBuildDifferenceTree(this IComparer comparer, Type type, object obj1, object obj2, IDifferenceTreeNode comparisonContext) { if (comparer is null) { @@ -52,10 +53,12 @@ public static IEnumerable CalculateDifferences(this ICompare } /// - /// Calculates list of differences between objects. Accepts comparison context. + /// If is , it looks for the difference, adds it to the difference tree and returns it, including its location. + /// If not, it only looks for the difference and returns it. /// - /// The method is intended for IContextableComparer implementers. - public static IEnumerable CalculateDifferences(this IComparer comparer, T obj1, T obj2, IDifferenceTreeNode comparisonContext) + /// Intended for implementers. To avoid side effects, consumers should call extension method instead. + /// The location of the difference in the difference tree. + public static IEnumerable TryBuildDifferenceTree(this IComparer comparer, T obj1, T obj2, IDifferenceTreeNode comparisonContext) { if (comparer is null) { From 21d4ff9c07729b9c2c28bf6f76114d768910cbff Mon Sep 17 00:00:00 2001 From: Daniel Nemec Date: Tue, 12 Apr 2022 09:18:31 +0200 Subject: [PATCH 129/181] Rename ContextableComparerNotImplementedException. Rename ContextableComparerNotImplementedException with DifferenceTreeBuilderNotImplementedException. Edit comments. --- .../Example4/Example4Tests.cs | 2 +- ObjectsComparer/ObjectsComparer/Comparer.cs | 2 +- .../ComparisonContextOptions.cs | 2 +- .../DifferenceTree/ContextableExtensions.cs | 57 +++++++++++-------- ...textableComparerNotImplementedException.cs | 7 ++- 5 files changed, 40 insertions(+), 30 deletions(-) diff --git a/ObjectsComparer/ObjectsComparer.Examples/Example4/Example4Tests.cs b/ObjectsComparer/ObjectsComparer.Examples/Example4/Example4Tests.cs index a1a2fb6..b392af5 100644 --- a/ObjectsComparer/ObjectsComparer.Examples/Example4/Example4Tests.cs +++ b/ObjectsComparer/ObjectsComparer.Examples/Example4/Example4Tests.cs @@ -101,7 +101,7 @@ public void CalculateDifferenceTree_Throw_ContextableComparerNotImplemented() } }; - Assert.Throws(() => + Assert.Throws(() => { var rootNode = _comparer.CalculateDifferenceTree(formula1, formula2); var differences = rootNode.GetDifferences(true).ToArray(); diff --git a/ObjectsComparer/ObjectsComparer/Comparer.cs b/ObjectsComparer/ObjectsComparer/Comparer.cs index 875c0b0..88adad7 100644 --- a/ObjectsComparer/ObjectsComparer/Comparer.cs +++ b/ObjectsComparer/ObjectsComparer/Comparer.cs @@ -69,7 +69,7 @@ IEnumerable IDifferenceTreeBuilder.BuildDifferenceTree(Type yield break; } - ContextableExtensions.ThrowContextableComparerNotImplemented(comparisonContext, Settings, comparer, $"{nameof(IDifferenceTreeBuilder)}<{type.FullName}>"); + ContextableExtensions.ThrowDifferenceTreeBuilderNotImplemented(comparisonContext, Settings, comparer, $"{nameof(IDifferenceTreeBuilder)}<{type.FullName}>"); } var genericType = comparerIsIContextableComparerT ? typeof(IDifferenceTreeBuilder<>).MakeGenericType(type) : typeof(IComparer<>).MakeGenericType(type); diff --git a/ObjectsComparer/ObjectsComparer/DifferenceTree/ComparisonContextOptions.cs b/ObjectsComparer/ObjectsComparer/DifferenceTree/ComparisonContextOptions.cs index d9db404..bb980cc 100644 --- a/ObjectsComparer/ObjectsComparer/DifferenceTree/ComparisonContextOptions.cs +++ b/ObjectsComparer/ObjectsComparer/DifferenceTree/ComparisonContextOptions.cs @@ -39,7 +39,7 @@ public void UseComparisonContextMemberFactory(Func - /// Whether to throw the when the user requires comparison context but has a comparer that does not implement or . + /// Whether to throw the when the user requires comparison context but has a comparer that does not implement or . /// Default = true. /// public ComparisonContextOptions ThrowContextableComparerNotImplemented(bool value) diff --git a/ObjectsComparer/ObjectsComparer/DifferenceTree/ContextableExtensions.cs b/ObjectsComparer/ObjectsComparer/DifferenceTree/ContextableExtensions.cs index 09f1750..4bf507a 100644 --- a/ObjectsComparer/ObjectsComparer/DifferenceTree/ContextableExtensions.cs +++ b/ObjectsComparer/ObjectsComparer/DifferenceTree/ContextableExtensions.cs @@ -2,18 +2,23 @@ using System; using System.Linq; using System.Collections.Generic; +using ObjectsComparer.Exceptions; namespace ObjectsComparer.DifferenceTreeExtensions { public static class ContextableExtensions { /// - /// If is , it looks for the difference, adds it to the difference tree and returns it, including its location. - /// If not, it only looks for the difference and returns it with empty location. + /// Builds the difference tree. /// - /// Intended for implementers. To avoid side effects, consumers should call extension method instead. - /// The location of the difference in the difference tree. - public static IEnumerable TryBuildDifferenceTree(this IComparer comparer, Type type, object obj1, object obj2, IDifferenceTreeNode comparisonContext) + /// + /// If is , it looks for the difference, adds it to the difference tree and returns it, including its location. + /// If not, it only looks for the difference and returns it with empty location.
+ /// It throws exception if necessary.
+ /// Intended for implementers. To avoid side effects, consumers should call extension method instead. + ///
+ /// The difference with its eventual location in the difference tree. + public static IEnumerable TryBuildDifferenceTree(this IComparer comparer, Type type, object obj1, object obj2, IDifferenceTreeNode currentNode) { if (comparer is null) { @@ -25,24 +30,24 @@ public static IEnumerable TryBuildDifferenceTree(this ICompa throw new ArgumentNullException(nameof(type)); } - if (comparisonContext is null) + if (currentNode is null) { - throw new ArgumentNullException(nameof(comparisonContext)); + throw new ArgumentNullException(nameof(currentNode)); } - if (comparer is IDifferenceTreeBuilder contextableComparer) + if (comparer is IDifferenceTreeBuilder differenceTreeBuilder) { - var differenceTreeNodeInfoList = contextableComparer.BuildDifferenceTree(type, obj1, obj2, comparisonContext); + var differenceNodeLocationList = differenceTreeBuilder.BuildDifferenceTree(type, obj1, obj2, currentNode); - foreach (var differenceTreeNodeInfo in differenceTreeNodeInfoList) + foreach (var differenceNodeLocation in differenceNodeLocationList) { - yield return differenceTreeNodeInfo; + yield return differenceNodeLocation; } yield break; } - ThrowContextableComparerNotImplemented(comparisonContext, comparer.Settings, comparer, nameof(IDifferenceTreeBuilder)); + ThrowDifferenceTreeBuilderNotImplemented(currentNode, comparer.Settings, comparer, nameof(IDifferenceTreeBuilder)); var differences = comparer.CalculateDifferences(type, obj1, obj2); @@ -53,11 +58,15 @@ public static IEnumerable TryBuildDifferenceTree(this ICompa } /// - /// If is , it looks for the difference, adds it to the difference tree and returns it, including its location. - /// If not, it only looks for the difference and returns it. + /// Builds the difference tree.
///
- /// Intended for implementers. To avoid side effects, consumers should call extension method instead. - /// The location of the difference in the difference tree. + /// + /// If is , it looks for the difference, adds it to the difference tree and returns it, including its location. + /// If not, it only looks for the difference and returns it with empty location.
+ /// It throws exception if necessary.
+ /// Intended for implementers. To avoid side effects, consumers should call extension method instead. + ///
+ /// The difference with its eventual location in the difference tree. public static IEnumerable TryBuildDifferenceTree(this IComparer comparer, T obj1, T obj2, IDifferenceTreeNode comparisonContext) { if (comparer is null) @@ -82,7 +91,7 @@ public static IEnumerable TryBuildDifferenceTree(this ICo yield break; } - ThrowContextableComparerNotImplemented(comparisonContext, comparer.Settings, comparer, $"{nameof(IDifferenceTreeBuilder)}<{typeof(T).FullName}>"); + ThrowDifferenceTreeBuilderNotImplemented(comparisonContext, comparer.Settings, comparer, $"{nameof(IDifferenceTreeBuilder)}<{typeof(T).FullName}>"); var differences = comparer.CalculateDifferences(obj1, obj2); @@ -113,7 +122,7 @@ static bool HasComparisonContextImplicitRoot(IDifferenceTreeNode comparisonConte return false; } - internal static void ThrowContextableComparerNotImplemented(IDifferenceTreeNode comparisonContext, ComparisonSettings comparisonSettings, object comparer, string unImplementedInterface) + internal static void ThrowDifferenceTreeBuilderNotImplemented(IDifferenceTreeNode comparisonContext, ComparisonSettings comparisonSettings, object comparer, string unImplementedInterface) { if (comparisonContext is null) { @@ -136,15 +145,15 @@ internal static void ThrowContextableComparerNotImplemented(IDifferenceTreeNode if (comparisonSettings.ComparisonContextOptionsAction != null) { var message = $"Because the comparison context was explicitly configured, the {comparer.GetType().FullName} must implement {unImplementedInterface} interface " + - "or throwing the ContextableComparerNotImplementedException must be disabled."; - throw new ContextableComparerNotImplementedException(message); + "or throwing the DifferenceTreeBuilderNotImplementedException must be disabled."; + throw new DifferenceTreeBuilderNotImplementedException(message); } if (comparisonSettings.ListComparisonOptionsAction != null) { var message = $"Because the list comparison was explicitly configured, the {comparer.GetType().FullName} must implement {unImplementedInterface} interface " + - "or throwing the ContextableComparerNotImplementedException must be disabled."; - throw new ContextableComparerNotImplementedException(message); + "or throwing the DifferenceTreeBuilderNotImplementedException must be disabled."; + throw new DifferenceTreeBuilderNotImplementedException(message); } //TODO: Check DifferenceOptionsAction @@ -152,8 +161,8 @@ internal static void ThrowContextableComparerNotImplemented(IDifferenceTreeNode if (HasComparisonContextImplicitRoot(comparisonContext) == false) { var message = $"Because the comparison context was explicitly passed, the {comparer.GetType().FullName} must implement {unImplementedInterface} interface " + - "or throwing the ContextableComparerNotImplementedException must be disabled."; - throw new ContextableComparerNotImplementedException(message); + "or throwing the DifferenceTreeBuilderNotImplementedException must be disabled."; + throw new DifferenceTreeBuilderNotImplementedException(message); } } } diff --git a/ObjectsComparer/ObjectsComparer/Exceptions/ContextableComparerNotImplementedException.cs b/ObjectsComparer/ObjectsComparer/Exceptions/ContextableComparerNotImplementedException.cs index 4408b9d..f1ed98e 100644 --- a/ObjectsComparer/ObjectsComparer/Exceptions/ContextableComparerNotImplementedException.cs +++ b/ObjectsComparer/ObjectsComparer/Exceptions/ContextableComparerNotImplementedException.cs @@ -1,14 +1,15 @@ using System; +using ObjectsComparer.DifferenceTreeExtensions; namespace ObjectsComparer.Exceptions { /// - /// Depending on the configuration, this exception may be thrown when a user defined comparer does not implement or . + /// Depending on the configuration or actual state of the comparison, this exception may be thrown when a user defined comparer does not implement or . /// To prevent this exception from being thrown, see operation. /// - public class ContextableComparerNotImplementedException : NotImplementedException + public class DifferenceTreeBuilderNotImplementedException : NotImplementedException { - internal ContextableComparerNotImplementedException(string message) : base(message) + internal DifferenceTreeBuilderNotImplementedException(string message) : base(message) { } } From 4afeeaf4844542f85f494bb791200bedf55a5fbd Mon Sep 17 00:00:00 2001 From: Daniel Nemec Date: Tue, 12 Apr 2022 09:31:05 +0200 Subject: [PATCH 130/181] Rename ContextableExtensions with DifferenceTreeBuilderExtensions. --- ObjectsComparer/ObjectsComparer/Comparer.cs | 2 +- ...extableExtensions.cs => DifferenceTreeBuilderExtensions.cs} | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) rename ObjectsComparer/ObjectsComparer/DifferenceTree/{ContextableExtensions.cs => DifferenceTreeBuilderExtensions.cs} (98%) diff --git a/ObjectsComparer/ObjectsComparer/Comparer.cs b/ObjectsComparer/ObjectsComparer/Comparer.cs index 88adad7..bceb46c 100644 --- a/ObjectsComparer/ObjectsComparer/Comparer.cs +++ b/ObjectsComparer/ObjectsComparer/Comparer.cs @@ -69,7 +69,7 @@ IEnumerable IDifferenceTreeBuilder.BuildDifferenceTree(Type yield break; } - ContextableExtensions.ThrowDifferenceTreeBuilderNotImplemented(comparisonContext, Settings, comparer, $"{nameof(IDifferenceTreeBuilder)}<{type.FullName}>"); + DifferenceTreeBuilderExtensions.ThrowDifferenceTreeBuilderNotImplemented(comparisonContext, Settings, comparer, $"{nameof(IDifferenceTreeBuilder)}<{type.FullName}>"); } var genericType = comparerIsIContextableComparerT ? typeof(IDifferenceTreeBuilder<>).MakeGenericType(type) : typeof(IComparer<>).MakeGenericType(type); diff --git a/ObjectsComparer/ObjectsComparer/DifferenceTree/ContextableExtensions.cs b/ObjectsComparer/ObjectsComparer/DifferenceTree/DifferenceTreeBuilderExtensions.cs similarity index 98% rename from ObjectsComparer/ObjectsComparer/DifferenceTree/ContextableExtensions.cs rename to ObjectsComparer/ObjectsComparer/DifferenceTree/DifferenceTreeBuilderExtensions.cs index 4bf507a..551f82d 100644 --- a/ObjectsComparer/ObjectsComparer/DifferenceTree/ContextableExtensions.cs +++ b/ObjectsComparer/ObjectsComparer/DifferenceTree/DifferenceTreeBuilderExtensions.cs @@ -2,11 +2,10 @@ using System; using System.Linq; using System.Collections.Generic; -using ObjectsComparer.Exceptions; namespace ObjectsComparer.DifferenceTreeExtensions { - public static class ContextableExtensions + public static class DifferenceTreeBuilderExtensions { /// /// Builds the difference tree. From af0b8392164f7eb3a445e3bb5bd23095f75ee955 Mon Sep 17 00:00:00 2001 From: Daniel Nemec Date: Tue, 12 Apr 2022 09:33:07 +0200 Subject: [PATCH 131/181] Rename ContextableComparerNotImplementedException.cs with DifferenceTreeBuilderNotImplementedException.cs. --- ...ception.cs => DifferenceTreeBuilderNotImplementedException.cs} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename ObjectsComparer/ObjectsComparer/Exceptions/{ContextableComparerNotImplementedException.cs => DifferenceTreeBuilderNotImplementedException.cs} (100%) diff --git a/ObjectsComparer/ObjectsComparer/Exceptions/ContextableComparerNotImplementedException.cs b/ObjectsComparer/ObjectsComparer/Exceptions/DifferenceTreeBuilderNotImplementedException.cs similarity index 100% rename from ObjectsComparer/ObjectsComparer/Exceptions/ContextableComparerNotImplementedException.cs rename to ObjectsComparer/ObjectsComparer/Exceptions/DifferenceTreeBuilderNotImplementedException.cs From f875e196b531553f391b44428091e626c971627b Mon Sep 17 00:00:00 2001 From: Daniel Nemec Date: Tue, 12 Apr 2022 10:03:34 +0200 Subject: [PATCH 132/181] Edit comments. --- .../DifferenceTree/DifferenceTreeBuilderExtensions.cs | 7 +++++-- .../DifferenceTree/ImplicitDifferenceTreeNode.cs | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/ObjectsComparer/ObjectsComparer/DifferenceTree/DifferenceTreeBuilderExtensions.cs b/ObjectsComparer/ObjectsComparer/DifferenceTree/DifferenceTreeBuilderExtensions.cs index 551f82d..f0e769f 100644 --- a/ObjectsComparer/ObjectsComparer/DifferenceTree/DifferenceTreeBuilderExtensions.cs +++ b/ObjectsComparer/ObjectsComparer/DifferenceTree/DifferenceTreeBuilderExtensions.cs @@ -100,7 +100,10 @@ public static IEnumerable TryBuildDifferenceTree(this ICo } } - static bool HasComparisonContextImplicitRoot(IDifferenceTreeNode comparisonContext) + /// + /// See . + /// + static bool HasDifferenceTreeImplicitRoot(IDifferenceTreeNode comparisonContext) { if (comparisonContext is null) { @@ -157,7 +160,7 @@ internal static void ThrowDifferenceTreeBuilderNotImplemented(IDifferenceTreeNod //TODO: Check DifferenceOptionsAction - if (HasComparisonContextImplicitRoot(comparisonContext) == false) + if (HasDifferenceTreeImplicitRoot(comparisonContext) == false) { var message = $"Because the comparison context was explicitly passed, the {comparer.GetType().FullName} must implement {unImplementedInterface} interface " + "or throwing the DifferenceTreeBuilderNotImplementedException must be disabled."; diff --git a/ObjectsComparer/ObjectsComparer/DifferenceTree/ImplicitDifferenceTreeNode.cs b/ObjectsComparer/ObjectsComparer/DifferenceTree/ImplicitDifferenceTreeNode.cs index 6d384dc..41e2e49 100644 --- a/ObjectsComparer/ObjectsComparer/DifferenceTree/ImplicitDifferenceTreeNode.cs +++ b/ObjectsComparer/ObjectsComparer/DifferenceTree/ImplicitDifferenceTreeNode.cs @@ -4,7 +4,7 @@ namespace ObjectsComparer { /// - /// Root comparison context for cases where the consumer does not create and pass his own root context at the beginning of the comparison. + /// The root difference tree node for cases where consumers does not explicitly, directly or indirectly request a difference tree, this means that the difference tree will only be created as an auxiliary. /// internal class ImplicitDifferenceTreeNode : DifferenceTreeNodeBase { From 79a8af4fc8621b220f588ac88959a7de59800e96 Mon Sep 17 00:00:00 2001 From: Daniel Nemec Date: Tue, 12 Apr 2022 10:08:15 +0200 Subject: [PATCH 133/181] Make CreateImplicitRootContext operation as public. --- .../DifferenceTree/ComparisonContextProvider.cs | 5 ++++- .../DifferenceTree/ImplicitDifferenceTreeNode.cs | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/ObjectsComparer/ObjectsComparer/DifferenceTree/ComparisonContextProvider.cs b/ObjectsComparer/ObjectsComparer/DifferenceTree/ComparisonContextProvider.cs index d4513e0..1f6c79a 100644 --- a/ObjectsComparer/ObjectsComparer/DifferenceTree/ComparisonContextProvider.cs +++ b/ObjectsComparer/ObjectsComparer/DifferenceTree/ComparisonContextProvider.cs @@ -10,7 +10,10 @@ public static IDifferenceTreeNode CreateRootContext() return new DifferenceTreeNode(new DifferenceTreeNodeMember()); } - internal static IDifferenceTreeNode CreateImplicitRootContext(ComparisonSettings comparisonSettings) + /// + /// Returns the root of the difference tree for cases where consumers do not explicitly, directly or indirectly request the difference tree, this means that the difference tree is created only as an auxiliary. + /// + public static IDifferenceTreeNode CreateImplicitRootContext(ComparisonSettings comparisonSettings) { _ = comparisonSettings ?? throw new ArgumentNullException(nameof(comparisonSettings)); diff --git a/ObjectsComparer/ObjectsComparer/DifferenceTree/ImplicitDifferenceTreeNode.cs b/ObjectsComparer/ObjectsComparer/DifferenceTree/ImplicitDifferenceTreeNode.cs index 41e2e49..5e7e7a6 100644 --- a/ObjectsComparer/ObjectsComparer/DifferenceTree/ImplicitDifferenceTreeNode.cs +++ b/ObjectsComparer/ObjectsComparer/DifferenceTree/ImplicitDifferenceTreeNode.cs @@ -4,7 +4,7 @@ namespace ObjectsComparer { /// - /// The root difference tree node for cases where consumers does not explicitly, directly or indirectly request a difference tree, this means that the difference tree will only be created as an auxiliary. + /// The root of the difference tree for cases where consumers do not explicitly, directly or indirectly request the difference tree, this means that the difference tree is created only as an auxiliary. /// internal class ImplicitDifferenceTreeNode : DifferenceTreeNodeBase { From e0a83f995b4c730cd7ccb9a7a3a4c2e30f1d378e Mon Sep 17 00:00:00 2001 From: Daniel Nemec Date: Tue, 12 Apr 2022 10:12:29 +0200 Subject: [PATCH 134/181] Edit comments. --- .../ObjectsComparer/DifferenceTree/ComparisonContextProvider.cs | 2 +- .../DifferenceTree/ImplicitDifferenceTreeNode.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ObjectsComparer/ObjectsComparer/DifferenceTree/ComparisonContextProvider.cs b/ObjectsComparer/ObjectsComparer/DifferenceTree/ComparisonContextProvider.cs index 1f6c79a..f164aa1 100644 --- a/ObjectsComparer/ObjectsComparer/DifferenceTree/ComparisonContextProvider.cs +++ b/ObjectsComparer/ObjectsComparer/DifferenceTree/ComparisonContextProvider.cs @@ -11,7 +11,7 @@ public static IDifferenceTreeNode CreateRootContext() } /// - /// Returns the root of the difference tree for cases where consumers do not explicitly, directly or indirectly request the difference tree, this means that the difference tree is created only as an auxiliary. + /// Returns the root of the difference tree for cases where the consumer does not explicitly, directly or indirectly request the difference tree, ie the difference tree is created only as an auxiliary. /// public static IDifferenceTreeNode CreateImplicitRootContext(ComparisonSettings comparisonSettings) { diff --git a/ObjectsComparer/ObjectsComparer/DifferenceTree/ImplicitDifferenceTreeNode.cs b/ObjectsComparer/ObjectsComparer/DifferenceTree/ImplicitDifferenceTreeNode.cs index 5e7e7a6..ae6d9c0 100644 --- a/ObjectsComparer/ObjectsComparer/DifferenceTree/ImplicitDifferenceTreeNode.cs +++ b/ObjectsComparer/ObjectsComparer/DifferenceTree/ImplicitDifferenceTreeNode.cs @@ -4,7 +4,7 @@ namespace ObjectsComparer { /// - /// The root of the difference tree for cases where consumers do not explicitly, directly or indirectly request the difference tree, this means that the difference tree is created only as an auxiliary. + /// The root of the difference tree for cases where the consumer does not explicitly, directly or indirectly request the difference tree, ie the difference tree is created only as an auxiliary. /// internal class ImplicitDifferenceTreeNode : DifferenceTreeNodeBase { From a7000fa5ddb828204c580e794e32694e41df129c Mon Sep 17 00:00:00 2001 From: Daniel Nemec Date: Fri, 15 Apr 2022 22:55:38 +0200 Subject: [PATCH 135/181] Add ComparisonContext. --- .../ComparisonContextTests.cs | 1 + .../DifferenceTree/ComparerExtensions.cs | 55 +++++++------------ .../DifferenceTree/ComparisonContext.cs | 21 +++++++ .../Utils/EnumerableExtensions.cs | 30 ++++++++++ 4 files changed, 73 insertions(+), 34 deletions(-) create mode 100644 ObjectsComparer/ObjectsComparer/DifferenceTree/ComparisonContext.cs create mode 100644 ObjectsComparer/ObjectsComparer/Utils/EnumerableExtensions.cs diff --git a/ObjectsComparer/ObjectsComparer.Tests/ComparisonContextTests.cs b/ObjectsComparer/ObjectsComparer.Tests/ComparisonContextTests.cs index e093e3d..7d1bbe5 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/ComparisonContextTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/ComparisonContextTests.cs @@ -7,6 +7,7 @@ using ObjectsComparer.Tests.Utils; using System.Reflection; using System.Diagnostics; +using ObjectsComparer.Utils; namespace ObjectsComparer.Tests { diff --git a/ObjectsComparer/ObjectsComparer/DifferenceTree/ComparerExtensions.cs b/ObjectsComparer/ObjectsComparer/DifferenceTree/ComparerExtensions.cs index 77f4da2..4a236c7 100644 --- a/ObjectsComparer/ObjectsComparer/DifferenceTree/ComparerExtensions.cs +++ b/ObjectsComparer/ObjectsComparer/DifferenceTree/ComparerExtensions.cs @@ -1,16 +1,21 @@ using ObjectsComparer.DifferenceTreeExtensions; using ObjectsComparer.Exceptions; +using ObjectsComparer.Utils; using System; using System.Collections.Generic; namespace ObjectsComparer { + public static class ComparerExtensions { /// - /// XXX + /// Calculates the difference tree. /// - public static IDifferenceTreeNode CalculateDifferenceTree(this IComparer comparer, Type type, object obj1, object obj2, Func findNextDifference = null, Action contextCompleted = null) + /// Current comparison context. The return value tells whether to look for another difference. If the argument is null the process is looking for all the differences. + /// If the comparison process has been completed, this action will be invoked. + /// The root node of the difference tree. + public static IDifferenceTreeNode CalculateDifferenceTree(this IComparer comparer, Type type, object obj1, object obj2, Func findNextDifference = null, Action contextCompleted = null) { if (comparer is null) { @@ -30,19 +35,22 @@ public static IDifferenceTreeNode CalculateDifferenceTree(this IComparer compare var differenceLocationList = comparer.TryBuildDifferenceTree(type, obj1, obj2, rootNode); differenceLocationList.EnumerateConditional( - currentLocation => + currentLocation => { - return findNextDifference(currentLocation); - }, + return findNextDifference(new ComparisonContext(rootNode, currentLocation.Difference, currentLocation.TreeNode)); + }, contextCompleted); return rootNode; } /// - /// XXX + /// Calculates the difference tree. /// - public static IDifferenceTreeNode CalculateDifferenceTree(this IComparer comparer, T obj1, T obj2, Func findNextDifference = null, Action contextCompleted = null) + /// Current comparison context. The return value tells whether to look for another difference. + /// If the comparison process has been completed, this action will be invoked. + /// The root node of the difference tree. + public static IDifferenceTreeNode CalculateDifferenceTree(this IComparer comparer, T obj1, T obj2, Func findNextDifference = null, Action contextCompleted = null) { if (comparer is null) { @@ -51,40 +59,19 @@ public static IDifferenceTreeNode CalculateDifferenceTree(this IComparer c findNextDifference = findNextDifference ?? ((_) => true); - var rootCtx = ComparisonContextProvider.CreateContext(comparer.Settings, ancestor: null); + var rootNode = ComparisonContextProvider.CreateContext(comparer.Settings, ancestor: null); - var differenceLocationList = comparer.TryBuildDifferenceTree(obj1, obj2, rootCtx); + var differenceLocationList = comparer.TryBuildDifferenceTree(obj1, obj2, rootNode); differenceLocationList.EnumerateConditional( currentLocation => { - return findNextDifference(currentLocation); + return findNextDifference(new ComparisonContext(rootNode, currentLocation.Difference, currentLocation.TreeNode)); }, contextCompleted); - return rootCtx; - } - - internal static void EnumerateConditional(this IEnumerable enumerable, Func findNextElement = null, Action enumerationCompleted = null) - { - _ = enumerable ?? throw new ArgumentNullException(nameof(enumerable)); - - var enumerator = enumerable.GetEnumerator(); - var enumerationTerminated = false; - - while (enumerator.MoveNext()) - { - if (findNextElement?.Invoke(enumerator.Current) == false) - { - enumerationTerminated = true; - break; - } - } - - if (enumerationTerminated == false) - { - enumerationCompleted?.Invoke(); - } + return rootNode; } } -} \ No newline at end of file +} + diff --git a/ObjectsComparer/ObjectsComparer/DifferenceTree/ComparisonContext.cs b/ObjectsComparer/ObjectsComparer/DifferenceTree/ComparisonContext.cs new file mode 100644 index 0000000..a2b536c --- /dev/null +++ b/ObjectsComparer/ObjectsComparer/DifferenceTree/ComparisonContext.cs @@ -0,0 +1,21 @@ +using System; + +namespace ObjectsComparer +{ + public class ComparisonContext + { + public IDifferenceTreeNode RootNode { get; } + + public Difference CurrentDifference { get; } + + public IDifferenceTreeNode CurrentNode { get; } + + public ComparisonContext(IDifferenceTreeNode rootNode, Difference currentDifference, IDifferenceTreeNode currentNode = null) + { + RootNode = rootNode ?? throw new ArgumentNullException(nameof(rootNode)); + CurrentDifference = currentDifference ?? throw new ArgumentNullException(nameof(currentDifference)); + CurrentNode = currentNode ?? throw new ArgumentNullException(nameof(currentNode)); + } + } +} + diff --git a/ObjectsComparer/ObjectsComparer/Utils/EnumerableExtensions.cs b/ObjectsComparer/ObjectsComparer/Utils/EnumerableExtensions.cs new file mode 100644 index 0000000..6b51ead --- /dev/null +++ b/ObjectsComparer/ObjectsComparer/Utils/EnumerableExtensions.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; + +namespace ObjectsComparer.Utils +{ + internal static class EnumerableExtensions + { + internal static void EnumerateConditional(this IEnumerable enumerable, Func findNextElement = null, Action enumerationCompleted = null) + { + _ = enumerable ?? throw new ArgumentNullException(nameof(enumerable)); + + var enumerator = enumerable.GetEnumerator(); + var enumerationTerminated = false; + + while (enumerator.MoveNext()) + { + if (findNextElement?.Invoke(enumerator.Current) == false) + { + enumerationTerminated = true; + break; + } + } + + if (enumerationTerminated == false) + { + enumerationCompleted?.Invoke(); + } + } + } +} \ No newline at end of file From 120b5137fbf591d6415fe887ef535408ab795834 Mon Sep 17 00:00:00 2001 From: Daniel Nemec Date: Fri, 15 Apr 2022 23:17:52 +0200 Subject: [PATCH 136/181] Edit comments. --- .../DifferenceTreeBuilderExtensions.cs | 12 ++++++------ .../DifferenceTree/IDifferenceTreeBuilder.cs | 5 +++-- .../DifferenceTree/IDifferenceTreeBuilder~1.cs | 5 +++-- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/ObjectsComparer/ObjectsComparer/DifferenceTree/DifferenceTreeBuilderExtensions.cs b/ObjectsComparer/ObjectsComparer/DifferenceTree/DifferenceTreeBuilderExtensions.cs index f0e769f..fa85fdc 100644 --- a/ObjectsComparer/ObjectsComparer/DifferenceTree/DifferenceTreeBuilderExtensions.cs +++ b/ObjectsComparer/ObjectsComparer/DifferenceTree/DifferenceTreeBuilderExtensions.cs @@ -8,15 +8,15 @@ namespace ObjectsComparer.DifferenceTreeExtensions public static class DifferenceTreeBuilderExtensions { /// - /// Builds the difference tree. + /// If possible, creates a difference tree. /// /// /// If is , it looks for the difference, adds it to the difference tree and returns it, including its location. /// If not, it only looks for the difference and returns it with empty location.
- /// It throws exception if necessary.
+ /// It throws exception if necessary.
/// Intended for implementers. To avoid side effects, consumers should call extension method instead. ///
- /// The difference with its eventual location in the difference tree. + /// The differences with its eventual location in the difference tree. public static IEnumerable TryBuildDifferenceTree(this IComparer comparer, Type type, object obj1, object obj2, IDifferenceTreeNode currentNode) { if (comparer is null) @@ -57,15 +57,15 @@ public static IEnumerable TryBuildDifferenceTree(this ICompa } /// - /// Builds the difference tree.
+ /// If possible, creates a difference tree. ///
/// /// If is , it looks for the difference, adds it to the difference tree and returns it, including its location. /// If not, it only looks for the difference and returns it with empty location.
- /// It throws exception if necessary.
+ /// It throws exception if necessary.
/// Intended for implementers. To avoid side effects, consumers should call extension method instead. ///
- /// The difference with its eventual location in the difference tree. + /// The differences with its eventual location in the difference tree. public static IEnumerable TryBuildDifferenceTree(this IComparer comparer, T obj1, T obj2, IDifferenceTreeNode comparisonContext) { if (comparer is null) diff --git a/ObjectsComparer/ObjectsComparer/DifferenceTree/IDifferenceTreeBuilder.cs b/ObjectsComparer/ObjectsComparer/DifferenceTree/IDifferenceTreeBuilder.cs index a55f8d2..5bfd76b 100644 --- a/ObjectsComparer/ObjectsComparer/DifferenceTree/IDifferenceTreeBuilder.cs +++ b/ObjectsComparer/ObjectsComparer/DifferenceTree/IDifferenceTreeBuilder.cs @@ -12,7 +12,8 @@ public interface IDifferenceTreeBuilder /// Finds the difference, adds it to the difference tree and returns it, including its location. ///
/// Intended for implementers. To avoid side effects, consumers should call extension method instead. - /// The location of the difference in the difference tree. - IEnumerable BuildDifferenceTree(Type type, object obj1, object obj2, IDifferenceTreeNode comparisonContext); + /// The starting point in the tree from which the differences should be built. + /// The list of the differences and their location in the difference tree. + IEnumerable BuildDifferenceTree(Type type, object obj1, object obj2, IDifferenceTreeNode differenceTreeNode); } } \ No newline at end of file diff --git a/ObjectsComparer/ObjectsComparer/DifferenceTree/IDifferenceTreeBuilder~1.cs b/ObjectsComparer/ObjectsComparer/DifferenceTree/IDifferenceTreeBuilder~1.cs index 83ed967..61f5da9 100644 --- a/ObjectsComparer/ObjectsComparer/DifferenceTree/IDifferenceTreeBuilder~1.cs +++ b/ObjectsComparer/ObjectsComparer/DifferenceTree/IDifferenceTreeBuilder~1.cs @@ -12,7 +12,8 @@ public interface IDifferenceTreeBuilder /// Finds the difference, adds it to the difference tree and returns it, including its location. ///
/// Intended for implementers. To avoid side effects, consumers should call extension method instead. - /// The location of the difference in the difference tree. - IEnumerable BuildDifferenceTree(T obj1, T obj2, IDifferenceTreeNode comparisonContext); + /// The starting point in the tree from which the differences should be built. + /// The list of the differences and their location in the difference tree. + IEnumerable BuildDifferenceTree(T obj1, T obj2, IDifferenceTreeNode differenceTreeNode); } } From b9de5425921c8f654a4344072fe705b963c6609b Mon Sep 17 00:00:00 2001 From: Daniel Nemec Date: Sat, 16 Apr 2022 23:00:17 +0200 Subject: [PATCH 137/181] Replace all occurences of the "comparison context" with "difference tree node". --- .../Example4/Example4Tests.cs | 2 +- .../Example4Tests_BuiltInKeyComparison.cs | 2 +- .../Comparer_CompilerGeneratedObjectsTests.cs | 4 +- .../Comparer_ExpandoObjectsTests.cs | 6 +- .../Comparer_MultidimensionalArraysTests.cs | 2 +- .../ComparisonSettingsTests.cs | 6 +- ...extTests.cs => DifferenceTreeNodeTests.cs} | 59 ++++++------- ...ferenceTreeNodeSerializationExtensions.cs} | 18 ++-- .../ObjectsComparer/BaseComparer.cs | 12 +-- ObjectsComparer/ObjectsComparer/Comparer.cs | 28 +++---- ObjectsComparer/ObjectsComparer/Comparer~1.cs | 20 ++--- .../ObjectsComparer/ComparisonSettings.cs | 13 ++- .../AbstractDynamicObjectsComprer.cs | 24 +++--- .../AbstractEnumerablesComparer.cs | 2 +- .../CustomComparers/EnumerablesComparer.cs | 18 ++-- .../EnumerablesComparerBase.cs | 44 +++++----- .../CustomComparers/EnumerablesComparer~1.cs | 18 ++-- .../GenericEnumerablesComparer.cs | 6 +- .../CustomComparers/HashSetsComparer.cs | 6 +- .../CustomComparers/HashSetsComparer~1.cs | 16 ++-- .../MultidimensionalArrayComparer~1.cs | 18 ++-- .../MultidimensionalArraysComparer.cs | 6 +- .../CustomComparers/TypesComparer.cs | 10 +-- .../DifferenceTree/ComparerExtensions.cs | 16 ++-- .../DifferenceTree/ComparisonContext.cs | 5 +- .../ComparisonContextOptions.cs | 52 ------------ .../ComparisonContextProvider.cs | 82 ------------------- .../DifferenceTreeBuilderExtensions.cs | 52 ++++++------ .../DifferenceTree/DifferenceTreeNodeBase.cs | 8 +- .../DifferenceTreeNodeProvider.cs | 82 +++++++++++++++++++ .../DifferenceTree/DifferenceTreeOptions.cs | 52 ++++++++++++ .../DifferenceTree/IDifferenceTreeNode.cs | 20 ++--- ...renceTreeBuilderNotImplementedException.cs | 2 +- .../Exceptions/ElementKeyNotFoundException.cs | 6 +- 34 files changed, 359 insertions(+), 358 deletions(-) rename ObjectsComparer/ObjectsComparer.Tests/{ComparisonContextTests.cs => DifferenceTreeNodeTests.cs} (68%) rename ObjectsComparer/ObjectsComparer.Tests/Utils/{ComparisonContextSerializationExtensions.cs => DifferenceTreeNodeSerializationExtensions.cs} (83%) delete mode 100644 ObjectsComparer/ObjectsComparer/DifferenceTree/ComparisonContextOptions.cs delete mode 100644 ObjectsComparer/ObjectsComparer/DifferenceTree/ComparisonContextProvider.cs create mode 100644 ObjectsComparer/ObjectsComparer/DifferenceTree/DifferenceTreeNodeProvider.cs create mode 100644 ObjectsComparer/ObjectsComparer/DifferenceTree/DifferenceTreeOptions.cs diff --git a/ObjectsComparer/ObjectsComparer.Examples/Example4/Example4Tests.cs b/ObjectsComparer/ObjectsComparer.Examples/Example4/Example4Tests.cs index b392af5..28125f4 100644 --- a/ObjectsComparer/ObjectsComparer.Examples/Example4/Example4Tests.cs +++ b/ObjectsComparer/ObjectsComparer.Examples/Example4/Example4Tests.cs @@ -67,7 +67,7 @@ public void List_Of_Equal_Sizes_But_Is_Inequality() } [Test] - public void CalculateDifferenceTree_Throw_ContextableComparerNotImplemented() + public void CalculateDifferenceTree_Throw_DifferenceBuilderNotImplemented() { var formula1 = new Formula { diff --git a/ObjectsComparer/ObjectsComparer.Examples/Example4/Example4Tests_BuiltInKeyComparison.cs b/ObjectsComparer/ObjectsComparer.Examples/Example4/Example4Tests_BuiltInKeyComparison.cs index 0e418e5..4e3bb23 100644 --- a/ObjectsComparer/ObjectsComparer.Examples/Example4/Example4Tests_BuiltInKeyComparison.cs +++ b/ObjectsComparer/ObjectsComparer.Examples/Example4/Example4Tests_BuiltInKeyComparison.cs @@ -240,7 +240,7 @@ public void List_Of_Different_Sizes_But_Is_Inequality_FormatKey() } [Test] - public void List_Of_Different_Sizes_But_Is_Inequality_FormatKey_CheckComparisonContext() + public void List_Of_Different_Sizes_But_Is_Inequality_FormatKey_CheckDifferenceTreeNode() { var formula1 = new Formula { diff --git a/ObjectsComparer/ObjectsComparer.Tests/Comparer_CompilerGeneratedObjectsTests.cs b/ObjectsComparer/ObjectsComparer.Tests/Comparer_CompilerGeneratedObjectsTests.cs index 3c4b8ad..1f18800 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/Comparer_CompilerGeneratedObjectsTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/Comparer_CompilerGeneratedObjectsTests.cs @@ -62,7 +62,7 @@ public void MissedFields() } [Test] - public void MissedFields_CheckComparisonContext() + public void MissedFields_CheckDifferenceTreeNode() { dynamic a1 = new { @@ -200,7 +200,7 @@ public void NullAndMissedMemberAreNotEqual() } [Test] - public void NullAndMissedMemberAreNotEqual_CheckComparisonContext() + public void NullAndMissedMemberAreNotEqual_CheckDifferenceTreeNode() { dynamic a1 = new { diff --git a/ObjectsComparer/ObjectsComparer.Tests/Comparer_ExpandoObjectsTests.cs b/ObjectsComparer/ObjectsComparer.Tests/Comparer_ExpandoObjectsTests.cs index 032a1dc..c47b696 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/Comparer_ExpandoObjectsTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/Comparer_ExpandoObjectsTests.cs @@ -101,7 +101,7 @@ public void Hierarchy() } [Test] - public void Hierarchy_CheckComparisonContext() + public void Hierarchy_CheckDifferenceTreeNode() { dynamic a1Sub1 = new ExpandoObject(); a1Sub1.Field1 = 10; @@ -283,7 +283,7 @@ public void UseDefaultValuesWhenSubclassNotSpecified() } [Test] - public void UseDefaultValuesWhenSubclassNotSpecified_CheckComparisonContext() + public void UseDefaultValuesWhenSubclassNotSpecified_CheckDifferenceTreeNode() { dynamic a1 = new ExpandoObject(); a1.Field1 = new ExpandoObject(); @@ -324,7 +324,7 @@ public void DifferenceWhenSubclassNotSpecified() } [Test] - public void DifferenceWhenSubclassNotSpecified_CheckComparisonContext() + public void DifferenceWhenSubclassNotSpecified_CheckDifferenceTreeNode() { dynamic a1 = new ExpandoObject(); a1.Field1 = new ExpandoObject(); diff --git a/ObjectsComparer/ObjectsComparer.Tests/Comparer_MultidimensionalArraysTests.cs b/ObjectsComparer/ObjectsComparer.Tests/Comparer_MultidimensionalArraysTests.cs index 93d85c9..e553d8a 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/Comparer_MultidimensionalArraysTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/Comparer_MultidimensionalArraysTests.cs @@ -406,7 +406,7 @@ public void IntIntInequality7() } [Test] - public void IntIntInequality7_CheckComparisonContext() + public void IntIntInequality7_CheckDifferenceTreeNode() { var a1 = new MultidimensionalArrays { IntInt = new int[0, 0] }; var a2 = new MultidimensionalArrays { IntInt = null }; diff --git a/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs b/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs index 6cc3622..302f4fe 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs @@ -9,8 +9,6 @@ namespace ObjectsComparer.Tests { - //NullAndMissedMemberAreNotEqual_CheckComparisonContext - [TestFixture] public class ComparisonSettingsTests { @@ -66,7 +64,7 @@ public void CompareListElementsByKeyIsCorrectlySet() //Client side. var settings = new ComparisonSettings(); - settings.ConfigureListComparison((curentContext, listOptions) => + settings.ConfigureListComparison((curentNode, listOptions) => { listOptions.CompareUnequalLists(true); @@ -76,7 +74,7 @@ public void CompareListElementsByKeyIsCorrectlySet() keyOptions.ThrowKeyNotFound(false); }); - var currentMember = curentContext.Member; + var currentMember = curentNode.Member; }); //Component side. diff --git a/ObjectsComparer/ObjectsComparer.Tests/ComparisonContextTests.cs b/ObjectsComparer/ObjectsComparer.Tests/DifferenceTreeNodeTests.cs similarity index 68% rename from ObjectsComparer/ObjectsComparer.Tests/ComparisonContextTests.cs rename to ObjectsComparer/ObjectsComparer.Tests/DifferenceTreeNodeTests.cs index 7d1bbe5..1ef1d07 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/ComparisonContextTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/DifferenceTreeNodeTests.cs @@ -8,14 +8,16 @@ using System.Reflection; using System.Diagnostics; using ObjectsComparer.Utils; +using ObjectsComparer.DifferenceTreeExtensions; +using ObjectsComparer.Exceptions; namespace ObjectsComparer.Tests { [TestFixture] - internal class ComparisonContextTests + internal class DifferenceTreeNodeTests { [Test] - public void ComparisonContextMember_Member_Correct_MemberName() + public void DifferenceTreeNodeMember_Member_Correct_MemberName() { var ctxMember = new DifferenceTreeNodeMember(name: "Property1"); Assert.AreEqual("Property1", ctxMember.Name); @@ -23,7 +25,7 @@ public void ComparisonContextMember_Member_Correct_MemberName() } [Test] - public void ComparisonContextMember_Member_Correct_Member() + public void DifferenceTreeNodeMember_Member_Correct_Member() { var memberInfo = typeof(Address).GetMember(nameof(Address.Country)).Single(); var ctxMember = new DifferenceTreeNodeMember(memberInfo, memberInfo.Name); @@ -32,51 +34,50 @@ public void ComparisonContextMember_Member_Correct_Member() } [Test] - public void CustomComparisonContext() + public void CustomDifferenceTreeNode() { var settings = new ComparisonSettings(); - var rootCtx = ComparisonContextProvider.CreateRootContext(); + var rootNode = DifferenceTreeNodeProvider.CreateRootNode(); - settings.ConfigureComparisonContext((currentContex, options) => + settings.ConfigureDifferenceTree((currentNode, options) => { - options.UseComparisonContextFactory(ctxMember => new CustomComparisonContext(ctxMember, rootCtx)); + options.UseDifferenceTreeNodeFactory(ctxMember => new CustomDifferenceTreeNode(ctxMember, rootNode)); }); - var ctx = ComparisonContextProvider.CreateContext(settings, rootCtx, "Property1"); + var ctx = DifferenceTreeNodeProvider.CreateNode(settings, rootNode, "Property1"); Assert.AreEqual("Property1", ctx.Member.Name); - Assert.IsTrue(ctx.GetType() == typeof(CustomComparisonContext)); - Assert.IsTrue(ctx.Ancestor == rootCtx); + Assert.IsTrue(ctx.GetType() == typeof(CustomDifferenceTreeNode)); + Assert.IsTrue(ctx.Ancestor == rootNode); } [Test] - public void CustomComparisonContextMember() + public void CustomDifferenceTreeNodeMember() { var settings = new ComparisonSettings(); - var rootCtx = ComparisonContextProvider.CreateRootContext(); + var rootCtx = DifferenceTreeNodeProvider.CreateRootNode(); - settings.ConfigureComparisonContext((currentContex, options) => + settings.ConfigureDifferenceTree((currentContex, options) => { - options.UseComparisonContextMemberFactory(defaultMember => new CustomComparisonContextMember(defaultMember.Name)); + options.UseDifferenceTreeNodeMemberFactory(defaultMember => new CustomDifferenceTreeNodeMember(defaultMember.Name)); }); - var ctx = ComparisonContextProvider.CreateContext(settings, rootCtx, "Property1"); + var ctx = DifferenceTreeNodeProvider.CreateNode(settings, rootCtx, "Property1"); Assert.AreEqual("Property1", ctx.Member.Name); Assert.AreEqual(null, ctx.Member.Info); - Assert.IsTrue(ctx.Member.GetType() == typeof(CustomComparisonContextMember)); + Assert.IsTrue(ctx.Member.GetType() == typeof(CustomDifferenceTreeNodeMember)); Assert.IsTrue(ctx.Ancestor == rootCtx); } - //[Test] - //public void ComparisonContextException() - //{ - // var factory = new CustomComparersFactory(); - // var comparer = factory.GetObjectsComparer(); - // var rootCtx = ComparisonContextProvider.CreateRootContext(); - - // var diffs = comparer.TryBuildDifferenceTree("hello", "hi", rootCtx).ToArray(); - //} + [Test] + public void TestThrowDifferenceTreeBuilderNotImplementedException() + { + var factory = new CustomComparersFactory(); + var comparer = factory.GetObjectsComparer(); + var rootCtx = DifferenceTreeNodeProvider.CreateRootNode(); + Assert.Throws(() => comparer.TryBuildDifferenceTree("hello", "hi", rootCtx).ToArray()); + } [Test] public void EnumerateConditional() @@ -176,17 +177,17 @@ public override IEnumerable CalculateDifferences(string obj1, string } } - class CustomComparisonContext : DifferenceTreeNodeBase + class CustomDifferenceTreeNode : DifferenceTreeNodeBase { - public CustomComparisonContext(IDifferenceTreeNodeMember member = null, IDifferenceTreeNode ancestor = null) : base(member, ancestor) + public CustomDifferenceTreeNode(IDifferenceTreeNodeMember member = null, IDifferenceTreeNode ancestor = null) : base(member, ancestor) { } } - class CustomComparisonContextMember : IDifferenceTreeNodeMember + class CustomDifferenceTreeNodeMember : IDifferenceTreeNodeMember { - public CustomComparisonContextMember(string memberName) + public CustomDifferenceTreeNodeMember(string memberName) { Name = memberName; } diff --git a/ObjectsComparer/ObjectsComparer.Tests/Utils/ComparisonContextSerializationExtensions.cs b/ObjectsComparer/ObjectsComparer.Tests/Utils/DifferenceTreeNodeSerializationExtensions.cs similarity index 83% rename from ObjectsComparer/ObjectsComparer.Tests/Utils/ComparisonContextSerializationExtensions.cs rename to ObjectsComparer/ObjectsComparer.Tests/Utils/DifferenceTreeNodeSerializationExtensions.cs index 30966bb..2e296a7 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/Utils/ComparisonContextSerializationExtensions.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/Utils/DifferenceTreeNodeSerializationExtensions.cs @@ -11,31 +11,31 @@ namespace ObjectsComparer.Tests.Utils { //TODO: Move ToJson to Core. - internal static class ComparisonContextSerializationExtensions + internal static class DifferenceTreeNodeSerializationExtensions { /// /// Serializes object to json string. /// - /// + /// /// /// /// - public static string ToJson(this DifferenceTreeNode comparisonContext, bool skipEmptyList = true, bool skipNullReference = true) + public static string ToJson(this DifferenceTreeNode differenceTreeNode, bool skipEmptyList = true, bool skipNullReference = true) { - return SerializeComparisonContext(comparisonContext, skipEmptyList, skipNullReference); + return SerializeDifferenceTreeNode(differenceTreeNode, skipEmptyList, skipNullReference); } - static string SerializeComparisonContext(DifferenceTreeNode context, bool skipEmptyList, bool skipNullReference) + static string SerializeDifferenceTreeNode(DifferenceTreeNode node, bool skipEmptyList, bool skipNullReference) { var settings = new JsonSerializerSettings() { - ContractResolver = new ComparisonContextContractResolver(skipEmptyList, skipNullReference), + ContractResolver = new DifferenceTreeNodeContractResolver(skipEmptyList, skipNullReference), ReferenceLoopHandling = ReferenceLoopHandling.Ignore, }; settings.Converters.Add(new StringEnumConverter { CamelCaseText = false }); settings.Converters.Add(new MemberInfoConverter()); - return JsonConvert.SerializeObject(context, Formatting.Indented, settings); + return JsonConvert.SerializeObject(node, Formatting.Indented, settings); } /// @@ -61,12 +61,12 @@ public override MemberInfo ReadJson(JsonReader reader, Type objectType, MemberIn public override bool CanRead => false; } - class ComparisonContextContractResolver : DefaultContractResolver + class DifferenceTreeNodeContractResolver : DefaultContractResolver { readonly bool _skipEmptyList; readonly bool _skipNullReference; - public ComparisonContextContractResolver(bool skipEmptyList = true, bool skipNullReference = true) + public DifferenceTreeNodeContractResolver(bool skipEmptyList = true, bool skipNullReference = true) { _skipEmptyList = skipEmptyList; _skipNullReference = skipNullReference; diff --git a/ObjectsComparer/ObjectsComparer/BaseComparer.cs b/ObjectsComparer/ObjectsComparer/BaseComparer.cs index 211af86..5710370 100644 --- a/ObjectsComparer/ObjectsComparer/BaseComparer.cs +++ b/ObjectsComparer/ObjectsComparer/BaseComparer.cs @@ -186,24 +186,24 @@ public void IgnoreMember(Func filter) } /// - /// Adds an to the end of the 's . + /// Adds an to the end of the 's . /// /// The instance. - protected virtual DifferenceLocation AddDifferenceToTree(Difference difference, IDifferenceTreeNode comparisonContext) + protected virtual DifferenceLocation AddDifferenceToTree(Difference difference, IDifferenceTreeNode differenceTreeNode) { if (difference is null) { throw new ArgumentNullException(nameof(difference)); } - if (comparisonContext is null) + if (differenceTreeNode is null) { - throw new ArgumentNullException(nameof(comparisonContext)); + throw new ArgumentNullException(nameof(differenceTreeNode)); } - comparisonContext.AddDifference(difference); + differenceTreeNode.AddDifference(difference); - return new DifferenceLocation(difference, comparisonContext); + return new DifferenceLocation(difference, differenceTreeNode); } } } \ No newline at end of file diff --git a/ObjectsComparer/ObjectsComparer/Comparer.cs b/ObjectsComparer/ObjectsComparer/Comparer.cs index bceb46c..231d6a2 100644 --- a/ObjectsComparer/ObjectsComparer/Comparer.cs +++ b/ObjectsComparer/ObjectsComparer/Comparer.cs @@ -35,31 +35,31 @@ public Comparer(ComparisonSettings settings = null, BaseComparer parentComparer public override IEnumerable CalculateDifferences(Type type, object obj1, object obj2) { - return AsContextableComparer().BuildDifferenceTree(type, obj1, obj2, ComparisonContextProvider.CreateImplicitRootContext(Settings)) + return AsDifferenceTreeBuilder().BuildDifferenceTree(type, obj1, obj2, DifferenceTreeNodeProvider.CreateImplicitRootNode(Settings)) .Select(differenceLoccation => differenceLoccation.Difference); } - IDifferenceTreeBuilder AsContextableComparer() => this; + IDifferenceTreeBuilder AsDifferenceTreeBuilder() => this; - IEnumerable IDifferenceTreeBuilder.BuildDifferenceTree(Type type, object obj1, object obj2, IDifferenceTreeNode comparisonContext) + IEnumerable IDifferenceTreeBuilder.BuildDifferenceTree(Type type, object obj1, object obj2, IDifferenceTreeNode differenceTreeNode) { - if (comparisonContext is null) + if (differenceTreeNode is null) { - throw new ArgumentNullException(nameof(comparisonContext)); + throw new ArgumentNullException(nameof(differenceTreeNode)); } var getObjectsComparerMethod = typeof(IComparersFactory).GetTypeInfo().GetMethods().First(m => m.IsGenericMethod); var getObjectsComparerGenericMethod = getObjectsComparerMethod.MakeGenericMethod(type); var comparer = getObjectsComparerGenericMethod.Invoke(Factory, new object[] { Settings, this }); - bool comparerIsIContextableComparerT = comparer.GetType().GetTypeInfo().GetInterfaces() + bool comparerIsDifferenceTreeBuilderT = comparer.GetType().GetTypeInfo().GetInterfaces() .Any(intft => intft.GetTypeInfo().IsGenericType && intft.GetGenericTypeDefinition() == typeof(IDifferenceTreeBuilder<>)); - if (comparerIsIContextableComparerT == false) + if (comparerIsDifferenceTreeBuilderT == false) { - if (comparer is IDifferenceTreeBuilder contextableComparer) + if (comparer is IDifferenceTreeBuilder differenceTreeBuilder) { - var diffLocationList = contextableComparer.BuildDifferenceTree(type, obj1, obj2, comparisonContext); + var diffLocationList = differenceTreeBuilder.BuildDifferenceTree(type, obj1, obj2, differenceTreeNode); foreach (var diffLocation in diffLocationList) { @@ -69,14 +69,14 @@ IEnumerable IDifferenceTreeBuilder.BuildDifferenceTree(Type yield break; } - DifferenceTreeBuilderExtensions.ThrowDifferenceTreeBuilderNotImplemented(comparisonContext, Settings, comparer, $"{nameof(IDifferenceTreeBuilder)}<{type.FullName}>"); + DifferenceTreeBuilderExtensions.ThrowDifferenceTreeBuilderNotImplemented(differenceTreeNode, Settings, comparer, $"{nameof(IDifferenceTreeBuilder)}<{type.FullName}>"); } - var genericType = comparerIsIContextableComparerT ? typeof(IDifferenceTreeBuilder<>).MakeGenericType(type) : typeof(IComparer<>).MakeGenericType(type); - var genericMethodName = comparerIsIContextableComparerT ? BuildDifferenceTreeMethodName : CalculateDifferencesMethodName; - var genericMethodParameterTypes = comparerIsIContextableComparerT ? new[] { type, type, typeof(IDifferenceTreeNode) } : new[] { type, type }; + var genericType = comparerIsDifferenceTreeBuilderT ? typeof(IDifferenceTreeBuilder<>).MakeGenericType(type) : typeof(IComparer<>).MakeGenericType(type); + var genericMethodName = comparerIsDifferenceTreeBuilderT ? BuildDifferenceTreeMethodName : CalculateDifferencesMethodName; + var genericMethodParameterTypes = comparerIsDifferenceTreeBuilderT ? new[] { type, type, typeof(IDifferenceTreeNode) } : new[] { type, type }; var genericMethod = genericType.GetTypeInfo().GetMethod(genericMethodName, genericMethodParameterTypes); - var genericMethodParameters = comparerIsIContextableComparerT ? new[] { obj1, obj2, comparisonContext } : new[] { obj1, obj2 }; + var genericMethodParameters = comparerIsDifferenceTreeBuilderT ? new[] { obj1, obj2, differenceTreeNode } : new[] { obj1, obj2 }; // ReSharper disable once PossibleNullReferenceException //return (IEnumerable)genericMethod.Invoke(comparer, genericMethodParameters); diff --git a/ObjectsComparer/ObjectsComparer/Comparer~1.cs b/ObjectsComparer/ObjectsComparer/Comparer~1.cs index 263ea60..4e5d0e6 100644 --- a/ObjectsComparer/ObjectsComparer/Comparer~1.cs +++ b/ObjectsComparer/ObjectsComparer/Comparer~1.cs @@ -57,18 +57,18 @@ public override IEnumerable CalculateDifferences(T obj1, T obj2) return CalculateDifferences(obj1, obj2, memberInfo: null); } - IEnumerable IDifferenceTreeBuilder.BuildDifferenceTree(T obj1, T obj2, IDifferenceTreeNode comparisonContext) + IEnumerable IDifferenceTreeBuilder.BuildDifferenceTree(T obj1, T obj2, IDifferenceTreeNode differenceTreeNode) { - return BuildDifferenceTree(obj1, obj2, memberInfo: null, comparisonContext); + return BuildDifferenceTree(obj1, obj2, memberInfo: null, differenceTreeNode); } internal IEnumerable CalculateDifferences(T obj1, T obj2, MemberInfo memberInfo) { - return BuildDifferenceTree(obj1, obj2, memberInfo, ComparisonContextProvider.CreateImplicitRootContext(Settings)) + return BuildDifferenceTree(obj1, obj2, memberInfo, DifferenceTreeNodeProvider.CreateImplicitRootNode(Settings)) .Select(differenceLocation => differenceLocation.Difference); } - IEnumerable BuildDifferenceTree(T obj1, T obj2, MemberInfo memberInfo, IDifferenceTreeNode comparisonContext) + IEnumerable BuildDifferenceTree(T obj1, T obj2, MemberInfo memberInfo, IDifferenceTreeNode differenceTreeNode) { var comparer = memberInfo != null ? OverridesCollection.GetComparer(memberInfo) @@ -80,7 +80,7 @@ IEnumerable BuildDifferenceTree(T obj1, T obj2, MemberInfo m comparer = comparer ?? DefaultValueComparer; if (!comparer.Compare(obj1, obj2, Settings)) { - yield return AddDifferenceToTree(new Difference(string.Empty, comparer.ToString(obj1), comparer.ToString(obj2)), comparisonContext); + yield return AddDifferenceToTree(new Difference(string.Empty, comparer.ToString(obj1), comparer.ToString(obj2)), differenceTreeNode); } yield break; @@ -89,7 +89,7 @@ IEnumerable BuildDifferenceTree(T obj1, T obj2, MemberInfo m var conditionalComparer = _conditionalComparers.FirstOrDefault(c => c.IsMatch(typeof(T), obj1, obj2)); if (conditionalComparer != null) { - foreach (var difference in conditionalComparer.TryBuildDifferenceTree(typeof(T), obj1, obj2, comparisonContext)) + foreach (var difference in conditionalComparer.TryBuildDifferenceTree(typeof(T), obj1, obj2, differenceTreeNode)) { yield return difference; } @@ -104,7 +104,7 @@ IEnumerable BuildDifferenceTree(T obj1, T obj2, MemberInfo m { if (!DefaultValueComparer.Compare(obj1, obj2, Settings)) { - yield return AddDifferenceToTree(new Difference(string.Empty, DefaultValueComparer.ToString(obj1), DefaultValueComparer.ToString(obj2)), comparisonContext); + yield return AddDifferenceToTree(new Difference(string.Empty, DefaultValueComparer.ToString(obj1), DefaultValueComparer.ToString(obj2)), differenceTreeNode); } yield break; @@ -126,7 +126,7 @@ IEnumerable BuildDifferenceTree(T obj1, T obj2, MemberInfo m continue; } - var memberContext = ComparisonContextProvider.CreateContext(Settings, comparisonContext, member); + var memberNode = DifferenceTreeNodeProvider.CreateNode(Settings, differenceTreeNode, member); var valueComparer = DefaultValueComparer; var hasCustomComparer = false; @@ -143,7 +143,7 @@ IEnumerable BuildDifferenceTree(T obj1, T obj2, MemberInfo m { var objectDataComparer = Factory.GetObjectsComparer(type, Settings, this); - foreach (var failure in objectDataComparer.TryBuildDifferenceTree(type, value1, value2, memberContext)) + foreach (var failure in objectDataComparer.TryBuildDifferenceTree(type, value1, value2, memberNode)) { failure.Difference.InsertPath(member.Name); yield return failure; @@ -154,7 +154,7 @@ IEnumerable BuildDifferenceTree(T obj1, T obj2, MemberInfo m if (!valueComparer.Compare(value1, value2, Settings)) { - yield return AddDifferenceToTree(new Difference(member.Name, valueComparer.ToString(value1), valueComparer.ToString(value2)), memberContext); + yield return AddDifferenceToTree(new Difference(member.Name, valueComparer.ToString(value1), valueComparer.ToString(value2)), memberNode); } } } diff --git a/ObjectsComparer/ObjectsComparer/ComparisonSettings.cs b/ObjectsComparer/ObjectsComparer/ComparisonSettings.cs index 0042854..f3a127d 100644 --- a/ObjectsComparer/ObjectsComparer/ComparisonSettings.cs +++ b/ObjectsComparer/ObjectsComparer/ComparisonSettings.cs @@ -72,7 +72,7 @@ public T GetCustomSetting(string key = null) /// /// Configures list comparison behavior, especially the type of the comparison. For more info, see . /// - /// First parameter: Current list comparison context. + /// First parameter: Current list node. public ComparisonSettings ConfigureListComparison(Action comparisonOptions) { if (comparisonOptions is null) @@ -117,11 +117,16 @@ public void ConfigureListComparison(bool compareElementsByKey = false, bool comp }); } - internal Action ComparisonContextOptionsAction { get; private set; } + internal Action DifferenceTreeOptionsAction { get; private set; } - public void ConfigureComparisonContext(Action options) + /// + /// Configures the difference tree behavior, see . + /// + /// + /// + public void ConfigureDifferenceTree(Action options) { - ComparisonContextOptionsAction = options ?? throw new ArgumentNullException(nameof(options)); + DifferenceTreeOptionsAction = options ?? throw new ArgumentNullException(nameof(options)); } } } diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractDynamicObjectsComprer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractDynamicObjectsComprer.cs index 50eb653..330b20a 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractDynamicObjectsComprer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractDynamicObjectsComprer.cs @@ -15,21 +15,21 @@ protected AbstractDynamicObjectsComprer(ComparisonSettings settings, BaseCompare public override IEnumerable CalculateDifferences(Type type, object obj1, object obj2) { - return AsContextableComparer().BuildDifferenceTree(type, obj1, obj2, ComparisonContextProvider.CreateImplicitRootContext(Settings)) + return AsDifferenceTreeBuilder().BuildDifferenceTree(type, obj1, obj2, DifferenceTreeNodeProvider.CreateImplicitRootNode(Settings)) .Select(differenceLocation => differenceLocation.Difference); } - IEnumerable IDifferenceTreeBuilder.BuildDifferenceTree(T obj1, T obj2, IDifferenceTreeNode comparisonContext) + IEnumerable IDifferenceTreeBuilder.BuildDifferenceTree(T obj1, T obj2, IDifferenceTreeNode differenceTreeNode) { - return AsContextableComparer().BuildDifferenceTree(typeof(T), obj1, obj2, ComparisonContextProvider.CreateImplicitRootContext(Settings)); + return AsDifferenceTreeBuilder().BuildDifferenceTree(typeof(T), obj1, obj2, DifferenceTreeNodeProvider.CreateImplicitRootNode(Settings)); } - IDifferenceTreeBuilder AsContextableComparer() + IDifferenceTreeBuilder AsDifferenceTreeBuilder() { return this; } - IEnumerable IDifferenceTreeBuilder.BuildDifferenceTree(Type type, object obj1, object obj2, IDifferenceTreeNode comparisonContext) + IEnumerable IDifferenceTreeBuilder.BuildDifferenceTree(Type type, object obj1, object obj2, IDifferenceTreeNode differenceTreeNode) { var castedObject1 = (T)obj1; var castedObject2 = (T)obj2; @@ -58,7 +58,7 @@ IEnumerable IDifferenceTreeBuilder.BuildDifferenceTree(Type TryGetMember(castedObject1, propertyKey, out member2); } - var keyComparisonContext = ComparisonContextProvider.CreateContext(Settings, comparisonContext, member1 ?? member2, propertyKey); + var keyDifferenceTreeNode = DifferenceTreeNodeProvider.CreateNode(Settings, differenceTreeNode, member1 ?? member2, propertyKey); var propertyType = (value1 ?? value2)?.GetType() ?? typeof(object); var customComparer = OverridesCollection.GetComparer(propertyType) ?? @@ -84,7 +84,7 @@ IEnumerable IDifferenceTreeBuilder.BuildDifferenceTree(Type { var difference = AddDifferenceToTree( new Difference(propertyKey, string.Empty, valueComparer.ToString(value2), DifferenceTypes.MissedMemberInFirstObject), - keyComparisonContext); + keyDifferenceTreeNode); yield return difference; continue; @@ -94,7 +94,7 @@ IEnumerable IDifferenceTreeBuilder.BuildDifferenceTree(Type { var difference = AddDifferenceToTree( new Difference(propertyKey, valueComparer.ToString(value1), string.Empty, DifferenceTypes.MissedMemberInSecondObject), - keyComparisonContext); + keyDifferenceTreeNode); yield return difference; continue; @@ -109,7 +109,7 @@ IEnumerable IDifferenceTreeBuilder.BuildDifferenceTree(Type var difference = AddDifferenceToTree( new Difference(propertyKey, valueComparer.ToString(value1), valueComparer2.ToString(value2), DifferenceTypes.TypeMismatch), - keyComparisonContext); + keyDifferenceTreeNode); yield return difference; continue; @@ -125,7 +125,7 @@ IEnumerable IDifferenceTreeBuilder.BuildDifferenceTree(Type var difference = AddDifferenceToTree( new Difference(propertyKey, valueComparer.ToString(value1), valueComparer2.ToString(value2), DifferenceTypes.TypeMismatch), - keyComparisonContext); + keyDifferenceTreeNode); yield return difference; continue; @@ -137,7 +137,7 @@ IEnumerable IDifferenceTreeBuilder.BuildDifferenceTree(Type { var differenceLocation = AddDifferenceToTree( new Difference(propertyKey, customComparer.ToString(value1), customComparer.ToString(value2)), - keyComparisonContext); + keyDifferenceTreeNode); yield return differenceLocation; } @@ -146,7 +146,7 @@ IEnumerable IDifferenceTreeBuilder.BuildDifferenceTree(Type } var comparer = Factory.GetObjectsComparer(propertyType, Settings, this); - foreach (var failure in comparer.TryBuildDifferenceTree(propertyType, value1, value2, comparisonContext)) + foreach (var failure in comparer.TryBuildDifferenceTree(propertyType, value1, value2, differenceTreeNode)) { failure.Difference.InsertPath(propertyKey); yield return failure; diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractEnumerablesComparer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractEnumerablesComparer.cs index 8f79f5b..ae42fd9 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractEnumerablesComparer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractEnumerablesComparer.cs @@ -60,6 +60,6 @@ public virtual bool SkipMember(Type type, MemberInfo member) public abstract bool IsMatch(Type type, object obj1, object obj2); - public abstract IEnumerable BuildDifferenceTree(Type type, object obj1, object obj2, IDifferenceTreeNode comparisonContext); + public abstract IEnumerable BuildDifferenceTree(Type type, object obj1, object obj2, IDifferenceTreeNode differenceTreeNode); } } \ No newline at end of file diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs index c1a4012..f3c4e37 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs @@ -18,25 +18,25 @@ public EnumerablesComparer(ComparisonSettings settings, BaseComparer parentCompa public override IEnumerable CalculateDifferences(Type type, object obj1, object obj2) { - return AsContextable().BuildDifferenceTree(type, obj1, obj2, ComparisonContextProvider.CreateImplicitRootContext(Settings)) + return AsDifferenceTreeBuilder().BuildDifferenceTree(type, obj1, obj2, DifferenceTreeNodeProvider.CreateImplicitRootNode(Settings)) .Select(differenceLocation => differenceLocation.Difference); } - IDifferenceTreeBuilder AsContextable() => this; + IDifferenceTreeBuilder AsDifferenceTreeBuilder() => this; - IEnumerable IDifferenceTreeBuilder.BuildDifferenceTree(Type type, object obj1, object obj2, IDifferenceTreeNode listComparisonContext) + IEnumerable IDifferenceTreeBuilder.BuildDifferenceTree(Type type, object obj1, object obj2, IDifferenceTreeNode listDifferenceTreeNode) { Debug.WriteLine($"{GetType().Name}.{nameof(CalculateDifferences)}: {type.Name}"); - if (listComparisonContext is null) + if (listDifferenceTreeNode is null) { - throw new ArgumentNullException(nameof(listComparisonContext)); + throw new ArgumentNullException(nameof(listDifferenceTreeNode)); } if (!Settings.EmptyAndNullEnumerablesEqual && (obj1 == null || obj2 == null) && obj1 != obj2) { - yield return AddDifferenceToTree(new Difference("[]", obj1?.ToString() ?? string.Empty, obj2?.ToString() ?? string.Empty), listComparisonContext); + yield return AddDifferenceToTree(new Difference("[]", obj1?.ToString() ?? string.Empty, obj2?.ToString() ?? string.Empty), listDifferenceTreeNode); yield break; } @@ -62,11 +62,11 @@ IEnumerable IDifferenceTreeBuilder.BuildDifferenceTree(Type var array2 = ((IEnumerable)obj2).Cast().ToArray(); var listComparisonOptions = ListComparisonOptions.Default(); - Settings.ListComparisonOptionsAction?.Invoke(listComparisonContext, listComparisonOptions); + Settings.ListComparisonOptionsAction?.Invoke(listDifferenceTreeNode, listComparisonOptions); if (array1.Length != array2.Length) { - yield return AddDifferenceToTree(new Difference("", array1.Length.ToString(), array2.Length.ToString(), DifferenceTypes.NumberOfElementsMismatch), listComparisonContext); + yield return AddDifferenceToTree(new Difference("", array1.Length.ToString(), array2.Length.ToString(), DifferenceTypes.NumberOfElementsMismatch), listDifferenceTreeNode); if (listComparisonOptions.UnequalListsComparisonEnabled == false) { @@ -74,7 +74,7 @@ IEnumerable IDifferenceTreeBuilder.BuildDifferenceTree(Type } } - var failrues = CalculateDifferences(array1, array2, listComparisonContext, listComparisonOptions); + var failrues = CalculateDifferences(array1, array2, listDifferenceTreeNode, listComparisonOptions); foreach (var failrue in failrues) { diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparerBase.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparerBase.cs index 97a2088..a35cd18 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparerBase.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparerBase.cs @@ -16,15 +16,15 @@ public EnumerablesComparerBase(ComparisonSettings settings, BaseComparer parentC /// /// Selects calculation operation based on the current value of the property. /// - protected virtual IEnumerable CalculateDifferences(IList list1, IList list2, IDifferenceTreeNode listComparisonContext, ListComparisonOptions listComparisonOptions) + protected virtual IEnumerable CalculateDifferences(IList list1, IList list2, IDifferenceTreeNode listDifferenceTreeNode, ListComparisonOptions listComparisonOptions) { if (listComparisonOptions.ElementSearchMode == ListElementSearchMode.Key) { - return CalculateDifferencesByKey(list1, list2, listComparisonContext, listComparisonOptions); + return CalculateDifferencesByKey(list1, list2, listDifferenceTreeNode, listComparisonOptions); } else if (listComparisonOptions.ElementSearchMode == ListElementSearchMode.Index) { - return CalculateDifferencesByIndex(list1, list2, listComparisonContext, listComparisonOptions); + return CalculateDifferencesByIndex(list1, list2, listDifferenceTreeNode, listComparisonOptions); } else { @@ -35,7 +35,7 @@ protected virtual IEnumerable CalculateDifferences(IList< /// /// Calculates differences using comparison mode. /// - protected virtual IEnumerable CalculateDifferencesByKey(IList array1, IList array2, IDifferenceTreeNode listComparisonContext, ListComparisonOptions listComparisonOptions) + protected virtual IEnumerable CalculateDifferencesByKey(IList array1, IList array2, IDifferenceTreeNode listDifferenceTreeNode, ListComparisonOptions listComparisonOptions) { Debug.WriteLine($"{GetType().Name}.{nameof(CalculateDifferencesByKey)}: {array1?.GetType().Name}"); @@ -45,8 +45,7 @@ protected virtual IEnumerable CalculateDifferencesByKey(I for (int element1Index = 0; element1Index < array1.Count(); element1Index++) { var element1 = array1[element1Index]; - //var elementComparisonContext = new ComparisonContext(new ComparisonContextMember(), listComparisonContext); - var elementComparisonContext = ComparisonContextProvider.CreateContext(Settings, listComparisonContext); + var elementDifferenceTreeNode = DifferenceTreeNodeProvider.CreateNode(Settings, listDifferenceTreeNode); if (element1 == null) { @@ -57,7 +56,7 @@ protected virtual IEnumerable CalculateDifferencesByKey(I var nullElementIdentifier = keyOptions.GetNullElementIdentifier(new FormatNullElementIdentifierArgs(element1Index)); - yield return AddDifferenceToTree(new Difference($"[{nullElementIdentifier}]", string.Empty, string.Empty, DifferenceTypes.MissedElementInSecondObject), elementComparisonContext); + yield return AddDifferenceToTree(new Difference($"[{nullElementIdentifier}]", string.Empty, string.Empty, DifferenceTypes.MissedElementInSecondObject), elementDifferenceTreeNode); continue; } @@ -67,7 +66,7 @@ protected virtual IEnumerable CalculateDifferencesByKey(I { if (keyOptions.ThrowKeyNotFoundEnabled) { - throw new ElementKeyNotFoundException(element1, elementComparisonContext); + throw new ElementKeyNotFoundException(element1, elementDifferenceTreeNode); } continue; @@ -80,7 +79,7 @@ protected virtual IEnumerable CalculateDifferencesByKey(I var element2 = array2.First(elm2 => elm2 != null && object.Equals(element1Key, keyOptions.ElementKeyProviderAction(new ListElementKeyProviderArgs(elm2)))); var comparer = Factory.GetObjectsComparer(element1.GetType(), Settings, this); - foreach (var failure in comparer.TryBuildDifferenceTree(element1.GetType(), element1, element2, elementComparisonContext)) + foreach (var failure in comparer.TryBuildDifferenceTree(element1.GetType(), element1, element2, elementDifferenceTreeNode)) { failure.Difference.InsertPath($"[{formattedElement1Key}]"); yield return failure; @@ -89,15 +88,14 @@ protected virtual IEnumerable CalculateDifferencesByKey(I else { var valueComparer1 = OverridesCollection.GetComparer(element1.GetType()) ?? DefaultValueComparer; - yield return AddDifferenceToTree(new Difference($"[{formattedElement1Key}]", valueComparer1.ToString(element1), string.Empty, DifferenceTypes.MissedElementInSecondObject), elementComparisonContext); + yield return AddDifferenceToTree(new Difference($"[{formattedElement1Key}]", valueComparer1.ToString(element1), string.Empty, DifferenceTypes.MissedElementInSecondObject), elementDifferenceTreeNode); } } for (int element2Index = 0; element2Index < array2.Count(); element2Index++) { var element2 = array2[element2Index]; - //var elementComparisonContext = new ComparisonContext(new ComparisonContextMember(), listComparisonContext); - var elementComparisonContext = ComparisonContextProvider.CreateContext(Settings, listComparisonContext); + var elementDifferenceTreeNode = DifferenceTreeNodeProvider.CreateNode(Settings, listDifferenceTreeNode); if (element2 == null) { @@ -108,7 +106,7 @@ protected virtual IEnumerable CalculateDifferencesByKey(I var nullElementIdentifier = keyOptions.GetNullElementIdentifier(new FormatNullElementIdentifierArgs(element2Index)); - yield return AddDifferenceToTree(new Difference($"[{nullElementIdentifier}]", string.Empty, string.Empty, DifferenceTypes.MissedElementInFirstObject), elementComparisonContext); + yield return AddDifferenceToTree(new Difference($"[{nullElementIdentifier}]", string.Empty, string.Empty, DifferenceTypes.MissedElementInFirstObject), elementDifferenceTreeNode); continue; } @@ -118,7 +116,7 @@ protected virtual IEnumerable CalculateDifferencesByKey(I { if (keyOptions.ThrowKeyNotFoundEnabled) { - throw new ElementKeyNotFoundException(element2, elementComparisonContext); + throw new ElementKeyNotFoundException(element2, elementDifferenceTreeNode); } continue; @@ -128,7 +126,7 @@ protected virtual IEnumerable CalculateDifferencesByKey(I { var formattedElement2Key = keyOptions.GetFormattedElementKey(new FormatListElementKeyArgs(element2Index, element2Key, element2)); var valueComparer2 = OverridesCollection.GetComparer(element2.GetType()) ?? DefaultValueComparer; - yield return AddDifferenceToTree(new Difference($"[{formattedElement2Key}]", string.Empty, valueComparer2.ToString(element2), DifferenceTypes.MissedElementInFirstObject), elementComparisonContext); + yield return AddDifferenceToTree(new Difference($"[{formattedElement2Key}]", string.Empty, valueComparer2.ToString(element2), DifferenceTypes.MissedElementInFirstObject), elementDifferenceTreeNode); } } } @@ -136,7 +134,7 @@ protected virtual IEnumerable CalculateDifferencesByKey(I /// /// Calculates differences using comparison mode. /// - protected virtual IEnumerable CalculateDifferencesByIndex(IList array1, IList array2, IDifferenceTreeNode listComparisonContext, ListComparisonOptions listComparisonOptions) + protected virtual IEnumerable CalculateDifferencesByIndex(IList array1, IList array2, IDifferenceTreeNode listDifferenceTreeNode, ListComparisonOptions listComparisonOptions) { Debug.WriteLine($"{GetType().Name}.{nameof(CalculateDifferencesByIndex)}: {array1?.GetType().Name}"); @@ -147,8 +145,7 @@ protected virtual IEnumerable CalculateDifferencesByIndex //ToDo Extract type for (var i = 0; i < smallerCount; i++) { - //var elementComparisonContext = new ComparisonContext(new ComparisonContextMember(), listComparisonContext); - var elementComparisonContext = ComparisonContextProvider.CreateContext(Settings, listComparisonContext); + var elementDifferenceTreeNode = DifferenceTreeNodeProvider.CreateNode(Settings, listDifferenceTreeNode); if (array1[i] == null && array2[i] == null) { @@ -160,25 +157,25 @@ protected virtual IEnumerable CalculateDifferencesByIndex if (array1[i] == null) { - yield return AddDifferenceToTree(new Difference($"[{i}]", string.Empty, valueComparer2.ToString(array2[i])), elementComparisonContext); + yield return AddDifferenceToTree(new Difference($"[{i}]", string.Empty, valueComparer2.ToString(array2[i])), elementDifferenceTreeNode); continue; } if (array2[i] == null) { - yield return AddDifferenceToTree(new Difference($"[{i}]", valueComparer1.ToString(array1[i]), string.Empty), elementComparisonContext); + yield return AddDifferenceToTree(new Difference($"[{i}]", valueComparer1.ToString(array1[i]), string.Empty), elementDifferenceTreeNode); continue; } if (array1[i].GetType() != array2[i].GetType()) { - yield return AddDifferenceToTree(new Difference($"[{i}]", valueComparer1.ToString(array1[i]), valueComparer2.ToString(array2[i]), DifferenceTypes.TypeMismatch), elementComparisonContext); + yield return AddDifferenceToTree(new Difference($"[{i}]", valueComparer1.ToString(array1[i]), valueComparer2.ToString(array2[i]), DifferenceTypes.TypeMismatch), elementDifferenceTreeNode); continue; } var comparer = Factory.GetObjectsComparer(array1[i].GetType(), Settings, this); - foreach (var failure in comparer.TryBuildDifferenceTree(array1[i].GetType(), array1[i], array2[i], elementComparisonContext)) + foreach (var failure in comparer.TryBuildDifferenceTree(array1[i].GetType(), array1[i], array2[i], elementDifferenceTreeNode)) { failure.Difference.InsertPath($"[{i}]"); yield return failure; @@ -200,8 +197,7 @@ protected virtual IEnumerable CalculateDifferencesByIndex value2: array2Count > array1Count ? valueComparer.ToString(largerArray[i]) : string.Empty, differenceType: array1Count > array2Count ? DifferenceTypes.MissedElementInSecondObject : DifferenceTypes.MissedElementInFirstObject); - //yield return AddDifferenceToComparisonContext(difference, new ComparisonContext(new ComparisonContextMember(), listComparisonContext)); - yield return AddDifferenceToTree(difference, ComparisonContextProvider.CreateContext(Settings, listComparisonContext)); + yield return AddDifferenceToTree(difference, DifferenceTreeNodeProvider.CreateNode(Settings, listDifferenceTreeNode)); } } } diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer~1.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer~1.cs index bfc6f25..3aeda59 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer~1.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer~1.cs @@ -19,17 +19,17 @@ public EnumerablesComparer(ComparisonSettings settings, BaseComparer parentCompa public override IEnumerable CalculateDifferences(Type type, object obj1, object obj2) { - return BuildDifferenceTree(type, obj1, obj2, ComparisonContextProvider.CreateImplicitRootContext(Settings)) + return BuildDifferenceTree(type, obj1, obj2, DifferenceTreeNodeProvider.CreateImplicitRootNode(Settings)) .Select(differeneLocation => differeneLocation.Difference); } - public IEnumerable BuildDifferenceTree(Type type, object obj1, object obj2, IDifferenceTreeNode listComparisonContext) + public IEnumerable BuildDifferenceTree(Type type, object obj1, object obj2, IDifferenceTreeNode listDifferenceTreeNode) { Debug.WriteLine($"{GetType().Name}.{nameof(BuildDifferenceTree)}: {type.Name}"); - if (listComparisonContext is null) + if (listDifferenceTreeNode is null) { - throw new ArgumentNullException(nameof(listComparisonContext)); + throw new ArgumentNullException(nameof(listDifferenceTreeNode)); } if (!type.InheritsFrom(typeof(IEnumerable<>))) @@ -60,13 +60,13 @@ public IEnumerable BuildDifferenceTree(Type type, object obj var list2 = ((IEnumerable)obj2).ToList(); var listComparisonOptions = ListComparisonOptions.Default(); - Settings.ListComparisonOptionsAction?.Invoke(listComparisonContext, listComparisonOptions); + Settings.ListComparisonOptionsAction?.Invoke(listDifferenceTreeNode, listComparisonOptions); if (list1.Count != list2.Count) { if (!type.GetTypeInfo().IsArray) { - yield return AddDifferenceToTree(new Difference("", list1.Count().ToString(), list2.Count().ToString(), DifferenceTypes.NumberOfElementsMismatch), listComparisonContext); + yield return AddDifferenceToTree(new Difference("", list1.Count().ToString(), list2.Count().ToString(), DifferenceTypes.NumberOfElementsMismatch), listDifferenceTreeNode); } if (listComparisonOptions.UnequalListsComparisonEnabled == false) @@ -75,7 +75,7 @@ public IEnumerable BuildDifferenceTree(Type type, object obj } } - var failrues = CalculateDifferences(list1, list2, listComparisonContext, listComparisonOptions); + var failrues = CalculateDifferences(list1, list2, listDifferenceTreeNode, listComparisonOptions); foreach (var failrue in failrues) { @@ -83,9 +83,9 @@ public IEnumerable BuildDifferenceTree(Type type, object obj } } - public IEnumerable BuildDifferenceTree(T obj1, T obj2, IDifferenceTreeNode listComparisonContext) + public IEnumerable BuildDifferenceTree(T obj1, T obj2, IDifferenceTreeNode listDifferenceTreeNode) { - return BuildDifferenceTree(((object)obj1 ?? obj2).GetType(), obj1, obj2, listComparisonContext); + return BuildDifferenceTree(((object)obj1 ?? obj2).GetType(), obj1, obj2, listDifferenceTreeNode); } } } diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/GenericEnumerablesComparer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/GenericEnumerablesComparer.cs index b52460f..fdac5ec 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/GenericEnumerablesComparer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/GenericEnumerablesComparer.cs @@ -18,11 +18,11 @@ public GenericEnumerablesComparer(ComparisonSettings settings, BaseComparer pare public override IEnumerable CalculateDifferences(Type type, object obj1, object obj2) { - return BuildDifferenceTree(type, obj1, obj2, ComparisonContextProvider.CreateImplicitRootContext(Settings)) + return BuildDifferenceTree(type, obj1, obj2, DifferenceTreeNodeProvider.CreateImplicitRootNode(Settings)) .Select(differenceLocation => differenceLocation.Difference); } - public override IEnumerable BuildDifferenceTree(Type type, object obj1, object obj2, IDifferenceTreeNode comparisonContext) + public override IEnumerable BuildDifferenceTree(Type type, object obj1, object obj2, IDifferenceTreeNode differenceTreeNode) { if (obj1 == null && obj2 == null) { @@ -51,7 +51,7 @@ public override IEnumerable BuildDifferenceTree(Type type, o var enumerablesComparerType = typeof(EnumerablesComparer<>).MakeGenericType(elementType); var comparer = (IComparer)Activator.CreateInstance(enumerablesComparerType, Settings, this, Factory); - foreach (var difference in comparer.TryBuildDifferenceTree(type, obj1, obj2, comparisonContext)) + foreach (var difference in comparer.TryBuildDifferenceTree(type, obj1, obj2, differenceTreeNode)) { yield return difference; } diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/HashSetsComparer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/HashSetsComparer.cs index 5faa697..feff414 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/HashSetsComparer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/HashSetsComparer.cs @@ -16,11 +16,11 @@ public HashSetsComparer(ComparisonSettings settings, BaseComparer parentComparer public override IEnumerable CalculateDifferences(Type type, object obj1, object obj2) { - return BuildDifferenceTree(type, obj1, obj2, ComparisonContextProvider.CreateImplicitRootContext(Settings)) + return BuildDifferenceTree(type, obj1, obj2, DifferenceTreeNodeProvider.CreateImplicitRootNode(Settings)) .Select(differenceLocation => differenceLocation.Difference); } - public override IEnumerable BuildDifferenceTree(Type type, object obj1, object obj2, IDifferenceTreeNode comparisonContext) + public override IEnumerable BuildDifferenceTree(Type type, object obj1, object obj2, IDifferenceTreeNode differenceTreeNode) { if (obj1 == null && obj2 == null) { @@ -40,7 +40,7 @@ public override IEnumerable BuildDifferenceTree(Type type, o var enumerablesComparerType = typeof(HashSetsComparer<>).MakeGenericType(elementType); var comparer = (IComparer)Activator.CreateInstance(enumerablesComparerType, Settings, this, Factory); - foreach (var difference in comparer.TryBuildDifferenceTree(type, obj1, obj2, comparisonContext)) + foreach (var difference in comparer.TryBuildDifferenceTree(type, obj1, obj2, differenceTreeNode)) { yield return difference; } diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/HashSetsComparer~1.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/HashSetsComparer~1.cs index bc57202..400b4e0 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/HashSetsComparer~1.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/HashSetsComparer~1.cs @@ -13,22 +13,22 @@ public HashSetsComparer(ComparisonSettings settings, BaseComparer parentComparer { } - public IEnumerable BuildDifferenceTree(T obj1, T obj2, IDifferenceTreeNode comparisonContext) + public IEnumerable BuildDifferenceTree(T obj1, T obj2, IDifferenceTreeNode differenceTreeNode) { - return BuildDifferenceTree(typeof(T), obj1, obj2, comparisonContext); + return BuildDifferenceTree(typeof(T), obj1, obj2, differenceTreeNode); } public override IEnumerable CalculateDifferences(Type type, object obj1, object obj2) { - return BuildDifferenceTree(type, obj1, obj2, ComparisonContextProvider.CreateImplicitRootContext(Settings)) + return BuildDifferenceTree(type, obj1, obj2, DifferenceTreeNodeProvider.CreateImplicitRootNode(Settings)) .Select(differenceLocation => differenceLocation.Difference); } - public IEnumerable BuildDifferenceTree(Type type, object obj1, object obj2, IDifferenceTreeNode comparisonContext) + public IEnumerable BuildDifferenceTree(Type type, object obj1, object obj2, IDifferenceTreeNode differenceTreeNode) { - if (comparisonContext is null) + if (differenceTreeNode is null) { - throw new ArgumentNullException(nameof(comparisonContext)); + throw new ArgumentNullException(nameof(differenceTreeNode)); } if (!type.InheritsFrom(typeof(HashSet<>))) @@ -65,7 +65,7 @@ public IEnumerable BuildDifferenceTree(Type type, object obj { var difference = AddDifferenceToTree( new Difference("", valueComparer.ToString(element), string.Empty, DifferenceTypes.MissedElementInSecondObject), - comparisonContext); + differenceTreeNode); yield return difference; } @@ -76,7 +76,7 @@ public IEnumerable BuildDifferenceTree(Type type, object obj if (!hashSet1.Contains(element)) { var difference = AddDifferenceToTree(new Difference("", string.Empty, valueComparer.ToString(element), - DifferenceTypes.MissedElementInFirstObject), comparisonContext); + DifferenceTypes.MissedElementInFirstObject), differenceTreeNode); yield return difference; } diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/MultidimensionalArrayComparer~1.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/MultidimensionalArrayComparer~1.cs index 76eeeb7..b2783b7 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/MultidimensionalArrayComparer~1.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/MultidimensionalArrayComparer~1.cs @@ -18,20 +18,20 @@ public MultidimensionalArrayComparer(ComparisonSettings settings, BaseComparer p public override IEnumerable CalculateDifferences(Type type, object obj1, object obj2) { - return BuildDifferenceTree(type, obj1, obj2, ComparisonContextProvider.CreateImplicitRootContext(Settings)) + return BuildDifferenceTree(type, obj1, obj2, DifferenceTreeNodeProvider.CreateImplicitRootNode(Settings)) .Select(differenceLocation => differenceLocation.Difference); } - public IEnumerable BuildDifferenceTree(T obj1, T obj2, IDifferenceTreeNode comparisonContext) + public IEnumerable BuildDifferenceTree(T obj1, T obj2, IDifferenceTreeNode differenceTreeNode) { - return BuildDifferenceTree(typeof(T), obj1, obj2, comparisonContext); + return BuildDifferenceTree(typeof(T), obj1, obj2, differenceTreeNode); } - public IEnumerable BuildDifferenceTree(Type type, object obj1, object obj2, IDifferenceTreeNode comparisonContext) + public IEnumerable BuildDifferenceTree(Type type, object obj1, object obj2, IDifferenceTreeNode differenceTreeNode) { - if (comparisonContext is null) + if (differenceTreeNode is null) { - throw new ArgumentNullException(nameof(comparisonContext)); + throw new ArgumentNullException(nameof(differenceTreeNode)); } if (!type.InheritsFrom(typeof(Array))) @@ -60,7 +60,7 @@ public IEnumerable BuildDifferenceTree(Type type, object obj if (array1.Rank != array2.Rank) { - var difference = AddDifferenceToTree(new Difference("Rank", array1.Rank.ToString(), array2.Rank.ToString()), comparisonContext); + var difference = AddDifferenceToTree(new Difference("Rank", array1.Rank.ToString(), array2.Rank.ToString()), differenceTreeNode); yield return difference; yield break; } @@ -75,7 +75,7 @@ public IEnumerable BuildDifferenceTree(Type type, object obj if (length1 != length2) { dimensionsFailure = true; - var difference = AddDifferenceToTree(new Difference($"Dimension{i}", length1.ToString(), length2.ToString()), comparisonContext); + var difference = AddDifferenceToTree(new Difference($"Dimension{i}", length1.ToString(), length2.ToString()), differenceTreeNode); yield return difference; } } @@ -89,7 +89,7 @@ public IEnumerable BuildDifferenceTree(Type type, object obj { var indecies = IndexToCoordinates(array1, i); - foreach (var failure in _comparer.TryBuildDifferenceTree((T)array1.GetValue(indecies), (T)array2.GetValue(indecies), comparisonContext)) + foreach (var failure in _comparer.TryBuildDifferenceTree((T)array1.GetValue(indecies), (T)array2.GetValue(indecies), differenceTreeNode)) { failure.Difference.InsertPath($"[{string.Join(",", indecies)}]"); yield return failure; diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/MultidimensionalArraysComparer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/MultidimensionalArraysComparer.cs index 0bb7058..003bb4e 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/MultidimensionalArraysComparer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/MultidimensionalArraysComparer.cs @@ -17,11 +17,11 @@ public MultidimensionalArraysComparer(ComparisonSettings settings, BaseComparer public override IEnumerable CalculateDifferences(Type type, object obj1, object obj2) { - return BuildDifferenceTree(type, obj1, obj2, ComparisonContextProvider.CreateImplicitRootContext(Settings)) + return BuildDifferenceTree(type, obj1, obj2, DifferenceTreeNodeProvider.CreateImplicitRootNode(Settings)) .Select(differenceLocation => differenceLocation.Difference); } - public override IEnumerable BuildDifferenceTree(Type type, object obj1, object obj2, IDifferenceTreeNode comparisonContext) + public override IEnumerable BuildDifferenceTree(Type type, object obj1, object obj2, IDifferenceTreeNode differenceTreeNode) { if (obj1 == null && obj2 == null) { @@ -32,7 +32,7 @@ public override IEnumerable BuildDifferenceTree(Type type, o var enumerablesComparerType = typeof(MultidimensionalArrayComparer<>).MakeGenericType(typeInfo.GetElementType()); var comparer = (IComparer)Activator.CreateInstance(enumerablesComparerType, Settings, this, Factory); - foreach (var difference in comparer.TryBuildDifferenceTree(type, obj1, obj2, comparisonContext)) + foreach (var difference in comparer.TryBuildDifferenceTree(type, obj1, obj2, differenceTreeNode)) { yield return difference; } diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/TypesComparer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/TypesComparer.cs index de1ba9b..e85cdfe 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/TypesComparer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/TypesComparer.cs @@ -17,15 +17,15 @@ public TypesComparer(ComparisonSettings settings, BaseComparer parentComparer, public override IEnumerable CalculateDifferences(Type type, object obj1, object obj2) { - return BuildDifferenceTree(type, obj1, obj2, ComparisonContextProvider.CreateImplicitRootContext(Settings)) + return BuildDifferenceTree(type, obj1, obj2, DifferenceTreeNodeProvider.CreateImplicitRootNode(Settings)) .Select(differenceLocation => differenceLocation.Difference); } - public IEnumerable BuildDifferenceTree(Type type, object obj1, object obj2, IDifferenceTreeNode comparisonContext) + public IEnumerable BuildDifferenceTree(Type type, object obj1, object obj2, IDifferenceTreeNode differenceTreeNode) { - if (comparisonContext is null) + if (differenceTreeNode is null) { - throw new ArgumentNullException(nameof(comparisonContext)); + throw new ArgumentNullException(nameof(differenceTreeNode)); } if (obj1 == null && obj2 == null) @@ -49,7 +49,7 @@ public IEnumerable BuildDifferenceTree(Type type, object obj if (type1Str != type2Str) { //yield return new Difference(string.Empty, type1Str, type2Str); - yield return AddDifferenceToTree(new Difference(string.Empty, type1Str, type2Str), comparisonContext); + yield return AddDifferenceToTree(new Difference(string.Empty, type1Str, type2Str), differenceTreeNode); } } diff --git a/ObjectsComparer/ObjectsComparer/DifferenceTree/ComparerExtensions.cs b/ObjectsComparer/ObjectsComparer/DifferenceTree/ComparerExtensions.cs index 4a236c7..b62647d 100644 --- a/ObjectsComparer/ObjectsComparer/DifferenceTree/ComparerExtensions.cs +++ b/ObjectsComparer/ObjectsComparer/DifferenceTree/ComparerExtensions.cs @@ -13,9 +13,9 @@ public static class ComparerExtensions /// Calculates the difference tree. /// /// Current comparison context. The return value tells whether to look for another difference. If the argument is null the process is looking for all the differences. - /// If the comparison process has been completed, this action will be invoked. + /// If the comparison process has been completed, this action will be invoked. /// The root node of the difference tree. - public static IDifferenceTreeNode CalculateDifferenceTree(this IComparer comparer, Type type, object obj1, object obj2, Func findNextDifference = null, Action contextCompleted = null) + public static IDifferenceTreeNode CalculateDifferenceTree(this IComparer comparer, Type type, object obj1, object obj2, Func findNextDifference = null, Action differenceTreeCompleted = null) { if (comparer is null) { @@ -30,7 +30,7 @@ public static IDifferenceTreeNode CalculateDifferenceTree(this IComparer compare findNextDifference = findNextDifference ?? ((_) => true); //Anything but ImplicitComparisonContext (ImplicitDifferenceTreeNode). - var rootNode = ComparisonContextProvider.CreateContext(comparer.Settings, ancestor: null); + var rootNode = DifferenceTreeNodeProvider.CreateNode(comparer.Settings, ancestor: null); var differenceLocationList = comparer.TryBuildDifferenceTree(type, obj1, obj2, rootNode); @@ -39,7 +39,7 @@ public static IDifferenceTreeNode CalculateDifferenceTree(this IComparer compare { return findNextDifference(new ComparisonContext(rootNode, currentLocation.Difference, currentLocation.TreeNode)); }, - contextCompleted); + differenceTreeCompleted); return rootNode; } @@ -48,9 +48,9 @@ public static IDifferenceTreeNode CalculateDifferenceTree(this IComparer compare /// Calculates the difference tree. /// /// Current comparison context. The return value tells whether to look for another difference. - /// If the comparison process has been completed, this action will be invoked. + /// If the comparison process has been completed, this action will be invoked. /// The root node of the difference tree. - public static IDifferenceTreeNode CalculateDifferenceTree(this IComparer comparer, T obj1, T obj2, Func findNextDifference = null, Action contextCompleted = null) + public static IDifferenceTreeNode CalculateDifferenceTree(this IComparer comparer, T obj1, T obj2, Func findNextDifference = null, Action differenceTreeCompleted = null) { if (comparer is null) { @@ -59,7 +59,7 @@ public static IDifferenceTreeNode CalculateDifferenceTree(this IComparer c findNextDifference = findNextDifference ?? ((_) => true); - var rootNode = ComparisonContextProvider.CreateContext(comparer.Settings, ancestor: null); + var rootNode = DifferenceTreeNodeProvider.CreateNode(comparer.Settings, ancestor: null); var differenceLocationList = comparer.TryBuildDifferenceTree(obj1, obj2, rootNode); @@ -68,7 +68,7 @@ public static IDifferenceTreeNode CalculateDifferenceTree(this IComparer c { return findNextDifference(new ComparisonContext(rootNode, currentLocation.Difference, currentLocation.TreeNode)); }, - contextCompleted); + differenceTreeCompleted); return rootNode; } diff --git a/ObjectsComparer/ObjectsComparer/DifferenceTree/ComparisonContext.cs b/ObjectsComparer/ObjectsComparer/DifferenceTree/ComparisonContext.cs index a2b536c..7205a0c 100644 --- a/ObjectsComparer/ObjectsComparer/DifferenceTree/ComparisonContext.cs +++ b/ObjectsComparer/ObjectsComparer/DifferenceTree/ComparisonContext.cs @@ -2,6 +2,9 @@ namespace ObjectsComparer { + /// + /// The current context of the comparison in the process of creating the difference tree. For more info, see , or . + /// public class ComparisonContext { public IDifferenceTreeNode RootNode { get; } @@ -14,7 +17,7 @@ public ComparisonContext(IDifferenceTreeNode rootNode, Difference currentDiffere { RootNode = rootNode ?? throw new ArgumentNullException(nameof(rootNode)); CurrentDifference = currentDifference ?? throw new ArgumentNullException(nameof(currentDifference)); - CurrentNode = currentNode ?? throw new ArgumentNullException(nameof(currentNode)); + CurrentNode = currentNode; } } } diff --git a/ObjectsComparer/ObjectsComparer/DifferenceTree/ComparisonContextOptions.cs b/ObjectsComparer/ObjectsComparer/DifferenceTree/ComparisonContextOptions.cs deleted file mode 100644 index bb980cc..0000000 --- a/ObjectsComparer/ObjectsComparer/DifferenceTree/ComparisonContextOptions.cs +++ /dev/null @@ -1,52 +0,0 @@ -using System; -using System.Reflection; -using ObjectsComparer.Exceptions; - -namespace ObjectsComparer -{ - public class ComparisonContextOptions - { - ComparisonContextOptions() - { - } - - internal static ComparisonContextOptions Default() - { - return new ComparisonContextOptions(); - } - - internal Func ComparisonContextFactory { get; private set; } - - internal Func ComparisonContextMemberFactory { get; private set; } - - /// - /// Factory for instances. - /// - /// - public void UseComparisonContextFactory(Func factory) - { - ComparisonContextFactory = factory ?? throw new ArgumentNullException(nameof(factory)); - } - - /// - /// Factory for instances. - /// - public void UseComparisonContextMemberFactory(Func factory) - { - ComparisonContextMemberFactory = factory ?? throw new ArgumentNullException(nameof(factory)); - } - - public bool ThrowContextableComparerNotImplementedEnabled { get; private set; } = true; - - /// - /// Whether to throw the when the user requires comparison context but has a comparer that does not implement or . - /// Default = true. - /// - public ComparisonContextOptions ThrowContextableComparerNotImplemented(bool value) - { - ThrowContextableComparerNotImplementedEnabled = value; - - return this; - } - } -} diff --git a/ObjectsComparer/ObjectsComparer/DifferenceTree/ComparisonContextProvider.cs b/ObjectsComparer/ObjectsComparer/DifferenceTree/ComparisonContextProvider.cs deleted file mode 100644 index f164aa1..0000000 --- a/ObjectsComparer/ObjectsComparer/DifferenceTree/ComparisonContextProvider.cs +++ /dev/null @@ -1,82 +0,0 @@ -using System; -using System.Reflection; - -namespace ObjectsComparer -{ - public static class ComparisonContextProvider - { - public static IDifferenceTreeNode CreateRootContext() - { - return new DifferenceTreeNode(new DifferenceTreeNodeMember()); - } - - /// - /// Returns the root of the difference tree for cases where the consumer does not explicitly, directly or indirectly request the difference tree, ie the difference tree is created only as an auxiliary. - /// - public static IDifferenceTreeNode CreateImplicitRootContext(ComparisonSettings comparisonSettings) - { - _ = comparisonSettings ?? throw new ArgumentNullException(nameof(comparisonSettings)); - - return new ImplicitDifferenceTreeNode(new DifferenceTreeNodeMember()); - } - - public static IDifferenceTreeNode CreateContext(ComparisonSettings comparisonSettings, IDifferenceTreeNode ancestor) - { - return CreateContext(comparisonSettings, new DifferenceTreeNodeMember(), ancestor); - } - - public static IDifferenceTreeNode CreateContext(ComparisonSettings comparisonSettings, IDifferenceTreeNode ancestor, MemberInfo memberInfo) - { - return CreateContext(comparisonSettings, new DifferenceTreeNodeMember(memberInfo, memberInfo?.Name), ancestor); - } - - public static IDifferenceTreeNode CreateContext(ComparisonSettings comparisonSettings, IDifferenceTreeNode ancestor, string memberName) - { - return CreateContext(comparisonSettings, new DifferenceTreeNodeMember(name: memberName), ancestor); - } - - public static IDifferenceTreeNode CreateContext(ComparisonSettings comparisonSettings, IDifferenceTreeNode ancestor, MemberInfo memberInfo, string memberName) - { - return CreateContext(comparisonSettings, new DifferenceTreeNodeMember(memberInfo, memberName), ancestor); - } - - public static IDifferenceTreeNode CreateContext(ComparisonSettings comparisonSettings, IDifferenceTreeNodeMember comparisonContextMember, IDifferenceTreeNode ancestor) - { - _ = comparisonSettings ?? throw new ArgumentNullException(nameof(comparisonSettings)); - _ = comparisonContextMember ?? throw new ArgumentNullException(nameof(comparisonContextMember)); - //_ = ancestor ?? throw new ArgumentNullException(nameof(ancestor)); - - ComparisonContextOptions options = ComparisonContextOptions.Default(); - comparisonSettings.ComparisonContextOptionsAction?.Invoke(ancestor, options); - - if (options.ComparisonContextMemberFactory != null) - { - var customComparisonContextMember = options.ComparisonContextMemberFactory.Invoke(comparisonContextMember); - - if (customComparisonContextMember == null) - { - throw new InvalidOperationException("Comparison context member factory returned null member."); - } - - comparisonContextMember = customComparisonContextMember; - } - - if (options.ComparisonContextFactory != null) - { - var customContext = options.ComparisonContextFactory(comparisonContextMember); - - if (customContext != null) - { - return customContext; - } - - if (customContext == null) - { - throw new InvalidOperationException("Comparison context factory returned null context."); - } - } - - return new DifferenceTreeNode(comparisonContextMember, ancestor); - } - } -} diff --git a/ObjectsComparer/ObjectsComparer/DifferenceTree/DifferenceTreeBuilderExtensions.cs b/ObjectsComparer/ObjectsComparer/DifferenceTree/DifferenceTreeBuilderExtensions.cs index fa85fdc..046869f 100644 --- a/ObjectsComparer/ObjectsComparer/DifferenceTree/DifferenceTreeBuilderExtensions.cs +++ b/ObjectsComparer/ObjectsComparer/DifferenceTree/DifferenceTreeBuilderExtensions.cs @@ -11,8 +11,7 @@ public static class DifferenceTreeBuilderExtensions /// If possible, creates a difference tree. /// /// - /// If is , it looks for the difference, adds it to the difference tree and returns it, including its location. - /// If not, it only looks for the difference and returns it with empty location.
+ /// If is , it builds the difference tree. If not, it only builds the flat list of differences. /// It throws exception if necessary.
/// Intended for implementers. To avoid side effects, consumers should call extension method instead. ///
@@ -60,27 +59,26 @@ public static IEnumerable TryBuildDifferenceTree(this ICompa /// If possible, creates a difference tree. /// /// - /// If is , it looks for the difference, adds it to the difference tree and returns it, including its location. - /// If not, it only looks for the difference and returns it with empty location.
+ /// If is , it builds the difference tree. If not, it only builds the flat list of differences. /// It throws exception if necessary.
/// Intended for implementers. To avoid side effects, consumers should call extension method instead. ///
/// The differences with its eventual location in the difference tree. - public static IEnumerable TryBuildDifferenceTree(this IComparer comparer, T obj1, T obj2, IDifferenceTreeNode comparisonContext) + public static IEnumerable TryBuildDifferenceTree(this IComparer comparer, T obj1, T obj2, IDifferenceTreeNode differenceTreeNode) { if (comparer is null) { throw new ArgumentNullException(nameof(comparer)); } - if (comparisonContext is null) + if (differenceTreeNode is null) { - throw new ArgumentNullException(nameof(comparisonContext)); + throw new ArgumentNullException(nameof(differenceTreeNode)); } - if (comparer is IDifferenceTreeBuilder contextableComparer) + if (comparer is IDifferenceTreeBuilder differenceTreeBuilder) { - var differenceTreeNodeInfoList = contextableComparer.BuildDifferenceTree(obj1, obj2, comparisonContext); + var differenceTreeNodeInfoList = differenceTreeBuilder.BuildDifferenceTree(obj1, obj2, differenceTreeNode); foreach (var differenceTreeNodeInfo in differenceTreeNodeInfoList) { @@ -90,7 +88,7 @@ public static IEnumerable TryBuildDifferenceTree(this ICo yield break; } - ThrowDifferenceTreeBuilderNotImplemented(comparisonContext, comparer.Settings, comparer, $"{nameof(IDifferenceTreeBuilder)}<{typeof(T).FullName}>"); + ThrowDifferenceTreeBuilderNotImplemented(differenceTreeNode, comparer.Settings, comparer, $"{nameof(IDifferenceTreeBuilder)}<{typeof(T).FullName}>"); var differences = comparer.CalculateDifferences(obj1, obj2); @@ -103,32 +101,32 @@ public static IEnumerable TryBuildDifferenceTree(this ICo /// /// See . /// - static bool HasDifferenceTreeImplicitRoot(IDifferenceTreeNode comparisonContext) + static bool HasDifferenceTreeImplicitRoot(IDifferenceTreeNode differenceTreeNode) { - if (comparisonContext is null) + if (differenceTreeNode is null) { - throw new ArgumentNullException(nameof(comparisonContext)); + throw new ArgumentNullException(nameof(differenceTreeNode)); } do { - if (comparisonContext.Ancestor == null && comparisonContext is ImplicitDifferenceTreeNode) + if (differenceTreeNode.Ancestor == null && differenceTreeNode is ImplicitDifferenceTreeNode) { return true; } - comparisonContext = comparisonContext.Ancestor; + differenceTreeNode = differenceTreeNode.Ancestor; - } while (comparisonContext != null); + } while (differenceTreeNode != null); return false; } - internal static void ThrowDifferenceTreeBuilderNotImplemented(IDifferenceTreeNode comparisonContext, ComparisonSettings comparisonSettings, object comparer, string unImplementedInterface) + internal static void ThrowDifferenceTreeBuilderNotImplemented(IDifferenceTreeNode differenceTreeNode, ComparisonSettings comparisonSettings, object comparer, string unImplementedInterface) { - if (comparisonContext is null) + if (differenceTreeNode is null) { - throw new ArgumentNullException(nameof(comparisonContext)); + throw new ArgumentNullException(nameof(differenceTreeNode)); } if (comparisonSettings is null) @@ -136,33 +134,33 @@ internal static void ThrowDifferenceTreeBuilderNotImplemented(IDifferenceTreeNod throw new ArgumentNullException(nameof(comparisonSettings)); } - var options = ComparisonContextOptions.Default(); - comparisonSettings.ComparisonContextOptionsAction?.Invoke(null, options); + var options = DifferenceTreeOptions.Default(); + comparisonSettings.DifferenceTreeOptionsAction?.Invoke(null, options); - if (options.ThrowContextableComparerNotImplementedEnabled == false) + if (options.ThrowDifferenceTreeBuilderNotImplementedEnabled == false) { return; } - if (comparisonSettings.ComparisonContextOptionsAction != null) + if (comparisonSettings.DifferenceTreeOptionsAction != null) { - var message = $"Because the comparison context was explicitly configured, the {comparer.GetType().FullName} must implement {unImplementedInterface} interface " + + var message = $"Because the difference tree has been explicitly configured, the {comparer.GetType().FullName} must implement {unImplementedInterface} interface " + "or throwing the DifferenceTreeBuilderNotImplementedException must be disabled."; throw new DifferenceTreeBuilderNotImplementedException(message); } if (comparisonSettings.ListComparisonOptionsAction != null) { - var message = $"Because the list comparison was explicitly configured, the {comparer.GetType().FullName} must implement {unImplementedInterface} interface " + + var message = $"Because the list comparison has bben explicitly configured, the {comparer.GetType().FullName} must implement {unImplementedInterface} interface " + "or throwing the DifferenceTreeBuilderNotImplementedException must be disabled."; throw new DifferenceTreeBuilderNotImplementedException(message); } //TODO: Check DifferenceOptionsAction - if (HasDifferenceTreeImplicitRoot(comparisonContext) == false) + if (HasDifferenceTreeImplicitRoot(differenceTreeNode) == false) { - var message = $"Because the comparison context was explicitly passed, the {comparer.GetType().FullName} must implement {unImplementedInterface} interface " + + var message = $"Because the difference tree has been explicitly passed, the {comparer.GetType().FullName} must implement {unImplementedInterface} interface " + "or throwing the DifferenceTreeBuilderNotImplementedException must be disabled."; throw new DifferenceTreeBuilderNotImplementedException(message); } diff --git a/ObjectsComparer/ObjectsComparer/DifferenceTree/DifferenceTreeNodeBase.cs b/ObjectsComparer/ObjectsComparer/DifferenceTree/DifferenceTreeNodeBase.cs index e003a61..18f5532 100644 --- a/ObjectsComparer/ObjectsComparer/DifferenceTree/DifferenceTreeNodeBase.cs +++ b/ObjectsComparer/ObjectsComparer/DifferenceTree/DifferenceTreeNodeBase.cs @@ -94,13 +94,13 @@ public IDifferenceTreeNode Shrink() { List removeDescendants = new List(); - _descendants.ForEach(descendantContext => + _descendants.ForEach(descendantNode => { - descendantContext.Shrink(); + descendantNode.Shrink(); - if (descendantContext.HasDifferences(true) == false) + if (descendantNode.HasDifferences(true) == false) { - removeDescendants.Add(descendantContext); + removeDescendants.Add(descendantNode); } }); diff --git a/ObjectsComparer/ObjectsComparer/DifferenceTree/DifferenceTreeNodeProvider.cs b/ObjectsComparer/ObjectsComparer/DifferenceTree/DifferenceTreeNodeProvider.cs new file mode 100644 index 0000000..05afc71 --- /dev/null +++ b/ObjectsComparer/ObjectsComparer/DifferenceTree/DifferenceTreeNodeProvider.cs @@ -0,0 +1,82 @@ +using System; +using System.Reflection; + +namespace ObjectsComparer +{ + public static class DifferenceTreeNodeProvider + { + public static IDifferenceTreeNode CreateRootNode() + { + return new DifferenceTreeNode(new DifferenceTreeNodeMember()); + } + + /// + /// Returns the root of the difference tree for cases where the consumer does not explicitly, directly or indirectly request the difference tree, ie the difference tree is created only as an auxiliary. + /// + public static IDifferenceTreeNode CreateImplicitRootNode(ComparisonSettings comparisonSettings) + { + _ = comparisonSettings ?? throw new ArgumentNullException(nameof(comparisonSettings)); + + return new ImplicitDifferenceTreeNode(new DifferenceTreeNodeMember()); + } + + public static IDifferenceTreeNode CreateNode(ComparisonSettings comparisonSettings, IDifferenceTreeNode ancestor) + { + return CreateNode(comparisonSettings, new DifferenceTreeNodeMember(), ancestor); + } + + public static IDifferenceTreeNode CreateNode(ComparisonSettings comparisonSettings, IDifferenceTreeNode ancestor, MemberInfo memberInfo) + { + return CreateNode(comparisonSettings, new DifferenceTreeNodeMember(memberInfo, memberInfo?.Name), ancestor); + } + + public static IDifferenceTreeNode CreateNode(ComparisonSettings comparisonSettings, IDifferenceTreeNode ancestor, string memberName) + { + return CreateNode(comparisonSettings, new DifferenceTreeNodeMember(name: memberName), ancestor); + } + + public static IDifferenceTreeNode CreateNode(ComparisonSettings comparisonSettings, IDifferenceTreeNode ancestor, MemberInfo memberInfo, string memberName) + { + return CreateNode(comparisonSettings, new DifferenceTreeNodeMember(memberInfo, memberName), ancestor); + } + + public static IDifferenceTreeNode CreateNode(ComparisonSettings comparisonSettings, IDifferenceTreeNodeMember differenceTreeNodeMember, IDifferenceTreeNode ancestor) + { + _ = comparisonSettings ?? throw new ArgumentNullException(nameof(comparisonSettings)); + _ = differenceTreeNodeMember ?? throw new ArgumentNullException(nameof(differenceTreeNodeMember)); + //_ = ancestor ?? throw new ArgumentNullException(nameof(ancestor)); + + DifferenceTreeOptions options = DifferenceTreeOptions.Default(); + comparisonSettings.DifferenceTreeOptionsAction?.Invoke(ancestor, options); + + if (options.DifferenceTreeNodeMemberFactory != null) + { + var customDifferenceTreeNodeMember = options.DifferenceTreeNodeMemberFactory.Invoke(differenceTreeNodeMember); + + if (customDifferenceTreeNodeMember == null) + { + throw new InvalidOperationException("Difference tree node member factory returned null member."); + } + + differenceTreeNodeMember = customDifferenceTreeNodeMember; + } + + if (options.DifferenceTreeNodeFactory != null) + { + var customDifferenceTreeNode = options.DifferenceTreeNodeFactory(differenceTreeNodeMember); + + if (customDifferenceTreeNode != null) + { + return customDifferenceTreeNode; + } + + if (customDifferenceTreeNode == null) + { + throw new InvalidOperationException("Difference tree node factory returned null node."); + } + } + + return new DifferenceTreeNode(differenceTreeNodeMember, ancestor); + } + } +} diff --git a/ObjectsComparer/ObjectsComparer/DifferenceTree/DifferenceTreeOptions.cs b/ObjectsComparer/ObjectsComparer/DifferenceTree/DifferenceTreeOptions.cs new file mode 100644 index 0000000..c342b58 --- /dev/null +++ b/ObjectsComparer/ObjectsComparer/DifferenceTree/DifferenceTreeOptions.cs @@ -0,0 +1,52 @@ +using System; +using ObjectsComparer.Exceptions; +using ObjectsComparer.DifferenceTreeExtensions; + +namespace ObjectsComparer +{ + public class DifferenceTreeOptions + { + DifferenceTreeOptions() + { + } + + internal static DifferenceTreeOptions Default() + { + return new DifferenceTreeOptions(); + } + + internal Func DifferenceTreeNodeFactory { get; private set; } + + internal Func DifferenceTreeNodeMemberFactory { get; private set; } + + /// + /// Factory for instances. + /// + /// + public void UseDifferenceTreeNodeFactory(Func factory) + { + DifferenceTreeNodeFactory = factory ?? throw new ArgumentNullException(nameof(factory)); + } + + /// + /// Factory for instances. + /// + public void UseDifferenceTreeNodeMemberFactory(Func factory) + { + DifferenceTreeNodeMemberFactory = factory ?? throw new ArgumentNullException(nameof(factory)); + } + + public bool ThrowDifferenceTreeBuilderNotImplementedEnabled { get; private set; } = true; + + /// + /// Whether to throw the when the user requires the difference tree but has a comparer that does not implement or . + /// Default = true. + /// + public DifferenceTreeOptions ThrowDifferenceTreeBuilderNotImplemented(bool value) + { + ThrowDifferenceTreeBuilderNotImplementedEnabled = value; + + return this; + } + } +} diff --git a/ObjectsComparer/ObjectsComparer/DifferenceTree/IDifferenceTreeNode.cs b/ObjectsComparer/ObjectsComparer/DifferenceTree/IDifferenceTreeNode.cs index d7bd0f3..8d9189f 100644 --- a/ObjectsComparer/ObjectsComparer/DifferenceTree/IDifferenceTreeNode.cs +++ b/ObjectsComparer/ObjectsComparer/DifferenceTree/IDifferenceTreeNode.cs @@ -9,52 +9,52 @@ namespace ObjectsComparer //TODO: Edit "Once the comparison process is completed, it is possible to traverse " /// - /// Context of comparison process. Each instance wraps compared , which is typically property. Each context has its ancestor and descendants the same way as its compared has its ancestor and descendant members. - /// Once the comparison process is completed, it is possible to traverse the comparison context graph and see differences at particular members. + /// Node in the difference tree. Each instance of the node wraps compared , which is typically property. Each node has its ancestor and descendants the same way as its compared has its ancestor and descendant members. + /// Once the comparison process is finished (completed or uncompleted), it is possible to traverse the difference tree and see differences at particular members. /// public interface IDifferenceTreeNode { /// - /// Ancestor context. + /// Ancestor node. /// IDifferenceTreeNode Ancestor { get; set; } /// - /// Children contexts. + /// Children nodes. /// IEnumerable Descendants { get; } /// - /// A list of differences directly related to the context. + /// A list of differences directly related to the node. /// IEnumerable Differences { get; } /// /// Compared member, for more info see . - /// It should be null for the root context (the starting point of the comparison) and for the list element context. A list element context never has a member, but it has an ancestor context which is the list and that list has its member. + /// It should be null for the root node (the starting point of the comparison) and for the list element node. A list element node never has a member, but it has an ancestor node which is the list and that list has its member. /// IDifferenceTreeNodeMember Member { get; } /// - /// Adds descendant to the context. + /// Adds descendant to the node. /// /// void AddDescendant(IDifferenceTreeNode descendant); /// - /// Adds the difference to the context. + /// Adds the difference to the node. /// /// void AddDifference(Difference difference); /// - /// Returns differences directly or indirectly related to the context. + /// Returns differences directly or indirectly related to the node. /// /// If value is true, it also looks for in . IEnumerable GetDifferences(bool recursive = true); /// - /// Whether there are differences directly or indirectly related to the context. + /// Whether there are differences directly or indirectly related to the node. /// /// If value is true, it also looks for in . bool HasDifferences(bool recursive); diff --git a/ObjectsComparer/ObjectsComparer/Exceptions/DifferenceTreeBuilderNotImplementedException.cs b/ObjectsComparer/ObjectsComparer/Exceptions/DifferenceTreeBuilderNotImplementedException.cs index f1ed98e..06771aa 100644 --- a/ObjectsComparer/ObjectsComparer/Exceptions/DifferenceTreeBuilderNotImplementedException.cs +++ b/ObjectsComparer/ObjectsComparer/Exceptions/DifferenceTreeBuilderNotImplementedException.cs @@ -5,7 +5,7 @@ namespace ObjectsComparer.Exceptions { /// /// Depending on the configuration or actual state of the comparison, this exception may be thrown when a user defined comparer does not implement or . - /// To prevent this exception from being thrown, see operation. + /// To prevent this exception from being thrown, see operation. /// public class DifferenceTreeBuilderNotImplementedException : NotImplementedException { diff --git a/ObjectsComparer/ObjectsComparer/Exceptions/ElementKeyNotFoundException.cs b/ObjectsComparer/ObjectsComparer/Exceptions/ElementKeyNotFoundException.cs index a99ca63..6708e57 100644 --- a/ObjectsComparer/ObjectsComparer/Exceptions/ElementKeyNotFoundException.cs +++ b/ObjectsComparer/ObjectsComparer/Exceptions/ElementKeyNotFoundException.cs @@ -16,10 +16,10 @@ public class ElementKeyNotFoundException : Exception /// /// An element that is missing a key. /// - internal ElementKeyNotFoundException(object keylessElement, IDifferenceTreeNode keylessElementComparisonContext, string message = ElementKeyNotFoundExceptionMsg) : base(message) + internal ElementKeyNotFoundException(object keylessElement, IDifferenceTreeNode keylessElementDifferenceTreeNode, string message = ElementKeyNotFoundExceptionMsg) : base(message) { KeylessElement = keylessElement ?? throw new ArgumentNullException(nameof(keylessElement)); - KeylessElementComparisonContext = keylessElementComparisonContext ?? throw new ArgumentNullException(nameof(keylessElementComparisonContext)); + KeylessElementDifferenceTreeNode = keylessElementDifferenceTreeNode ?? throw new ArgumentNullException(nameof(keylessElementDifferenceTreeNode)); } /// @@ -30,6 +30,6 @@ internal ElementKeyNotFoundException(object keylessElement, IDifferenceTreeNode /// /// The current in which the exception occurred. /// - public IDifferenceTreeNode KeylessElementComparisonContext { get; } + public IDifferenceTreeNode KeylessElementDifferenceTreeNode { get; } } } From ba7b91a868034921ed6fda5ee9964a78a646e263 Mon Sep 17 00:00:00 2001 From: Daniel Nemec Date: Mon, 18 Apr 2022 11:15:02 +0200 Subject: [PATCH 138/181] Rename ctx with node. --- .../Comparer_GenericEnumerableTests.cs | 4 +- .../ComparisonSettingsTests.cs | 4 +- .../DifferenceTreeNodeTests.cs | 40 +++++++++---------- ...fferenceTreeNodeSerializationExtensions.cs | 10 ++--- .../DifferenceTreeBuilderExtensions.cs | 4 +- .../DifferenceTree/DifferenceTreeNodeBase.cs | 2 +- .../DifferenceTree/IDifferenceTreeNode.cs | 10 +++-- 7 files changed, 38 insertions(+), 36 deletions(-) diff --git a/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs b/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs index 216424e..6872b3b 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs @@ -304,9 +304,9 @@ public void ClassArrayInequalityCount_CompareByKey_DoesNotThrow_ElementKeyNotFou .CompareUnequalLists(true) .CompareElementsByKey(keyOptions => keyOptions.ThrowKeyNotFound(false))); - settings.ConfigureListComparison((ctx, options) => + settings.ConfigureListComparison((currentNode, options) => { - if (ctx.Member.Name == "TrvaleAdresy") + if (currentNode.Member.Name == "TrvaleAdresy") { options.CompareElementsByKey(); } diff --git a/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs b/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs index 302f4fe..1cc55a7 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/ComparisonSettingsTests.cs @@ -79,8 +79,8 @@ public void CompareListElementsByKeyIsCorrectlySet() //Component side. var listComparisonOptions = ListComparisonOptions.Default(); - var ctx = new DifferenceTreeNode(); - settings.ListComparisonOptionsAction(ctx, listComparisonOptions); + var currentNode = new DifferenceTreeNode(); + settings.ListComparisonOptionsAction(currentNode, listComparisonOptions); var listElementComparisonByKeyOptions = ListElementComparisonByKeyOptions.Default(); listComparisonOptions.KeyOptionsAction(listElementComparisonByKeyOptions); diff --git a/ObjectsComparer/ObjectsComparer.Tests/DifferenceTreeNodeTests.cs b/ObjectsComparer/ObjectsComparer.Tests/DifferenceTreeNodeTests.cs index 1ef1d07..a2dfed5 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/DifferenceTreeNodeTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/DifferenceTreeNodeTests.cs @@ -19,18 +19,18 @@ internal class DifferenceTreeNodeTests [Test] public void DifferenceTreeNodeMember_Member_Correct_MemberName() { - var ctxMember = new DifferenceTreeNodeMember(name: "Property1"); - Assert.AreEqual("Property1", ctxMember.Name); - Assert.AreEqual(null, ctxMember.Info); + var treeNodeMember = new DifferenceTreeNodeMember(name: "Property1"); + Assert.AreEqual("Property1", treeNodeMember.Name); + Assert.AreEqual(null, treeNodeMember.Info); } [Test] public void DifferenceTreeNodeMember_Member_Correct_Member() { var memberInfo = typeof(Address).GetMember(nameof(Address.Country)).Single(); - var ctxMember = new DifferenceTreeNodeMember(memberInfo, memberInfo.Name); - Assert.AreEqual(nameof(Address.Country), ctxMember.Info.Name); - Assert.AreEqual(nameof(Address.Country), ctxMember.Name); + var treeNodeMember = new DifferenceTreeNodeMember(memberInfo, memberInfo.Name); + Assert.AreEqual(nameof(Address.Country), treeNodeMember.Info.Name); + Assert.AreEqual(nameof(Address.Country), treeNodeMember.Name); } [Test] @@ -41,33 +41,33 @@ public void CustomDifferenceTreeNode() settings.ConfigureDifferenceTree((currentNode, options) => { - options.UseDifferenceTreeNodeFactory(ctxMember => new CustomDifferenceTreeNode(ctxMember, rootNode)); + options.UseDifferenceTreeNodeFactory(treeNodeMember => new CustomDifferenceTreeNode(treeNodeMember, rootNode)); }); - var ctx = DifferenceTreeNodeProvider.CreateNode(settings, rootNode, "Property1"); + var treeNode = DifferenceTreeNodeProvider.CreateNode(settings, rootNode, "Property1"); - Assert.AreEqual("Property1", ctx.Member.Name); - Assert.IsTrue(ctx.GetType() == typeof(CustomDifferenceTreeNode)); - Assert.IsTrue(ctx.Ancestor == rootNode); + Assert.AreEqual("Property1", treeNode.Member.Name); + Assert.IsTrue(treeNode.GetType() == typeof(CustomDifferenceTreeNode)); + Assert.IsTrue(treeNode.Ancestor == rootNode); } [Test] public void CustomDifferenceTreeNodeMember() { var settings = new ComparisonSettings(); - var rootCtx = DifferenceTreeNodeProvider.CreateRootNode(); + var rootNode = DifferenceTreeNodeProvider.CreateRootNode(); settings.ConfigureDifferenceTree((currentContex, options) => { options.UseDifferenceTreeNodeMemberFactory(defaultMember => new CustomDifferenceTreeNodeMember(defaultMember.Name)); }); - var ctx = DifferenceTreeNodeProvider.CreateNode(settings, rootCtx, "Property1"); + var treeNode = DifferenceTreeNodeProvider.CreateNode(settings, rootNode, "Property1"); - Assert.AreEqual("Property1", ctx.Member.Name); - Assert.AreEqual(null, ctx.Member.Info); - Assert.IsTrue(ctx.Member.GetType() == typeof(CustomDifferenceTreeNodeMember)); - Assert.IsTrue(ctx.Ancestor == rootCtx); + Assert.AreEqual("Property1", treeNode.Member.Name); + Assert.AreEqual(null, treeNode.Member.Info); + Assert.IsTrue(treeNode.Member.GetType() == typeof(CustomDifferenceTreeNodeMember)); + Assert.IsTrue(treeNode.Ancestor == rootNode); } [Test] @@ -75,8 +75,8 @@ public void TestThrowDifferenceTreeBuilderNotImplementedException() { var factory = new CustomComparersFactory(); var comparer = factory.GetObjectsComparer(); - var rootCtx = DifferenceTreeNodeProvider.CreateRootNode(); - Assert.Throws(() => comparer.TryBuildDifferenceTree("hello", "hi", rootCtx).ToArray()); + var rootNode = DifferenceTreeNodeProvider.CreateRootNode(); + Assert.Throws(() => comparer.TryBuildDifferenceTree("hello", "hi", rootNode).ToArray()); } [Test] @@ -115,7 +115,7 @@ public void EnumerateConditional_Completed() } [Test] - public void EnumerateConditional_FetchOne_NotCompleted() + public void EnumerateConditional_FetchFirst_NotCompleted() { var list = new List { 6, 8, 79, 3, 45, 9 }; bool completed = false; diff --git a/ObjectsComparer/ObjectsComparer.Tests/Utils/DifferenceTreeNodeSerializationExtensions.cs b/ObjectsComparer/ObjectsComparer.Tests/Utils/DifferenceTreeNodeSerializationExtensions.cs index 2e296a7..cdac08f 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/Utils/DifferenceTreeNodeSerializationExtensions.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/Utils/DifferenceTreeNodeSerializationExtensions.cs @@ -81,26 +81,26 @@ protected override JsonProperty CreateProperty(MemberInfo member, MemberSerializ property.ShouldSerialize = instance => { - DifferenceTreeNode ctx = (DifferenceTreeNode)instance; + DifferenceTreeNode treeNode = (DifferenceTreeNode)instance; if (property.PropertyName == nameof(DifferenceTreeNode.Descendants)) { - return _skipEmptyList == false || ctx.Descendants.Any(); + return _skipEmptyList == false || treeNode.Descendants.Any(); } if (property.PropertyName == nameof(DifferenceTreeNode.Differences)) { - return _skipEmptyList == false || ctx.Differences.Any(); + return _skipEmptyList == false || treeNode.Differences.Any(); } if (property.PropertyName == nameof(DifferenceTreeNode.Member)) { - return _skipNullReference == false || ctx.Member != null; + return _skipNullReference == false || treeNode.Member != null; } if (property.PropertyName == nameof(DifferenceTreeNode.Ancestor)) { - return _skipNullReference == false || ctx.Ancestor != null; + return _skipNullReference == false || treeNode.Ancestor != null; } return true; diff --git a/ObjectsComparer/ObjectsComparer/DifferenceTree/DifferenceTreeBuilderExtensions.cs b/ObjectsComparer/ObjectsComparer/DifferenceTree/DifferenceTreeBuilderExtensions.cs index 046869f..5b04380 100644 --- a/ObjectsComparer/ObjectsComparer/DifferenceTree/DifferenceTreeBuilderExtensions.cs +++ b/ObjectsComparer/ObjectsComparer/DifferenceTree/DifferenceTreeBuilderExtensions.cs @@ -15,7 +15,7 @@ public static class DifferenceTreeBuilderExtensions /// It throws exception if necessary.
/// Intended for implementers. To avoid side effects, consumers should call extension method instead. /// - /// The differences with its eventual location in the difference tree. + /// The differences with their eventual location in the difference tree. public static IEnumerable TryBuildDifferenceTree(this IComparer comparer, Type type, object obj1, object obj2, IDifferenceTreeNode currentNode) { if (comparer is null) @@ -63,7 +63,7 @@ public static IEnumerable TryBuildDifferenceTree(this ICompa /// It throws exception if necessary.
/// Intended for implementers. To avoid side effects, consumers should call extension method instead. /// - /// The differences with its eventual location in the difference tree. + /// The differences with their eventual location in the difference tree. public static IEnumerable TryBuildDifferenceTree(this IComparer comparer, T obj1, T obj2, IDifferenceTreeNode differenceTreeNode) { if (comparer is null) diff --git a/ObjectsComparer/ObjectsComparer/DifferenceTree/DifferenceTreeNodeBase.cs b/ObjectsComparer/ObjectsComparer/DifferenceTree/DifferenceTreeNodeBase.cs index 18f5532..9c46d85 100644 --- a/ObjectsComparer/ObjectsComparer/DifferenceTree/DifferenceTreeNodeBase.cs +++ b/ObjectsComparer/ObjectsComparer/DifferenceTree/DifferenceTreeNodeBase.cs @@ -104,7 +104,7 @@ public IDifferenceTreeNode Shrink() } }); - _descendants.RemoveAll(ctx => removeDescendants.Contains(ctx)); + _descendants.RemoveAll(descendantTreeNode => removeDescendants.Contains(descendantTreeNode )); return this; } diff --git a/ObjectsComparer/ObjectsComparer/DifferenceTree/IDifferenceTreeNode.cs b/ObjectsComparer/ObjectsComparer/DifferenceTree/IDifferenceTreeNode.cs index 8d9189f..1d3746c 100644 --- a/ObjectsComparer/ObjectsComparer/DifferenceTree/IDifferenceTreeNode.cs +++ b/ObjectsComparer/ObjectsComparer/DifferenceTree/IDifferenceTreeNode.cs @@ -6,12 +6,14 @@ namespace ObjectsComparer { - //TODO: Edit "Once the comparison process is completed, it is possible to traverse " - /// - /// Node in the difference tree. Each instance of the node wraps compared , which is typically property. Each node has its ancestor and descendants the same way as its compared has its ancestor and descendant members. - /// Once the comparison process is finished (completed or uncompleted), it is possible to traverse the difference tree and see differences at particular members. + /// Node in the difference tree. /// + /// + /// Each instance of the node wraps compared , which is typically a property. Each node has its ancestor and descendants the same way as its compared has its ancestor and descendant members.
+ /// Once the calculation of the difference tree is finished (completed or uncompleted), it is possible to traverse the difference tree and see differences at particular members.
+ /// For more about calculation of the difference tree see or . + ///
public interface IDifferenceTreeNode { /// From 9089fc8e7d9b022934535aec877ab27d05b8e568 Mon Sep 17 00:00:00 2001 From: Daniel Nemec Date: Tue, 19 Apr 2022 08:51:31 +0200 Subject: [PATCH 139/181] Edit comments. --- .../DifferenceTree/DifferenceLocation.cs | 5 ++++- .../DifferenceTreeBuilderExtensions.cs | 16 ++++++++-------- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/ObjectsComparer/ObjectsComparer/DifferenceTree/DifferenceLocation.cs b/ObjectsComparer/ObjectsComparer/DifferenceTree/DifferenceLocation.cs index 895247e..c0b1091 100644 --- a/ObjectsComparer/ObjectsComparer/DifferenceTree/DifferenceLocation.cs +++ b/ObjectsComparer/ObjectsComparer/DifferenceTree/DifferenceLocation.cs @@ -14,7 +14,10 @@ public DifferenceLocation(Difference difference, IDifferenceTreeNode treeNode = } public Difference Difference { get; } - + + /// + /// Optional. Returns null, if no location is specified (probably by a builder who does not implement ). + /// public IDifferenceTreeNode TreeNode { get; } } } \ No newline at end of file diff --git a/ObjectsComparer/ObjectsComparer/DifferenceTree/DifferenceTreeBuilderExtensions.cs b/ObjectsComparer/ObjectsComparer/DifferenceTree/DifferenceTreeBuilderExtensions.cs index 5b04380..05f7645 100644 --- a/ObjectsComparer/ObjectsComparer/DifferenceTree/DifferenceTreeBuilderExtensions.cs +++ b/ObjectsComparer/ObjectsComparer/DifferenceTree/DifferenceTreeBuilderExtensions.cs @@ -12,11 +12,11 @@ public static class DifferenceTreeBuilderExtensions /// /// /// If is , it builds the difference tree. If not, it only builds the flat list of differences. - /// It throws exception if necessary.
- /// Intended for implementers. To avoid side effects, consumers should call extension method instead. + /// It throws if necessary.
+ /// Intended for implementers. To avoid side effects, consumers should instead call extension method. ///
/// The differences with their eventual location in the difference tree. - public static IEnumerable TryBuildDifferenceTree(this IComparer comparer, Type type, object obj1, object obj2, IDifferenceTreeNode currentNode) + public static IEnumerable TryBuildDifferenceTree(this IComparer comparer, Type type, object obj1, object obj2, IDifferenceTreeNode differenceTreeNode) { if (comparer is null) { @@ -28,14 +28,14 @@ public static IEnumerable TryBuildDifferenceTree(this ICompa throw new ArgumentNullException(nameof(type)); } - if (currentNode is null) + if (differenceTreeNode is null) { - throw new ArgumentNullException(nameof(currentNode)); + throw new ArgumentNullException(nameof(differenceTreeNode)); } if (comparer is IDifferenceTreeBuilder differenceTreeBuilder) { - var differenceNodeLocationList = differenceTreeBuilder.BuildDifferenceTree(type, obj1, obj2, currentNode); + var differenceNodeLocationList = differenceTreeBuilder.BuildDifferenceTree(type, obj1, obj2, differenceTreeNode); foreach (var differenceNodeLocation in differenceNodeLocationList) { @@ -45,7 +45,7 @@ public static IEnumerable TryBuildDifferenceTree(this ICompa yield break; } - ThrowDifferenceTreeBuilderNotImplemented(currentNode, comparer.Settings, comparer, nameof(IDifferenceTreeBuilder)); + ThrowDifferenceTreeBuilderNotImplemented(differenceTreeNode, comparer.Settings, comparer, nameof(IDifferenceTreeBuilder)); var differences = comparer.CalculateDifferences(type, obj1, obj2); @@ -60,7 +60,7 @@ public static IEnumerable TryBuildDifferenceTree(this ICompa ///
/// /// If is , it builds the difference tree. If not, it only builds the flat list of differences. - /// It throws exception if necessary.
+ /// It throws if necessary.
/// Intended for implementers. To avoid side effects, consumers should call extension method instead. ///
/// The differences with their eventual location in the difference tree. From 7bba6cf310194ab4d1b99333b2728eb05a1ad74c Mon Sep 17 00:00:00 2001 From: Daniel Nemec Date: Wed, 20 Apr 2022 08:55:01 +0200 Subject: [PATCH 140/181] Edit comments. --- .../ObjectsComparer/DifferenceTree/ComparerExtensions.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ObjectsComparer/ObjectsComparer/DifferenceTree/ComparerExtensions.cs b/ObjectsComparer/ObjectsComparer/DifferenceTree/ComparerExtensions.cs index b62647d..571dc75 100644 --- a/ObjectsComparer/ObjectsComparer/DifferenceTree/ComparerExtensions.cs +++ b/ObjectsComparer/ObjectsComparer/DifferenceTree/ComparerExtensions.cs @@ -12,8 +12,8 @@ public static class ComparerExtensions /// /// Calculates the difference tree. /// - /// Current comparison context. The return value tells whether to look for another difference. If the argument is null the process is looking for all the differences. - /// If the comparison process has been completed, this action will be invoked. + /// Current comparison context. The return value tells the comparison process whether to look for another difference. If the argument is null the process is looking for all the differences. + /// Occurs when the comparison process reaches the last member of the objects being compared. /// The root node of the difference tree. public static IDifferenceTreeNode CalculateDifferenceTree(this IComparer comparer, Type type, object obj1, object obj2, Func findNextDifference = null, Action differenceTreeCompleted = null) { @@ -47,8 +47,8 @@ public static IDifferenceTreeNode CalculateDifferenceTree(this IComparer compare /// /// Calculates the difference tree. /// - /// Current comparison context. The return value tells whether to look for another difference. - /// If the comparison process has been completed, this action will be invoked. + /// Current comparison context. The return value tells the comparison process whether to look for another difference. If the argument is null the process is looking for all the differences. + /// Occurs when the comparison process reaches the last member of the objects being compared. /// The root node of the difference tree. public static IDifferenceTreeNode CalculateDifferenceTree(this IComparer comparer, T obj1, T obj2, Func findNextDifference = null, Action differenceTreeCompleted = null) { From 9cc6cb67cb09579ca10ddfa734bc52ed2c7eeaef Mon Sep 17 00:00:00 2001 From: nemec Date: Wed, 27 Apr 2022 16:21:11 +0200 Subject: [PATCH 141/181] Simplify null check. --- .../DifferenceTree/ComparerExtensions.cs | 7 ++-- .../DifferenceTreeBuilderExtensions.cs | 39 ++++--------------- 2 files changed, 11 insertions(+), 35 deletions(-) diff --git a/ObjectsComparer/ObjectsComparer/DifferenceTree/ComparerExtensions.cs b/ObjectsComparer/ObjectsComparer/DifferenceTree/ComparerExtensions.cs index 571dc75..29f9f83 100644 --- a/ObjectsComparer/ObjectsComparer/DifferenceTree/ComparerExtensions.cs +++ b/ObjectsComparer/ObjectsComparer/DifferenceTree/ComparerExtensions.cs @@ -13,7 +13,7 @@ public static class ComparerExtensions /// Calculates the difference tree. /// /// Current comparison context. The return value tells the comparison process whether to look for another difference. If the argument is null the process is looking for all the differences. - /// Occurs when the comparison process reaches the last member of the objects being compared. + /// Occurs when (and only when) the comparison process reaches the last member of the objects being compared. /// The root node of the difference tree. public static IDifferenceTreeNode CalculateDifferenceTree(this IComparer comparer, Type type, object obj1, object obj2, Func findNextDifference = null, Action differenceTreeCompleted = null) { @@ -29,7 +29,7 @@ public static IDifferenceTreeNode CalculateDifferenceTree(this IComparer compare findNextDifference = findNextDifference ?? ((_) => true); - //Anything but ImplicitComparisonContext (ImplicitDifferenceTreeNode). + //Anything but ImplicitDifferenceTreeNode. var rootNode = DifferenceTreeNodeProvider.CreateNode(comparer.Settings, ancestor: null); var differenceLocationList = comparer.TryBuildDifferenceTree(type, obj1, obj2, rootNode); @@ -48,7 +48,7 @@ public static IDifferenceTreeNode CalculateDifferenceTree(this IComparer compare /// Calculates the difference tree. /// /// Current comparison context. The return value tells the comparison process whether to look for another difference. If the argument is null the process is looking for all the differences. - /// Occurs when the comparison process reaches the last member of the objects being compared. + /// Occurs when (and only when) the comparison process reaches the last member of the objects being compared. /// The root node of the difference tree. public static IDifferenceTreeNode CalculateDifferenceTree(this IComparer comparer, T obj1, T obj2, Func findNextDifference = null, Action differenceTreeCompleted = null) { @@ -59,6 +59,7 @@ public static IDifferenceTreeNode CalculateDifferenceTree(this IComparer c findNextDifference = findNextDifference ?? ((_) => true); + //Anything but ImplicitDifferenceTreeNode. var rootNode = DifferenceTreeNodeProvider.CreateNode(comparer.Settings, ancestor: null); var differenceLocationList = comparer.TryBuildDifferenceTree(obj1, obj2, rootNode); diff --git a/ObjectsComparer/ObjectsComparer/DifferenceTree/DifferenceTreeBuilderExtensions.cs b/ObjectsComparer/ObjectsComparer/DifferenceTree/DifferenceTreeBuilderExtensions.cs index 05f7645..5783860 100644 --- a/ObjectsComparer/ObjectsComparer/DifferenceTree/DifferenceTreeBuilderExtensions.cs +++ b/ObjectsComparer/ObjectsComparer/DifferenceTree/DifferenceTreeBuilderExtensions.cs @@ -18,20 +18,9 @@ public static class DifferenceTreeBuilderExtensions /// The differences with their eventual location in the difference tree. public static IEnumerable TryBuildDifferenceTree(this IComparer comparer, Type type, object obj1, object obj2, IDifferenceTreeNode differenceTreeNode) { - if (comparer is null) - { - throw new ArgumentNullException(nameof(comparer)); - } - - if (type is null) - { - throw new ArgumentNullException(nameof(type)); - } - - if (differenceTreeNode is null) - { - throw new ArgumentNullException(nameof(differenceTreeNode)); - } + _ = comparer ?? throw new ArgumentNullException(nameof(comparer)); + _ = type ?? throw new ArgumentNullException(nameof(type)); + _ = differenceTreeNode ?? throw new ArgumentNullException(nameof(differenceTreeNode)); if (comparer is IDifferenceTreeBuilder differenceTreeBuilder) { @@ -66,15 +55,8 @@ public static IEnumerable TryBuildDifferenceTree(this ICompa /// The differences with their eventual location in the difference tree. public static IEnumerable TryBuildDifferenceTree(this IComparer comparer, T obj1, T obj2, IDifferenceTreeNode differenceTreeNode) { - if (comparer is null) - { - throw new ArgumentNullException(nameof(comparer)); - } - - if (differenceTreeNode is null) - { - throw new ArgumentNullException(nameof(differenceTreeNode)); - } + _ = comparer ?? throw new ArgumentNullException(nameof(comparer)); + _ = differenceTreeNode ?? throw new ArgumentNullException(nameof(differenceTreeNode)); if (comparer is IDifferenceTreeBuilder differenceTreeBuilder) { @@ -124,15 +106,8 @@ static bool HasDifferenceTreeImplicitRoot(IDifferenceTreeNode differenceTreeNode internal static void ThrowDifferenceTreeBuilderNotImplemented(IDifferenceTreeNode differenceTreeNode, ComparisonSettings comparisonSettings, object comparer, string unImplementedInterface) { - if (differenceTreeNode is null) - { - throw new ArgumentNullException(nameof(differenceTreeNode)); - } - - if (comparisonSettings is null) - { - throw new ArgumentNullException(nameof(comparisonSettings)); - } + _ = differenceTreeNode ?? throw new ArgumentNullException(nameof(differenceTreeNode)); + _ = comparisonSettings ?? throw new ArgumentNullException(nameof(comparisonSettings)); var options = DifferenceTreeOptions.Default(); comparisonSettings.DifferenceTreeOptionsAction?.Invoke(null, options); From 68ca01b6f91649baa2de8a551a8dcdfd856adf25 Mon Sep 17 00:00:00 2001 From: Daniel Nemec Date: Sun, 1 May 2022 12:09:18 +0200 Subject: [PATCH 142/181] Change the Shrink operaton as void. --- .../ObjectsComparer/DifferenceTree/DifferenceTreeNodeBase.cs | 4 +--- .../ObjectsComparer/DifferenceTree/IDifferenceTreeNode.cs | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/ObjectsComparer/ObjectsComparer/DifferenceTree/DifferenceTreeNodeBase.cs b/ObjectsComparer/ObjectsComparer/DifferenceTree/DifferenceTreeNodeBase.cs index 9c46d85..db104ac 100644 --- a/ObjectsComparer/ObjectsComparer/DifferenceTree/DifferenceTreeNodeBase.cs +++ b/ObjectsComparer/ObjectsComparer/DifferenceTree/DifferenceTreeNodeBase.cs @@ -90,7 +90,7 @@ public bool HasDifferences(bool recursive) return GetDifferences(recursive).Any(); } - public IDifferenceTreeNode Shrink() + public void Shrink() { List removeDescendants = new List(); @@ -105,8 +105,6 @@ public IDifferenceTreeNode Shrink() }); _descendants.RemoveAll(descendantTreeNode => removeDescendants.Contains(descendantTreeNode )); - - return this; } } } diff --git a/ObjectsComparer/ObjectsComparer/DifferenceTree/IDifferenceTreeNode.cs b/ObjectsComparer/ObjectsComparer/DifferenceTree/IDifferenceTreeNode.cs index 1d3746c..37d36ab 100644 --- a/ObjectsComparer/ObjectsComparer/DifferenceTree/IDifferenceTreeNode.cs +++ b/ObjectsComparer/ObjectsComparer/DifferenceTree/IDifferenceTreeNode.cs @@ -64,6 +64,6 @@ public interface IDifferenceTreeNode /// /// Removes all which have no directly or indirectly in their . /// - IDifferenceTreeNode Shrink(); + void Shrink(); } } From 13d547a7ae0a91933c8c0649d9b4ce4eff157f57 Mon Sep 17 00:00:00 2001 From: Daniel Nemec Date: Mon, 2 May 2022 14:28:08 +0200 Subject: [PATCH 143/181] Edit comments. --- .../ObjectsComparer/DifferenceTree/ComparerExtensions.cs | 3 +-- .../DifferenceTree/DifferenceTreeBuilderExtensions.cs | 4 ++-- .../DifferenceTreeBuilderNotImplementedException.cs | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/ObjectsComparer/ObjectsComparer/DifferenceTree/ComparerExtensions.cs b/ObjectsComparer/ObjectsComparer/DifferenceTree/ComparerExtensions.cs index 29f9f83..dfe597a 100644 --- a/ObjectsComparer/ObjectsComparer/DifferenceTree/ComparerExtensions.cs +++ b/ObjectsComparer/ObjectsComparer/DifferenceTree/ComparerExtensions.cs @@ -6,13 +6,12 @@ namespace ObjectsComparer { - public static class ComparerExtensions { /// /// Calculates the difference tree. /// - /// Current comparison context. The return value tells the comparison process whether to look for another difference. If the argument is null the process is looking for all the differences. + /// Current comparison context, see . The return value tells the comparison process whether to look for another difference. If the argument is null the process is looking for all the differences. /// Occurs when (and only when) the comparison process reaches the last member of the objects being compared. /// The root node of the difference tree. public static IDifferenceTreeNode CalculateDifferenceTree(this IComparer comparer, Type type, object obj1, object obj2, Func findNextDifference = null, Action differenceTreeCompleted = null) diff --git a/ObjectsComparer/ObjectsComparer/DifferenceTree/DifferenceTreeBuilderExtensions.cs b/ObjectsComparer/ObjectsComparer/DifferenceTree/DifferenceTreeBuilderExtensions.cs index 5783860..d48674a 100644 --- a/ObjectsComparer/ObjectsComparer/DifferenceTree/DifferenceTreeBuilderExtensions.cs +++ b/ObjectsComparer/ObjectsComparer/DifferenceTree/DifferenceTreeBuilderExtensions.cs @@ -12,10 +12,10 @@ public static class DifferenceTreeBuilderExtensions /// /// /// If is , it builds the difference tree. If not, it only builds the flat list of differences. - /// It throws if necessary.
/// Intended for implementers. To avoid side effects, consumers should instead call extension method. ///
/// The differences with their eventual location in the difference tree. + /// For more info see . public static IEnumerable TryBuildDifferenceTree(this IComparer comparer, Type type, object obj1, object obj2, IDifferenceTreeNode differenceTreeNode) { _ = comparer ?? throw new ArgumentNullException(nameof(comparer)); @@ -49,10 +49,10 @@ public static IEnumerable TryBuildDifferenceTree(this ICompa /// /// /// If is , it builds the difference tree. If not, it only builds the flat list of differences. - /// It throws if necessary.
/// Intended for implementers. To avoid side effects, consumers should call extension method instead. ///
/// The differences with their eventual location in the difference tree. + /// For more info see . public static IEnumerable TryBuildDifferenceTree(this IComparer comparer, T obj1, T obj2, IDifferenceTreeNode differenceTreeNode) { _ = comparer ?? throw new ArgumentNullException(nameof(comparer)); diff --git a/ObjectsComparer/ObjectsComparer/Exceptions/DifferenceTreeBuilderNotImplementedException.cs b/ObjectsComparer/ObjectsComparer/Exceptions/DifferenceTreeBuilderNotImplementedException.cs index 06771aa..70d6686 100644 --- a/ObjectsComparer/ObjectsComparer/Exceptions/DifferenceTreeBuilderNotImplementedException.cs +++ b/ObjectsComparer/ObjectsComparer/Exceptions/DifferenceTreeBuilderNotImplementedException.cs @@ -4,7 +4,7 @@ namespace ObjectsComparer.Exceptions { /// - /// Depending on the configuration or actual state of the comparison, this exception may be thrown when a user defined comparer does not implement or . + /// Depending on the configuration or actual state of the comparison process, this exception may be thrown when a user defined comparer does not implement or . /// To prevent this exception from being thrown, see operation. /// public class DifferenceTreeBuilderNotImplementedException : NotImplementedException From 87e43ed9adbcbdf5200930e21508ed8aa09fe2ee Mon Sep 17 00:00:00 2001 From: Daniel Nemec Date: Wed, 4 May 2022 08:50:08 +0200 Subject: [PATCH 144/181] Edit comment. --- .../ObjectsComparer/DifferenceTree/DifferenceLocation.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ObjectsComparer/ObjectsComparer/DifferenceTree/DifferenceLocation.cs b/ObjectsComparer/ObjectsComparer/DifferenceTree/DifferenceLocation.cs index c0b1091..00da2a6 100644 --- a/ObjectsComparer/ObjectsComparer/DifferenceTree/DifferenceLocation.cs +++ b/ObjectsComparer/ObjectsComparer/DifferenceTree/DifferenceLocation.cs @@ -16,7 +16,7 @@ public DifferenceLocation(Difference difference, IDifferenceTreeNode treeNode = public Difference Difference { get; } /// - /// Optional. Returns null, if no location is specified (probably by a builder who does not implement ). + /// Optional. Returns null, if no location is specified (probably by a comparer who does not implement ). /// public IDifferenceTreeNode TreeNode { get; } } From e8823d0965da84e9829319093894d6613a1cbda3 Mon Sep 17 00:00:00 2001 From: Daniel Nemec Date: Fri, 6 May 2022 07:32:54 +0200 Subject: [PATCH 145/181] Test commit. --- .../ObjectsComparer.Tests/DifferenceTreeNodeTests.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ObjectsComparer/ObjectsComparer.Tests/DifferenceTreeNodeTests.cs b/ObjectsComparer/ObjectsComparer.Tests/DifferenceTreeNodeTests.cs index a2dfed5..b429f00 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/DifferenceTreeNodeTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/DifferenceTreeNodeTests.cs @@ -195,4 +195,6 @@ public CustomDifferenceTreeNodeMember(string memberName) public string Name { get; } } + + //Test commit. } From 784f88bfba7e66f2e154fb1c4a56ad808a884a86 Mon Sep 17 00:00:00 2001 From: Daniel Nemec Date: Sat, 7 May 2022 17:07:56 +0200 Subject: [PATCH 146/181] AbstractDynamicObjectsComprer.BuildDifferenceTree: Correct the bug in hierarchy. Related tests added. --- .../Comparer_CompilerGeneratedObjectsTests.cs | 48 +++++++++++++++++++ ...fferenceTreeNodeSerializationExtensions.cs | 2 - .../AbstractDynamicObjectsComprer.cs | 2 +- 3 files changed, 49 insertions(+), 3 deletions(-) diff --git a/ObjectsComparer/ObjectsComparer.Tests/Comparer_CompilerGeneratedObjectsTests.cs b/ObjectsComparer/ObjectsComparer.Tests/Comparer_CompilerGeneratedObjectsTests.cs index 1f18800..268e694 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/Comparer_CompilerGeneratedObjectsTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/Comparer_CompilerGeneratedObjectsTests.cs @@ -35,6 +35,32 @@ public void DifferentValues() Assert.IsTrue(differences.Any(d => d.MemberPath == "Field3" && d.Value1 == "True" && d.Value2 == "False")); } + [Test] + public void DifferentValues_CalculateDifferenceTree() + { + dynamic a1 = new + { + Field1 = "A", + Field2 = 5, + Field3 = true + }; + dynamic a2 = new + { + Field1 = "B", + Field2 = 8, + Field3 = false + }; + var comparer = new Comparer(); + + var rootNode = comparer.CalculateDifferenceTree(typeof(object), (object)a1, (object)a2); + var differences = rootNode.GetDifferences().ToList(); + + Assert.AreEqual(3, differences.Count); + Assert.IsTrue(differences.Any(d => d.MemberPath == "Field1" && d.Value1 == "A" && d.Value2 == "B")); + Assert.IsTrue(differences.Any(d => d.MemberPath == "Field2" && d.Value1 == "5" && d.Value2 == "8")); + Assert.IsTrue(differences.Any(d => d.MemberPath == "Field3" && d.Value1 == "True" && d.Value2 == "False")); + } + [Test] public void MissedFields() { @@ -131,6 +157,28 @@ public void Hierarchy() Assert.IsTrue(differences.Any(d => d.MemberPath == "Field1.FieldSub1" && d.Value1 == "10" && d.Value2 == "8")); } + [Test] + public void Hierarchy_CalculateDifferenceTree() + { + dynamic a1Sub1 = new { FieldSub1 = 10 }; + dynamic a1 = new { Field1 = a1Sub1 }; + dynamic a2Sub1 = new { FieldSub1 = 8 }; + dynamic a2 = new { Field1 = a2Sub1 }; + var comparer = new Comparer(); + + var rootNode = comparer.CalculateDifferenceTree(typeof(object), (object)a1, (object)a2); + var differences = rootNode.GetDifferences().ToList(); + + Assert.AreEqual(1, differences.Count); + Assert.IsTrue(differences.Any(d => d.MemberPath == "Field1.FieldSub1" && d.Value1 == "10" && d.Value2 == "8")); + + var field1 = rootNode.Descendants.First(); + var fieldSub1 = field1.Descendants.First(); + + Assert.IsTrue(differences.Any(d => d.MemberPath == $"{field1.Member.Name}.{fieldSub1.Member.Name}" && d.Value1 == "10" && d.Value2 == "8")); + Assert.IsTrue(differences.Any(d => d.MemberPath == $"{field1.Member.Info.Name}.{fieldSub1.Member.Info.Name}" && d.Value1 == "10" && d.Value2 == "8")); + } + [Test] public void DifferentTypes() { diff --git a/ObjectsComparer/ObjectsComparer.Tests/Utils/DifferenceTreeNodeSerializationExtensions.cs b/ObjectsComparer/ObjectsComparer.Tests/Utils/DifferenceTreeNodeSerializationExtensions.cs index cdac08f..75b423e 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/Utils/DifferenceTreeNodeSerializationExtensions.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/Utils/DifferenceTreeNodeSerializationExtensions.cs @@ -9,8 +9,6 @@ namespace ObjectsComparer.Tests.Utils { - //TODO: Move ToJson to Core. - internal static class DifferenceTreeNodeSerializationExtensions { /// diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractDynamicObjectsComprer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractDynamicObjectsComprer.cs index 330b20a..12a028a 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractDynamicObjectsComprer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractDynamicObjectsComprer.cs @@ -146,7 +146,7 @@ IEnumerable IDifferenceTreeBuilder.BuildDifferenceTree(Type } var comparer = Factory.GetObjectsComparer(propertyType, Settings, this); - foreach (var failure in comparer.TryBuildDifferenceTree(propertyType, value1, value2, differenceTreeNode)) + foreach (var failure in comparer.TryBuildDifferenceTree(propertyType, value1, value2, keyDifferenceTreeNode)) { failure.Difference.InsertPath(propertyKey); yield return failure; From 08bf417d2ca100adedd838662a3910f6fd83b523 Mon Sep 17 00:00:00 2001 From: Daniel Nemec Date: Sun, 8 May 2022 00:42:13 +0200 Subject: [PATCH 147/181] Add sample test methods for PR. --- .../Comparer_GenericEnumerableTests.cs | 148 ++++++++++++++++++ .../DifferenceTreeNodeTests.cs | 16 ++ .../ObjectsComparer.Tests/TestClasses/A.cs | 2 + .../ObjectsComparer.Tests/TestClasses/B.cs | 2 + .../ListElementKeyProviderArgs.cs | 1 - 5 files changed, 168 insertions(+), 1 deletion(-) diff --git a/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs b/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs index 6872b3b..86b2b87 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs @@ -1442,5 +1442,153 @@ public void DictionaryInequalityDifferentValue_CompareByKey_FormatElementKey() Assert.AreEqual("Two!", differences.First().Value2); Assert.AreEqual("[Key=2].Value", differences.First().MemberPath); } + + [Test] + public void CompareEnumerables_DefaultBehavior() + { + var a1 = new int[] { 3, 2, 1 }; + var a2 = new int[] { 1, 2, 3, 4 }; + + var comparer = new Comparer(); + var differences = comparer.CalculateDifferences(a1, a2).ToArray(); + + Assert.IsTrue(differences.Count() == 1); + Assert.AreEqual(DifferenceTypes.ValueMismatch, differences[0].DifferenceType); + Assert.AreEqual("Length", differences[0].MemberPath); + Assert.AreEqual("3", differences[0].Value1); + Assert.AreEqual("4", differences[0].Value2); + } + + [Test] + public void CompareEnumerables_UnequalListEnabled() + { + var a1 = new int[] { 3, 2, 1 }; + var a2 = new int[] { 1, 2, 3, 4 }; + + var settings = new ComparisonSettings(); + settings.ConfigureListComparison(compareUnequalLists: true); + var comparer = new Comparer(settings); + var differences = comparer.CalculateDifferences(a1, a2).ToArray(); + + Assert.IsTrue(differences.Count() == 4); + Assert.IsTrue(differences.Any(d => d.DifferenceType == DifferenceTypes.ValueMismatch && d.MemberPath == "[0]" && d.Value1 == "3" && d.Value2 == "1")); + Assert.IsTrue(differences.Any(d => d.DifferenceType == DifferenceTypes.ValueMismatch && d.MemberPath == "[2]" && d.Value1 == "1" && d.Value2 == "3")); + Assert.IsTrue(differences.Any(d => d.DifferenceType == DifferenceTypes.MissedElementInFirstObject && d.MemberPath == "[3]" && d.Value1 == "" && d.Value2 == "4")); + Assert.IsTrue(differences.Any(d => d.DifferenceType == DifferenceTypes.ValueMismatch && d.MemberPath == "Length" && d.Value1 == "3" && d.Value2 == "4")); + } + + [Test] + public void CompareIntArrayByKey() + { + var a1 = new int[] { 3, 2, 1 }; + var a2 = new int[] { 1, 2, 3, 4 }; + + var settings = new ComparisonSettings(); + settings.ConfigureListComparison(compareElementsByKey: true, compareUnequalLists: true); + var comparer = new Comparer(settings); + var differences = comparer.CalculateDifferences(a1, a2).ToArray(); + + Assert.IsTrue(differences.Count() == 2); + Assert.IsTrue(differences.Any(d => d.DifferenceType == DifferenceTypes.MissedElementInFirstObject && d.MemberPath == "[4]" && d.Value1 == "" && d.Value2 == "4")); + Assert.IsTrue(differences.Any(d => d.DifferenceType == DifferenceTypes.ValueMismatch && d.MemberPath == "Length" && d.Value1 == "3" && d.Value2 == "4")); + } + + [Test] + public void CompareIntArrayByKeyDisplayIndex() + { + var a1 = new int[] { 3, 2, 1 }; + var a2 = new int[] { 1, 2, 3, 4 }; + + var settings = new ComparisonSettings(); + + settings.ConfigureListComparison(listOptions => + { + listOptions + .CompareUnequalLists(true) + .CompareElementsByKey(keyOptions => + { + keyOptions.FormatElementKey(args => args.ElementIndex.ToString()); + }); + }); + + var comparer = new Comparer(settings); + var differences = comparer.CalculateDifferences(a1, a2).ToArray(); + + Assert.IsTrue(differences.Count() == 2); + Assert.IsTrue(differences.Any(d => d.DifferenceType == DifferenceTypes.MissedElementInFirstObject && d.MemberPath == "[3]" && d.Value1 == "" && d.Value2 == "4")); + Assert.IsTrue(differences.Any(d => d.DifferenceType == DifferenceTypes.ValueMismatch && d.MemberPath == "Length" && d.Value1 == "3" && d.Value2 == "4")); + } + + [Test] + public void CompareObjectListByKey() + { + var a1 = new A { ListOfB = new List { new B { Id = 1, Property1 = "Value 1" }, new B { Id = 2, Property1 = "Value 2" } } }; + var a2 = new A { ListOfB = new List { new B { Id = 2, Property1 = "Value two" }, new B { Id = 1, Property1 = "Value one" } } }; + + var settings = new ComparisonSettings(); + settings.ConfigureListComparison(compareElementsByKey: true); + var comparer = new Comparer(settings); + var differences = comparer.CalculateDifferences(a1, a2).ToArray(); + + Assert.IsTrue(differences.Count() == 2); + Assert.IsTrue(differences.Any(d => d.DifferenceType == DifferenceTypes.ValueMismatch && d.MemberPath == "ListOfB[1].Property1" && d.Value1 == "Value 1" && d.Value2 == "Value one")); + Assert.IsTrue(differences.Any(d => d.DifferenceType == DifferenceTypes.ValueMismatch && d.MemberPath == "ListOfB[2].Property1" && d.Value1 == "Value 2" && d.Value2 == "Value two")); + } + + [Test] + public void CompareObjectListByCustomKey() + { + var a1 = new A { ListOfB = new List { new B { Id = 1, Property1 = "Value 1", Property2 = "Key1" }, new B { Id = 2, Property1 = "Value 2", Property2 = "Key2" } } }; + var a2 = new A { ListOfB = new List { new B { Id = 1, Property1 = "Value two", Property2 = "Key2" }, new B { Id = 2, Property1 = "Value one", Property2 = "Key1" } } }; + + var settings = new ComparisonSettings(); + + settings.ConfigureListComparison(options => + { + options.CompareElementsByKey(keyOptions => + { + keyOptions.UseKey(args => ((B)args.Element).Property2); + }); + }); + + var comparer = new Comparer(settings); + var differences = comparer.CalculateDifferences(a1, a2).ToArray(); + + Assert.IsTrue(differences.Count() == 4); + Assert.IsTrue(differences.Any(d => d.DifferenceType == DifferenceTypes.ValueMismatch && d.MemberPath == "ListOfB[Key1].Property1" && d.Value1 == "Value 1" && d.Value2 == "Value one")); + Assert.IsTrue(differences.Any(d => d.DifferenceType == DifferenceTypes.ValueMismatch && d.MemberPath == "ListOfB[Key1].Id.Value" && d.Value1 == "1" && d.Value2 == "2")); + Assert.IsTrue(differences.Any(d => d.DifferenceType == DifferenceTypes.ValueMismatch && d.MemberPath == "ListOfB[Key2].Property1" && d.Value1 == "Value 2" && d.Value2 == "Value two")); + Assert.IsTrue(differences.Any(d => d.DifferenceType == DifferenceTypes.ValueMismatch && d.MemberPath == "ListOfB[Key2].Id.Value" && d.Value1 == "2" && d.Value2 == "1")); + } + + [Test] + public void CompareIntArraysFirstByIndexSecondByKey() + { + var a1 = new A { IntArray = new int[] { 3, 2, 1 }, IntArray2 = new int[] { 3, 2, 1 } }; + var a2 = new A { IntArray = new int[] { 1, 2, 3, 4 }, IntArray2 = new int[] { 1, 2, 3, 4 } }; + + var settings = new ComparisonSettings(); + + settings.ConfigureListComparison((currentProperty, listOptions) => + { + listOptions.CompareUnequalLists(true); + + if (currentProperty.Member.Name == nameof(A.IntArray2)) + { + listOptions.CompareElementsByKey(); + } + }); + + var comparer = new Comparer(settings); + var differences = comparer.CalculateDifferences(a1, a2).ToArray(); + + Assert.IsTrue(differences.Count() == 6); + Assert.IsTrue(differences.Any(d => d.DifferenceType == DifferenceTypes.ValueMismatch && d.MemberPath == "IntArray[0]" && d.Value1 == "3" && d.Value2 == "1")); + Assert.IsTrue(differences.Any(d => d.DifferenceType == DifferenceTypes.ValueMismatch && d.MemberPath == "IntArray[2]" && d.Value1 == "1" && d.Value2 == "3")); + Assert.IsTrue(differences.Any(d => d.DifferenceType == DifferenceTypes.MissedElementInFirstObject && d.MemberPath == "IntArray[3]" && d.Value1 == "" && d.Value2 == "4")); + Assert.IsTrue(differences.Any(d => d.DifferenceType == DifferenceTypes.ValueMismatch && d.MemberPath == "IntArray.Length" && d.Value1 == "3" && d.Value2 == "4")); + Assert.IsTrue(differences.Any(d => d.DifferenceType == DifferenceTypes.MissedElementInFirstObject && d.MemberPath == "IntArray2[4]" && d.Value1 == "" && d.Value2 == "4")); + Assert.IsTrue(differences.Any(d => d.DifferenceType == DifferenceTypes.ValueMismatch && d.MemberPath == "IntArray2.Length" && d.Value1 == "3" && d.Value2 == "4")); + } } } diff --git a/ObjectsComparer/ObjectsComparer.Tests/DifferenceTreeNodeTests.cs b/ObjectsComparer/ObjectsComparer.Tests/DifferenceTreeNodeTests.cs index b429f00..ef25fc6 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/DifferenceTreeNodeTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/DifferenceTreeNodeTests.cs @@ -16,6 +16,22 @@ namespace ObjectsComparer.Tests [TestFixture] internal class DifferenceTreeNodeTests { + [Test] + public void XXX() + { + var a1 = new A { ClassB = new B { Property1 = "hello" } }; + var a2 = new A { ClassB = new B { Property1 = "hallo" } }; + + var comparer = new Comparer(); + var rootNode = comparer.CalculateDifferenceTree(a1, a2); + var differences = rootNode.GetDifferences().ToList(); + var classB = rootNode.Descendants.Single(n => n.Member.Name == nameof(A.ClassB)); + var property1 = classB.Descendants.Single(n => n.Member.Name == nameof(B.Property1)); + + Assert.AreEqual(1, differences.Count); + Assert.AreEqual(differences[0].MemberPath, $"{classB.Member.Name}.{property1.Member.Name}"); + } + [Test] public void DifferenceTreeNodeMember_Member_Correct_MemberName() { diff --git a/ObjectsComparer/ObjectsComparer.Tests/TestClasses/A.cs b/ObjectsComparer/ObjectsComparer.Tests/TestClasses/A.cs index cc5fee7..5ad86ad 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/TestClasses/A.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/TestClasses/A.cs @@ -30,6 +30,8 @@ internal class A public int[] IntArray { get; set; } + public int[] IntArray2 { get; set; } + public B[] ArrayOfB { get; set; } public Collection CollectionOfB { get; set; } diff --git a/ObjectsComparer/ObjectsComparer.Tests/TestClasses/B.cs b/ObjectsComparer/ObjectsComparer.Tests/TestClasses/B.cs index c500bf3..8c03dd6 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/TestClasses/B.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/TestClasses/B.cs @@ -4,6 +4,8 @@ public class B { public string Property1 { get; set; } + public string Property2 { get; set; } + public int? Id { get; set; } } } diff --git a/ObjectsComparer/ObjectsComparer/ListElementKeyProviderArgs.cs b/ObjectsComparer/ObjectsComparer/ListElementKeyProviderArgs.cs index 076587a..ff0e39f 100644 --- a/ObjectsComparer/ObjectsComparer/ListElementKeyProviderArgs.cs +++ b/ObjectsComparer/ObjectsComparer/ListElementKeyProviderArgs.cs @@ -18,5 +18,4 @@ public ListElementKeyProviderArgs(object element) /// public object Element { get; } } - } From 0e40d1c97587440869c8d91a159777d30f136b98 Mon Sep 17 00:00:00 2001 From: Daniel Nemec Date: Sun, 8 May 2022 11:14:41 +0200 Subject: [PATCH 148/181] Add sample test methods for PR. --- .../Comparer_GenericEnumerableTests.cs | 41 ++++++++++++++++++- .../ObjectsComparer.Tests/TestClasses/A.cs | 2 + .../ObjectsComparer.Tests/TestClasses/C.cs | 11 +++++ 3 files changed, 52 insertions(+), 2 deletions(-) create mode 100644 ObjectsComparer/ObjectsComparer.Tests/TestClasses/C.cs diff --git a/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs b/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs index 86b2b87..0be02b4 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs @@ -1547,7 +1547,7 @@ public void CompareObjectListByCustomKey() { options.CompareElementsByKey(keyOptions => { - keyOptions.UseKey(args => ((B)args.Element).Property2); + keyOptions.UseKey(nameof(B.Property2)); }); }); @@ -1562,7 +1562,7 @@ public void CompareObjectListByCustomKey() } [Test] - public void CompareIntArraysFirstByIndexSecondByKey() + public void CompareIntArrayFirstByIndexSecondByKey() { var a1 = new A { IntArray = new int[] { 3, 2, 1 }, IntArray2 = new int[] { 3, 2, 1 } }; var a2 = new A { IntArray = new int[] { 1, 2, 3, 4 }, IntArray2 = new int[] { 1, 2, 3, 4 } }; @@ -1590,5 +1590,42 @@ public void CompareIntArraysFirstByIndexSecondByKey() Assert.IsTrue(differences.Any(d => d.DifferenceType == DifferenceTypes.MissedElementInFirstObject && d.MemberPath == "IntArray2[4]" && d.Value1 == "" && d.Value2 == "4")); Assert.IsTrue(differences.Any(d => d.DifferenceType == DifferenceTypes.ValueMismatch && d.MemberPath == "IntArray2.Length" && d.Value1 == "3" && d.Value2 == "4")); } + + [Test] + public void CompareObjectListFirstByDefaultKeySecondByCustomKey() + { + var a1 = new A + { + ListOfB = new List { new B { Id = 1, Property1 = "Value 1" }, new B { Id = 2, Property1 = "Value 2" } }, + ListOfC = new List { new C { Key = "Key1", Property1 = "Value 3" }, new C { Key = "Key2", Property1 = "Value 4" } } + }; + + var a2 = new A + { + ListOfB = new List { new B { Id = 2, Property1 = "Value two" }, new B { Id = 1, Property1 = "Value one" } } , + ListOfC = new List { new C { Key = "Key2", Property1 = "Value four" }, new C { Key = "Key1", Property1 = "Value three" } } + }; + + var settings = new ComparisonSettings(); + + settings.ConfigureListComparison((currentProperty, listOptions) => + { + listOptions.CompareElementsByKey(); + + if (currentProperty.Member.Name == nameof(A.ListOfC)) + { + listOptions.CompareElementsByKey(keyOptions => keyOptions.UseKey("Key")); + } + }); + + var comparer = new Comparer(settings); + var differences = comparer.CalculateDifferences(a1, a2).ToArray(); + + Assert.IsTrue(differences.Count() == 4); + Assert.IsTrue(differences.Any(d => d.DifferenceType == DifferenceTypes.ValueMismatch && d.MemberPath == "ListOfB[1].Property1" && d.Value1 == "Value 1" && d.Value2 == "Value one")); + Assert.IsTrue(differences.Any(d => d.DifferenceType == DifferenceTypes.ValueMismatch && d.MemberPath == "ListOfB[2].Property1" && d.Value1 == "Value 2" && d.Value2 == "Value two")); + Assert.IsTrue(differences.Any(d => d.DifferenceType == DifferenceTypes.ValueMismatch && d.MemberPath == "ListOfC[Key1].Property1" && d.Value1 == "Value 3" && d.Value2 == "Value three")); + Assert.IsTrue(differences.Any(d => d.DifferenceType == DifferenceTypes.ValueMismatch && d.MemberPath == "ListOfC[Key2].Property1" && d.Value1 == "Value 4" && d.Value2 == "Value four")); + } } } diff --git a/ObjectsComparer/ObjectsComparer.Tests/TestClasses/A.cs b/ObjectsComparer/ObjectsComparer.Tests/TestClasses/A.cs index 5ad86ad..7b588c0 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/TestClasses/A.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/TestClasses/A.cs @@ -40,6 +40,8 @@ internal class A public List ListOfB { get; set; } + public List ListOfC { get; set; } + public Dictionary DictionaryOfB { get; set; } public CollectionOfB ClassImplementsCollectionOfB { get; set; } diff --git a/ObjectsComparer/ObjectsComparer.Tests/TestClasses/C.cs b/ObjectsComparer/ObjectsComparer.Tests/TestClasses/C.cs new file mode 100644 index 0000000..4784770 --- /dev/null +++ b/ObjectsComparer/ObjectsComparer.Tests/TestClasses/C.cs @@ -0,0 +1,11 @@ +namespace ObjectsComparer.Tests.TestClasses +{ + public class C + { + public string Property1 { get; set; } + + public string Property2 { get; set; } + + public string Key { get; set; } + } +} From 93fd8bb58741289dde624c5b34d2ecba37562530 Mon Sep 17 00:00:00 2001 From: Daniel Nemec Date: Sun, 8 May 2022 18:30:33 +0200 Subject: [PATCH 149/181] Add sample test methods for PR. --- .../ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs b/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs index 0be02b4..cb49228 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs @@ -604,7 +604,7 @@ public void ClassImplementsCollectionEquality() public void ClassImplementsCollectionEquality_CompareByKey() { var a1 = new A { ClassImplementsCollectionOfB = new CollectionOfB { new B { Property1 = "Str1", Id = 1 }, new B { Property1 = "Str2", Id = 2 } } }; - var a2 = new A { ClassImplementsCollectionOfB = new CollectionOfB { new B { Property1 = "Str1", Id = 1 }, new B { Property1 = "Str2", Id = 2 } } }; + var a2 = new A { ClassImplementsCollectionOfB = new CollectionOfB { new B { Property1 = "Str2", Id = 2 }, new B { Property1 = "Str1", Id = 1 } } }; var settings = new ComparisonSettings(); settings.ConfigureListComparison(listOptions => listOptions.CompareElementsByKey()); From 7ce289b3ffcfa60f3a525f749c6da9f3f0d541e6 Mon Sep 17 00:00:00 2001 From: Daniel Nemec Date: Mon, 9 May 2022 14:24:40 +0200 Subject: [PATCH 150/181] Add CompareIntArrayByKey test method. --- .../Comparer_GenericEnumerableTests.cs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs b/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs index cb49228..758f4e3 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs @@ -1483,6 +1483,24 @@ public void CompareIntArrayByKey() var a1 = new int[] { 3, 2, 1 }; var a2 = new int[] { 1, 2, 3, 4 }; + var settings = new ComparisonSettings(); + settings.ConfigureListComparison(compareElementsByKey: true); + var comparer = new Comparer(settings); + var differences = comparer.CalculateDifferences(a1, a2).ToArray(); + + Assert.IsTrue(differences.Count() == 1); + Assert.AreEqual(DifferenceTypes.ValueMismatch, differences[0].DifferenceType); + Assert.AreEqual("Length", differences[0].MemberPath); + Assert.AreEqual("3", differences[0].Value1); + Assert.AreEqual("4", differences[0].Value2); + } + + [Test] + public void CompareIntArrayByKey_UnequalListEnabled() + { + var a1 = new int[] { 3, 2, 1 }; + var a2 = new int[] { 1, 2, 3, 4 }; + var settings = new ComparisonSettings(); settings.ConfigureListComparison(compareElementsByKey: true, compareUnequalLists: true); var comparer = new Comparer(settings); From 3b01014c17f1ee32dd0d67e0dd2a47369a7047fd Mon Sep 17 00:00:00 2001 From: Daniel Nemec Date: Tue, 10 May 2022 08:55:54 +0200 Subject: [PATCH 151/181] Add DifferenceTreeNodeTests.CompareIntArrayUnequalListEnabled test mehod. --- .../Comparer_GenericEnumerableTests.cs | 4 ++-- .../DifferenceTreeNodeTests.cs | 18 ++++++++++++++++++ 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs b/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs index 758f4e3..bd324b9 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs @@ -1444,7 +1444,7 @@ public void DictionaryInequalityDifferentValue_CompareByKey_FormatElementKey() } [Test] - public void CompareEnumerables_DefaultBehavior() + public void CompareIntArrayDefaultBehavior() { var a1 = new int[] { 3, 2, 1 }; var a2 = new int[] { 1, 2, 3, 4 }; @@ -1460,7 +1460,7 @@ public void CompareEnumerables_DefaultBehavior() } [Test] - public void CompareEnumerables_UnequalListEnabled() + public void CompareIntArrayUnequalListEnabled() { var a1 = new int[] { 3, 2, 1 }; var a2 = new int[] { 1, 2, 3, 4 }; diff --git a/ObjectsComparer/ObjectsComparer.Tests/DifferenceTreeNodeTests.cs b/ObjectsComparer/ObjectsComparer.Tests/DifferenceTreeNodeTests.cs index ef25fc6..06957c6 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/DifferenceTreeNodeTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/DifferenceTreeNodeTests.cs @@ -149,6 +149,24 @@ public void EnumerateConditional_FetchFirst_NotCompleted() Assert.AreEqual(false, completed); } + [Test] + public void CompareIntArrayUnequalListEnabled() + { + var a1 = new int[] { 3, 2, 1 }; + var a2 = new int[] { 1, 2, 3, 4 }; + + var settings = new ComparisonSettings(); + settings.ConfigureListComparison(compareUnequalLists: true); + var comparer = new Comparer(settings); + + var diffs = comparer.CalculateDifferences(a1, a2); + + foreach (var item in diffs) + { + System.Diagnostics.Debug.WriteLine(item); + } + } + protected IEnumerable EnumerateConditionalExt(IEnumerable enumerable, Func moveNextItem, Action completed = null) { var enumerator = enumerable.GetEnumerator(); From c246730a6930b76e23c08315b3722342b8096a50 Mon Sep 17 00:00:00 2001 From: Daniel Nemec Date: Mon, 23 May 2022 14:50:13 +0200 Subject: [PATCH 152/181] Add sample test methods for PR. --- .../Comparer_ExpandoObjectsTests.cs | 23 ++ .../Comparer_GenericEnumerableTests.cs | 221 +++++++++++++++++- .../TestClasses/Address.cs | 4 +- .../TestClasses/Customer.cs | 9 + .../TestClasses/Person.cs | 5 +- .../TestClasses/Student.cs | 9 + 6 files changed, 267 insertions(+), 4 deletions(-) create mode 100644 ObjectsComparer/ObjectsComparer.Tests/TestClasses/Customer.cs create mode 100644 ObjectsComparer/ObjectsComparer.Tests/TestClasses/Student.cs diff --git a/ObjectsComparer/ObjectsComparer.Tests/Comparer_ExpandoObjectsTests.cs b/ObjectsComparer/ObjectsComparer.Tests/Comparer_ExpandoObjectsTests.cs index c47b696..2c47e42 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/Comparer_ExpandoObjectsTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/Comparer_ExpandoObjectsTests.cs @@ -372,5 +372,28 @@ public void ExpandoObjectWithCollections() Assert.IsTrue(differences.Any( d => d.MemberPath == "Transaction[0].No" && d.DifferenceType == DifferenceTypes.ValueMismatch)); } + + [Test] + public void ExpandoObjectWithCollectionCheckDifferenceTreeNodePath() + { + var comparer = new Comparer(new ComparisonSettings { RecursiveComparison = true }); + + dynamic a1 = JsonConvert.DeserializeObject( + "{ \"Transaction\": [ { \"Name\": \"abc\", \"No\": 101 } ] }"); + + dynamic a2 = JsonConvert.DeserializeObject( + "{ \"Transaction\": [ { \"Name\": \"abc\", \"No\": 102 } ] }"); + + var rootNode = comparer.CalculateDifferenceTree(typeof(object), (object)a1, (object)a2); + var namePropertyPath = $"{rootNode.Descendants.First().Member.Name}.[0].{rootNode.Descendants.First().Descendants.First().Descendants.First().Member.Name}"; + var noPropertyPath = $"{rootNode.Descendants.First().Member.Name}.[0].{rootNode.Descendants.First().Descendants.First().Descendants.Skip(1).First().Member.Name}"; + var differences = rootNode.GetDifferences(true).ToList(); + + Assert.AreEqual(1, differences.Count); + Assert.IsTrue(differences.Any( + d => d.MemberPath == "Transaction[0].No" && d.DifferenceType == DifferenceTypes.ValueMismatch)); + Assert.AreEqual("Transaction.[0].Name", namePropertyPath); + Assert.AreEqual("Transaction.[0].No", noPropertyPath); + } } } diff --git a/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs b/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs index bd324b9..4f063a1 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs @@ -7,6 +7,11 @@ using System; using ObjectsComparer.Utils; using ObjectsComparer.Tests.Utils; +using System.Diagnostics; +using Newtonsoft.Json; +using System.Text; +using System.Collections; +using System.Reflection; namespace ObjectsComparer.Tests { @@ -1632,10 +1637,19 @@ public void CompareObjectListFirstByDefaultKeySecondByCustomKey() if (currentProperty.Member.Name == nameof(A.ListOfC)) { - listOptions.CompareElementsByKey(keyOptions => keyOptions.UseKey("Key")); + //listOptions.CompareElementsByKey(keyOptions => keyOptions.UseKey("Key")); + listOptions.CompareElementsByKey(keyOptions => keyOptions.UseKey(args => + { + var c = (C)args.Element; + return new { c.Key }; + })); } }); + object obj1 = new { Key = "1", Key2 = "2" }; + object obj2 = new { Key = "1", Key2 = "3" }; + var match = object.Equals(obj1, obj2); + var comparer = new Comparer(settings); var differences = comparer.CalculateDifferences(a1, a2).ToArray(); @@ -1645,5 +1659,210 @@ public void CompareObjectListFirstByDefaultKeySecondByCustomKey() Assert.IsTrue(differences.Any(d => d.DifferenceType == DifferenceTypes.ValueMismatch && d.MemberPath == "ListOfC[Key1].Property1" && d.Value1 == "Value 3" && d.Value2 == "Value three")); Assert.IsTrue(differences.Any(d => d.DifferenceType == DifferenceTypes.ValueMismatch && d.MemberPath == "ListOfC[Key2].Property1" && d.Value1 == "Value 4" && d.Value2 == "Value four")); } + + [Test] + public void TestCompareEntireObject() + { + var a1 = new TestClass { IntProperty = 10, StringProperty1 = "a", StringProperty2 = "c", ClassBProperty = new TestClassB { IntPropertyB = 30 } }; + var a2 = new TestClass { IntProperty = 10, StringProperty1 = "b", StringProperty2 = "c", ClassBProperty = new TestClassB { IntPropertyB = 40 } }; + + var comparer = new Comparer(); + //var comparer = new Comparer(); + bool compareResult = comparer.Compare(a1, a2); //Only IntProperty. + //bool calculateAnyDifferencesResult = comparer.CalculateDifferences(a1, a2).Any(); //Only IntProperty. + //var diffsArray = comparer.CalculateDifferences(a1, a2).ToArray(); //All properties. + + /* + IntProperty 10. + IntProperty 20. + */ + } + + public class TestClassB + { + int _intPropertyB; + + public int IntPropertyB + { + get + { + Console.WriteLine($"C IntPropertyB {_intPropertyB}."); + Debug.WriteLine($"IntPropertyB {_intPropertyB}."); + return _intPropertyB; + } + + set => _intPropertyB = value; + } + } + + public class TestClass + { + int _intProperty; + string _stringProperty1; + string _stringProperty2; + TestClassB _classBProperty; + + public int IntProperty + { + get + { + Console.WriteLine($"C IntProperty {_intProperty}."); + Debug.WriteLine($"IntProperty {_intProperty}."); + return _intProperty; + } + + set => _intProperty = value; + } + + public string StringProperty1 + { + get + { + Console.WriteLine($"C StringProperty1 {_stringProperty1}."); + Debug.WriteLine($"StringProperty1 {_stringProperty1}."); + return _stringProperty1; + } + + set => _stringProperty1 = value; + } + + public string StringProperty2 + { + get + { + Console.WriteLine($"C StringProperty2 {_stringProperty2}."); + Debug.WriteLine($"StringProperty2 {_stringProperty2}."); + return _stringProperty2; + } + + set => _stringProperty2 = value; + } + + public TestClassB ClassBProperty + { + get + { + Debug.WriteLine($"ClassBProperty {_classBProperty}."); + return _classBProperty; + } + + set => _classBProperty = value; + } + } + + [Test] + public void CompareObjectListsByContext() + { + var student1 = new Student + { + Person = new Person + { + ListOfAddress1 = new List
+ { + new Address { City = "Prag", Country = "Czech republic" }, + new Address { City = "Prag", Country = "Czech republic" } + } + } + }; + + var student2 = new Student + { + Person = new Person + { + ListOfAddress1 = new List
+ { + new Address { City = "Olomouc", Country = "Czech republic 2" }, + new Address { City = "Prag", Country = "Czech republic" } + } + } + }; + + var customer = new Customer + { + Person = new Person + { + ListOfAddress1 = new List
+ { + new Address { City = "Olomouc", Country = "Czech republic 2" } + } + } + }; + + var comparer = new ComparersFactory().GetObjectsComparer(); + var rootNode = comparer.CalculateDifferenceTree(student1, student2); + var diffs = rootNode.GetDifferences(true).ToArray(); + + var stringBuilder = new StringBuilder(); + WalkDifferenceTree(rootNode, 0, stringBuilder); + var differenceTreeStr = stringBuilder.ToString(); + var differenceTreeJson = (rootNode as DifferenceTreeNode).ToJson(); + + rootNode.Shrink(); + + Debug.WriteLine(""); + + stringBuilder = new StringBuilder(); + WalkDifferenceTree(rootNode, 0, stringBuilder); + differenceTreeStr = stringBuilder.ToString(); + differenceTreeJson = (rootNode as DifferenceTreeNode).ToJson(); + } + + void WalkDifferenceTree(IDifferenceTreeNode node, int level, StringBuilder stringBuilder) + { + var blankMemberName = "?"; + string indent = String.Concat(Enumerable.Repeat(" ", 2 * level)); + + if (TreeNodeIsListItem(node) == false) + { + var memberName = node?.Member?.Name ?? blankMemberName; + var line = indent + memberName; + stringBuilder.AppendLine(line); + Debug.WriteLine(line); + } + + foreach (var diff in node.Differences) + { + var line = indent + String.Concat(Enumerable.Repeat(" ", 2)) + diff.ToString(); + stringBuilder.AppendLine(line); + Debug.WriteLine(line); + } + + level++; + + var descendants = node.Descendants.ToArray(); + + for (int i = 0; i < descendants.Length; i++) + { + var desc = descendants[i]; + + if (TreeNodeIsListItem(desc)) + { + var line = indent + String.Concat(Enumerable.Repeat(" ", 2)) + $"[{GetIndex(desc)}]"; + stringBuilder.AppendLine(line); + Debug.WriteLine(line); + } + + WalkDifferenceTree(desc, level, stringBuilder); + } + } + + int? GetIndex(IDifferenceTreeNode node) + { + var itemx = node.Ancestor.Descendants + .Select((descendant, index) => new { Index = index, Descendant = descendant }).Where(n => n.Descendant == node) + .FirstOrDefault(); + + return itemx?.Index; + } + + bool TreeNodeIsListItem(IDifferenceTreeNode node) + { + if (node.Ancestor?.Member?.Info is PropertyInfo pi && typeof(IEnumerable).IsAssignableFrom(pi.PropertyType) && pi.PropertyType != typeof(string)) + { + return true; + } + + return false; + } } } diff --git a/ObjectsComparer/ObjectsComparer.Tests/TestClasses/Address.cs b/ObjectsComparer/ObjectsComparer.Tests/TestClasses/Address.cs index fc77cb9..1981bde 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/TestClasses/Address.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/TestClasses/Address.cs @@ -1,4 +1,6 @@ -namespace ObjectsComparer.Tests.TestClasses +using System.Collections.Generic; + +namespace ObjectsComparer.Tests.TestClasses { public class Address { diff --git a/ObjectsComparer/ObjectsComparer.Tests/TestClasses/Customer.cs b/ObjectsComparer/ObjectsComparer.Tests/TestClasses/Customer.cs new file mode 100644 index 0000000..43247d8 --- /dev/null +++ b/ObjectsComparer/ObjectsComparer.Tests/TestClasses/Customer.cs @@ -0,0 +1,9 @@ +using System.Collections.Generic; + +namespace ObjectsComparer.Tests.TestClasses +{ + public class Customer + { + public Person Person { get; set; } + } +} diff --git a/ObjectsComparer/ObjectsComparer.Tests/TestClasses/Person.cs b/ObjectsComparer/ObjectsComparer.Tests/TestClasses/Person.cs index d4c3489..b561c60 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/TestClasses/Person.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/TestClasses/Person.cs @@ -1,4 +1,5 @@ using System.Collections; +using System.Collections.Generic; namespace ObjectsComparer.Tests.TestClasses { @@ -12,8 +13,8 @@ public class Person public string PhoneNumber { get; set; } - public IEnumerable NonGenericLiveAddresses { get; set; } + public List
ListOfAddress1 { get; set; } - public IEnumerable NonGenericStayAddresses { get; set; } + public List
ListOfAddress2 { get; set; } } } diff --git a/ObjectsComparer/ObjectsComparer.Tests/TestClasses/Student.cs b/ObjectsComparer/ObjectsComparer.Tests/TestClasses/Student.cs new file mode 100644 index 0000000..a68ca71 --- /dev/null +++ b/ObjectsComparer/ObjectsComparer.Tests/TestClasses/Student.cs @@ -0,0 +1,9 @@ +using System.Collections.Generic; + +namespace ObjectsComparer.Tests.TestClasses +{ + public class Student + { + public Person Person { get; set; } + } +} From a9518f50ed0fe3e515e561521bd744f6eb7ad645 Mon Sep 17 00:00:00 2001 From: Daniel Nemec Date: Tue, 24 May 2022 15:27:36 +0200 Subject: [PATCH 153/181] Add tetst method CompareObjectListFirstByDefaultKeySecondByCustomKeyFormatCustomKey. --- .../Comparer_GenericEnumerableTests.cs | 99 +++++++++++++++++-- .../ObjectsComparer.Tests/TestClasses/C.cs | 2 + 2 files changed, 95 insertions(+), 6 deletions(-) diff --git a/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs b/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs index a9c9c94..5e3ceb9 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs @@ -1807,9 +1807,53 @@ public void CompareObjectListFirstByDefaultKeySecondByCustomKey() } }); - object obj1 = new { Key = "1", Key2 = "2" }; - object obj2 = new { Key = "1", Key2 = "3" }; - var match = object.Equals(obj1, obj2); + var comparer = new Comparer(settings); + var differences = comparer.CalculateDifferences(a1, a2).ToArray(); + + Assert.IsTrue(differences.Count() == 4); + Assert.IsTrue(differences.Any(d => d.DifferenceType == DifferenceTypes.ValueMismatch && d.MemberPath == "ListOfB[1].Property1" && d.Value1 == "Value 1" && d.Value2 == "Value one")); + Assert.IsTrue(differences.Any(d => d.DifferenceType == DifferenceTypes.ValueMismatch && d.MemberPath == "ListOfB[2].Property1" && d.Value1 == "Value 2" && d.Value2 == "Value two")); + Assert.IsTrue(differences.Any(d => d.DifferenceType == DifferenceTypes.ValueMismatch && d.MemberPath == "ListOfC[{ Key = Key1 }].Property1" && d.Value1 == "Value 3" && d.Value2 == "Value three")); + Assert.IsTrue(differences.Any(d => d.DifferenceType == DifferenceTypes.ValueMismatch && d.MemberPath == "ListOfC[{ Key = Key2 }].Property1" && d.Value1 == "Value 4" && d.Value2 == "Value four")); + } + + [Test] + public void CompareObjectListFirstByDefaultKeySecondByCustomKeyFormatCustomKey() + { + var a1 = new A + { + ListOfB = new List { new B { Id = 1, Property1 = "Value 1" }, new B { Id = 2, Property1 = "Value 2" } }, + ListOfC = new List { new C { Key = "Key1", Property1 = "Value 3" }, new C { Key = "Key2", Property1 = "Value 4" } } + }; + + var a2 = new A + { + ListOfB = new List { new B { Id = 2, Property1 = "Value two" }, new B { Id = 1, Property1 = "Value one" } }, + ListOfC = new List { new C { Key = "Key2", Property1 = "Value four" }, new C { Key = "Key1", Property1 = "Value three" } } + }; + + var settings = new ComparisonSettings(); + + settings.ConfigureListComparison((currentProperty, listOptions) => + { + listOptions.CompareElementsByKey(); + + if (currentProperty.Member.Name == nameof(A.ListOfC)) + { + listOptions.CompareElementsByKey(keyOptions => + keyOptions + .UseKey(args => + { + var element = (C)args.Element; + return new { element.Key }; + }) + .FormatElementKey(args => + { + var element = (C)args.Element; + return element.Key; + })); + } + }); var comparer = new Comparer(settings); var differences = comparer.CalculateDifferences(a1, a2).ToArray(); @@ -1817,8 +1861,8 @@ public void CompareObjectListFirstByDefaultKeySecondByCustomKey() Assert.IsTrue(differences.Count() == 4); Assert.IsTrue(differences.Any(d => d.DifferenceType == DifferenceTypes.ValueMismatch && d.MemberPath == "ListOfB[1].Property1" && d.Value1 == "Value 1" && d.Value2 == "Value one")); Assert.IsTrue(differences.Any(d => d.DifferenceType == DifferenceTypes.ValueMismatch && d.MemberPath == "ListOfB[2].Property1" && d.Value1 == "Value 2" && d.Value2 == "Value two")); - Assert.IsTrue(differences.Any(d => d.DifferenceType == DifferenceTypes.ValueMismatch && d.MemberPath == "ListOfC[Key1].Property1" && d.Value1 == "Value 3" && d.Value2 == "Value three")); - Assert.IsTrue(differences.Any(d => d.DifferenceType == DifferenceTypes.ValueMismatch && d.MemberPath == "ListOfC[Key2].Property1" && d.Value1 == "Value 4" && d.Value2 == "Value four")); + Assert.IsTrue(differences.Any(d => d.DifferenceType == DifferenceTypes.ValueMismatch && d.MemberPath == "ListOfC[{ Key = Key1 }].Property1" && d.Value1 == "Value 3" && d.Value2 == "Value three")); + Assert.IsTrue(differences.Any(d => d.DifferenceType == DifferenceTypes.ValueMismatch && d.MemberPath == "ListOfC[{ Key = Key2 }].Property1" && d.Value1 == "Value 4" && d.Value2 == "Value four")); } [Test] @@ -1912,7 +1956,7 @@ public TestClassB ClassBProperty } [Test] - public void CompareObjectListsByContext() + public void CompareObjectListByContext() { var student1 = new Student { @@ -2025,5 +2069,48 @@ bool TreeNodeIsListItem(IDifferenceTreeNode node) return false; } + + [Test] + public void CompareObjectListsByComplexKey() + { + var a1 = new A + { + ListOfC = new List + { + new C { Property1 = "Key1a", Property2 ="Key1b", Property3 = "Value 1" }, + new C { Property1 = "Key2a", Property2 = "Key2b", Property3 = "Value 2" } + } + }; + + var a2 = new A + { + ListOfC = new List + { + new C { Property1 = "Key2a", Property2 = "Key2b", Property3 = "Value two" }, + new C { Property1 = "Key1a", Property2 ="Key1b", Property3 = "Value 1" }, + } + }; + + var settings = new ComparisonSettings(); + + settings.ConfigureListComparison(listOptions => + { + listOptions.CompareElementsByKey(keyOptions => keyOptions.UseKey(args => new + { + ((C)args.Element).Property1, + ((C)args.Element).Property2 + })); + }); + + var comparer = new Comparer(settings); + var differences = comparer.CalculateDifferences(a1, a2).ToArray(); + + Assert.IsTrue(differences.Count() == 1); + Assert.IsTrue(differences.Any(d => + d.DifferenceType == DifferenceTypes.ValueMismatch + && d.MemberPath == "ListOfC[{ Property1 = Key2a, Property2 = Key2b }].Property3" + && d.Value1 == "Value 2" && + d.Value2 == "Value two")); + } } } diff --git a/ObjectsComparer/ObjectsComparer.Tests/TestClasses/C.cs b/ObjectsComparer/ObjectsComparer.Tests/TestClasses/C.cs index 4784770..541f4c7 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/TestClasses/C.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/TestClasses/C.cs @@ -7,5 +7,7 @@ public class C public string Property2 { get; set; } public string Key { get; set; } + + public string Property3 { get; set; } } } From defaf5e2292ccb5a42f9a7ed04faf856ed1d074f Mon Sep 17 00:00:00 2001 From: Daniel Nemec Date: Wed, 25 May 2022 14:45:06 +0200 Subject: [PATCH 154/181] Edit CompareObjectListFirstByDefaultKeySecondByCustomKey. --- .../Comparer_GenericEnumerableTests.cs | 21 ++++--------------- 1 file changed, 4 insertions(+), 17 deletions(-) diff --git a/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs b/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs index 5e3ceb9..5407980 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs @@ -1798,12 +1798,7 @@ public void CompareObjectListFirstByDefaultKeySecondByCustomKey() if (currentProperty.Member.Name == nameof(A.ListOfC)) { - //listOptions.CompareElementsByKey(keyOptions => keyOptions.UseKey("Key")); - listOptions.CompareElementsByKey(keyOptions => keyOptions.UseKey(args => - { - var c = (C)args.Element; - return new { c.Key }; - })); + listOptions.CompareElementsByKey(keyOptions => keyOptions.UseKey(args => ((C)args.Element).Key)); } }); @@ -1840,18 +1835,10 @@ public void CompareObjectListFirstByDefaultKeySecondByCustomKeyFormatCustomKey() if (currentProperty.Member.Name == nameof(A.ListOfC)) { - listOptions.CompareElementsByKey(keyOptions => + listOptions.CompareElementsByKey(keyOptions => keyOptions - .UseKey(args => - { - var element = (C)args.Element; - return new { element.Key }; - }) - .FormatElementKey(args => - { - var element = (C)args.Element; - return element.Key; - })); + .UseKey(args => new { ((C)args.Element).Key }) + .FormatElementKey(args => ((C)args.Element).Key)); } }); From 94ee84ed123dea4b30f98f10394b47da9e367d78 Mon Sep 17 00:00:00 2001 From: Daniel Nemec Date: Tue, 31 May 2022 09:50:55 +0200 Subject: [PATCH 155/181] Edit comments. --- ObjectsComparer/ObjectsComparer/ComparisonSettings.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ObjectsComparer/ObjectsComparer/ComparisonSettings.cs b/ObjectsComparer/ObjectsComparer/ComparisonSettings.cs index f3a127d..0d2fa52 100644 --- a/ObjectsComparer/ObjectsComparer/ComparisonSettings.cs +++ b/ObjectsComparer/ObjectsComparer/ComparisonSettings.cs @@ -71,6 +71,7 @@ public T GetCustomSetting(string key = null) /// /// Configures list comparison behavior, especially the type of the comparison. For more info, see . + /// The term list has a general meaning here and includes almost all Enumerable objects. /// /// First parameter: Current list node. public ComparisonSettings ConfigureListComparison(Action comparisonOptions) @@ -87,6 +88,7 @@ public ComparisonSettings ConfigureListComparison(Action /// Configures list comparison behavior, especially the type of comparison. For more info, see . + /// The term list has a general meaning here and includes almost all Enumerable objects. /// /// See . public void ConfigureListComparison(Action comparisonOptions) @@ -96,6 +98,7 @@ public void ConfigureListComparison(Action comparisonOpti /// /// Configures the type of list comparison and whether to compare unequal lists. For more info, see . + /// The term list has a general meaning here and includes almost all Enumerable objects. /// /// /// True value is shortcut for operation. From 0f2bb3598e3d00129c5de535bf39060ff98ff7f3 Mon Sep 17 00:00:00 2001 From: Daniel Nemec Date: Fri, 3 Jun 2022 10:12:49 +0200 Subject: [PATCH 156/181] Add DifferenceConfigurationTests class. --- .../DifferenceConfigurationTests.cs | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 ObjectsComparer/ObjectsComparer.Tests/DifferenceConfigurationTests.cs diff --git a/ObjectsComparer/ObjectsComparer.Tests/DifferenceConfigurationTests.cs b/ObjectsComparer/ObjectsComparer.Tests/DifferenceConfigurationTests.cs new file mode 100644 index 0000000..415ceac --- /dev/null +++ b/ObjectsComparer/ObjectsComparer.Tests/DifferenceConfigurationTests.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Threading; +using NSubstitute; +using NUnit.Framework; +using ObjectsComparer.Tests.TestClasses; + +namespace ObjectsComparer.Tests + +{ + [TestFixture] + public class DifferenceConfigurationTests + { + [Test] + public void PropertyEquality() + { + var a1 = new A { IntProperty = 10, DateTimeProperty = new DateTime(2017, 1, 1), Property3 = 5 }; + var a2 = new A { IntProperty = 10, DateTimeProperty = new DateTime(2017, 1, 1), Property3 = 8 }; + var comparer = new Comparer(); + + var isEqual = comparer.Compare(a1, a2); + + Assert.IsTrue(isEqual); + } + } +} From f3286144f89d5ecfdeddb50181f325e26a5dfe59 Mon Sep 17 00:00:00 2001 From: Daniel Nemec Date: Fri, 3 Jun 2022 12:43:43 +0200 Subject: [PATCH 157/181] Add DifferenceConfigurationTests's test methods. --- .../DifferenceConfigurationTests.cs | 46 ++++++++++++++++--- .../ObjectsComparer/ComparisonSettings.cs | 12 +++++ .../ObjectsComparer/DifferenceOptions.cs | 25 ++++++++++ 3 files changed, 77 insertions(+), 6 deletions(-) create mode 100644 ObjectsComparer/ObjectsComparer/DifferenceOptions.cs diff --git a/ObjectsComparer/ObjectsComparer.Tests/DifferenceConfigurationTests.cs b/ObjectsComparer/ObjectsComparer.Tests/DifferenceConfigurationTests.cs index 415ceac..eadc366 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/DifferenceConfigurationTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/DifferenceConfigurationTests.cs @@ -14,15 +14,49 @@ namespace ObjectsComparer.Tests public class DifferenceConfigurationTests { [Test] - public void PropertyEquality() + public void RawValuesIncludedDefault() { - var a1 = new A { IntProperty = 10, DateTimeProperty = new DateTime(2017, 1, 1), Property3 = 5 }; - var a2 = new A { IntProperty = 10, DateTimeProperty = new DateTime(2017, 1, 1), Property3 = 8 }; - var comparer = new Comparer(); + var differenceOptions = DifferenceOptions.Default(); + Assert.IsFalse(differenceOptions.RawValuesIncluded); + } + + [Test] + [TestCase(true)] + [TestCase(false)] + public void RawValuesIncluded(bool included) + { + var settings = new ComparisonSettings(); + + settings.ConfigureDifference(options => options.IncludeRawValues(included)); + + var differenceOptions = DifferenceOptions.Default(); + settings.DifferenceOptionsAction(null, differenceOptions); + + Assert.AreEqual(included, differenceOptions.RawValuesIncluded); + } + + [Test] + [TestCase("Property1", "Property1", true)] + [TestCase("Property2", "X", false)] + public void RawValuesIncludedConditional(string propertyName, string expectedPropertyName, bool expected) + { + var diffNode = new DifferenceTreeNode(new DifferenceTreeNodeMember(name: propertyName)); - var isEqual = comparer.Compare(a1, a2); + var settings = new ComparisonSettings(); - Assert.IsTrue(isEqual); + settings.ConfigureDifference((currentProperty, options) => + { + if (currentProperty.Member.Name == expectedPropertyName) + { + options.IncludeRawValues(true); + } + }); + + var differenceOptions = DifferenceOptions.Default(); + settings.DifferenceOptionsAction(diffNode, differenceOptions); + + Assert.AreEqual(expected, differenceOptions.RawValuesIncluded); } } } + diff --git a/ObjectsComparer/ObjectsComparer/ComparisonSettings.cs b/ObjectsComparer/ObjectsComparer/ComparisonSettings.cs index 0d2fa52..e7f32db 100644 --- a/ObjectsComparer/ObjectsComparer/ComparisonSettings.cs +++ b/ObjectsComparer/ObjectsComparer/ComparisonSettings.cs @@ -131,5 +131,17 @@ public void ConfigureDifferenceTree(Action DifferenceOptionsAction; + + public void ConfigureDifference(Action differenceOptions) + { + DifferenceOptionsAction = differenceOptions ?? throw new ArgumentNullException(nameof(differenceOptions)); + } + + public void ConfigureDifference(Action differenceOptions) + { + ConfigureDifference((_, options) => differenceOptions(options)); + } } } diff --git a/ObjectsComparer/ObjectsComparer/DifferenceOptions.cs b/ObjectsComparer/ObjectsComparer/DifferenceOptions.cs new file mode 100644 index 0000000..5645f4a --- /dev/null +++ b/ObjectsComparer/ObjectsComparer/DifferenceOptions.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace ObjectsComparer +{ + public class DifferenceOptions + { + DifferenceOptions() + { + } + + /// + /// Default options. + /// + internal static DifferenceOptions Default() => new DifferenceOptions(); + + public bool RawValuesIncluded { get; private set; } = false; + + public void IncludeRawValues(bool value) + { + RawValuesIncluded = value; + } + } +} From 628cb44a1295af14703a21a8d46e26c2567f93dd Mon Sep 17 00:00:00 2001 From: Daniel Nemec Date: Fri, 3 Jun 2022 13:26:03 +0200 Subject: [PATCH 158/181] Add DifferenceProvider class. --- .../ObjectsComparer/DifferenceOptions.cs | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/ObjectsComparer/ObjectsComparer/DifferenceOptions.cs b/ObjectsComparer/ObjectsComparer/DifferenceOptions.cs index 5645f4a..ac9817a 100644 --- a/ObjectsComparer/ObjectsComparer/DifferenceOptions.cs +++ b/ObjectsComparer/ObjectsComparer/DifferenceOptions.cs @@ -22,4 +22,51 @@ public void IncludeRawValues(bool value) RawValuesIncluded = value; } } + + //public class CreateDifferenceArgs + //{ + // public CreateDifferenceArgs(string memberPath, string value1, string value2, DifferenceTypes differenceType = DifferenceTypes.ValueMismatch, object rawValue1 = null, object rawValue2 = null) + // { + // MemberPath = memberPath; + // Value1 = value1; + // Value2 = value2; + // DifferenceType = differenceType; + // RawValue1 = rawValue1; + // RawValue2 = rawValue2; + // } + + // public string MemberPath { get; } + + // public string Value1 { get; } + + // public string Value2 { get; } + + // public DifferenceTypes DifferenceType { get; } + + // public object RawValue1 { get; } + + // public object RawValue2 { get; } + //} + + public static class DifferenceProvider + { + public static Difference CreateDifference( + ComparisonSettings settings, + IDifferenceTreeNode differenceTreeNode, + string memberPath, + string value1, + string value2, + DifferenceTypes differenceType = DifferenceTypes.ValueMismatch, + object rawValue1 = null, + object rawValue2 = null) + { + var options = DifferenceOptions.Default(); + settings.DifferenceOptionsAction?.Invoke(differenceTreeNode, options); + + //var difference = new Difference(); + + throw new NotImplementedException(); + + } + } } From 39cebd7c2c36f3d460dcba35e033798c088f0139 Mon Sep 17 00:00:00 2001 From: Daniel Nemec Date: Mon, 6 Jun 2022 08:32:56 +0200 Subject: [PATCH 159/181] Correcct CompareObjectListFirstByDefaultKeySecondByCustomKeyFormatCustomKey, CompareObjectListFirstByDefaultKeySecondByCustomKey. --- .../Comparer_GenericEnumerableTests.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs b/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs index 5407980..4169306 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs @@ -1808,8 +1808,8 @@ public void CompareObjectListFirstByDefaultKeySecondByCustomKey() Assert.IsTrue(differences.Count() == 4); Assert.IsTrue(differences.Any(d => d.DifferenceType == DifferenceTypes.ValueMismatch && d.MemberPath == "ListOfB[1].Property1" && d.Value1 == "Value 1" && d.Value2 == "Value one")); Assert.IsTrue(differences.Any(d => d.DifferenceType == DifferenceTypes.ValueMismatch && d.MemberPath == "ListOfB[2].Property1" && d.Value1 == "Value 2" && d.Value2 == "Value two")); - Assert.IsTrue(differences.Any(d => d.DifferenceType == DifferenceTypes.ValueMismatch && d.MemberPath == "ListOfC[{ Key = Key1 }].Property1" && d.Value1 == "Value 3" && d.Value2 == "Value three")); - Assert.IsTrue(differences.Any(d => d.DifferenceType == DifferenceTypes.ValueMismatch && d.MemberPath == "ListOfC[{ Key = Key2 }].Property1" && d.Value1 == "Value 4" && d.Value2 == "Value four")); + Assert.IsTrue(differences.Any(d => d.DifferenceType == DifferenceTypes.ValueMismatch && d.MemberPath == "ListOfC[Key1].Property1" && d.Value1 == "Value 3" && d.Value2 == "Value three")); + Assert.IsTrue(differences.Any(d => d.DifferenceType == DifferenceTypes.ValueMismatch && d.MemberPath == "ListOfC[Key2].Property1" && d.Value1 == "Value 4" && d.Value2 == "Value four")); } [Test] @@ -1838,7 +1838,7 @@ public void CompareObjectListFirstByDefaultKeySecondByCustomKeyFormatCustomKey() listOptions.CompareElementsByKey(keyOptions => keyOptions .UseKey(args => new { ((C)args.Element).Key }) - .FormatElementKey(args => ((C)args.Element).Key)); + .FormatElementKey(args => $"Key={((C)args.Element).Key}")); } }); @@ -1848,8 +1848,8 @@ public void CompareObjectListFirstByDefaultKeySecondByCustomKeyFormatCustomKey() Assert.IsTrue(differences.Count() == 4); Assert.IsTrue(differences.Any(d => d.DifferenceType == DifferenceTypes.ValueMismatch && d.MemberPath == "ListOfB[1].Property1" && d.Value1 == "Value 1" && d.Value2 == "Value one")); Assert.IsTrue(differences.Any(d => d.DifferenceType == DifferenceTypes.ValueMismatch && d.MemberPath == "ListOfB[2].Property1" && d.Value1 == "Value 2" && d.Value2 == "Value two")); - Assert.IsTrue(differences.Any(d => d.DifferenceType == DifferenceTypes.ValueMismatch && d.MemberPath == "ListOfC[{ Key = Key1 }].Property1" && d.Value1 == "Value 3" && d.Value2 == "Value three")); - Assert.IsTrue(differences.Any(d => d.DifferenceType == DifferenceTypes.ValueMismatch && d.MemberPath == "ListOfC[{ Key = Key2 }].Property1" && d.Value1 == "Value 4" && d.Value2 == "Value four")); + Assert.IsTrue(differences.Any(d => d.DifferenceType == DifferenceTypes.ValueMismatch && d.MemberPath == "ListOfC[Key=Key1].Property1" && d.Value1 == "Value 3" && d.Value2 == "Value three")); + Assert.IsTrue(differences.Any(d => d.DifferenceType == DifferenceTypes.ValueMismatch && d.MemberPath == "ListOfC[Key=Key2].Property1" && d.Value1 == "Value 4" && d.Value2 == "Value four")); } [Test] From 7a590d39ac2266857b6342a9c4c55518744c912a Mon Sep 17 00:00:00 2001 From: Daniel Nemec Date: Mon, 6 Jun 2022 14:14:35 +0200 Subject: [PATCH 160/181] Add raw values to Difference. Add DifferenceProvider. Raw values are optional. --- .../DifferenceConfigurationTests.cs | 88 ++++++++++++++++++- ObjectsComparer/ObjectsComparer/Difference.cs | 16 +++- .../ObjectsComparer/DifferenceOptions.cs | 68 +++++--------- .../ObjectsComparer/DifferenceProvider.cs | 49 +++++++++++ 4 files changed, 172 insertions(+), 49 deletions(-) create mode 100644 ObjectsComparer/ObjectsComparer/DifferenceProvider.cs diff --git a/ObjectsComparer/ObjectsComparer.Tests/DifferenceConfigurationTests.cs b/ObjectsComparer/ObjectsComparer.Tests/DifferenceConfigurationTests.cs index eadc366..f29787c 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/DifferenceConfigurationTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/DifferenceConfigurationTests.cs @@ -38,13 +38,13 @@ public void RawValuesIncluded(bool included) [Test] [TestCase("Property1", "Property1", true)] [TestCase("Property2", "X", false)] - public void RawValuesIncludedConditional(string propertyName, string expectedPropertyName, bool expected) + public void RawValuesIncludedConditionalCorrectlySet(string propertyName, string expectedPropertyName, bool expected) { - var diffNode = new DifferenceTreeNode(new DifferenceTreeNodeMember(name: propertyName)); + var differenceTreeNode = new DifferenceTreeNode(new DifferenceTreeNodeMember(name: propertyName)); var settings = new ComparisonSettings(); - settings.ConfigureDifference((currentProperty, options) => + settings.ConfigureDifference((currentProperty, options) => { if (currentProperty.Member.Name == expectedPropertyName) { @@ -53,10 +53,90 @@ public void RawValuesIncludedConditional(string propertyName, string expectedPro }); var differenceOptions = DifferenceOptions.Default(); - settings.DifferenceOptionsAction(diffNode, differenceOptions); + settings.DifferenceOptionsAction(differenceTreeNode, differenceOptions); Assert.AreEqual(expected, differenceOptions.RawValuesIncluded); } + + [Test] + [TestCase(true)] + [TestCase(false)] + public void DifferenceFactoryOverIncludeRawValues(bool includeRawValues) + { + var differenceTreeNode = new DifferenceTreeNode(new DifferenceTreeNodeMember()); + var settings = new ComparisonSettings(); + + settings.ConfigureDifference(options => + { + options.IncludeRawValues(includeRawValues); + options.UseDifferenceFactory(defDifference => defDifference); + }); + + var sourceDifference = new Difference( + memberPath: "PathXY", + value1: "VALUE1", + value2: "VALUE2", + rawValue1: new { Value = "VALUE1" }, + rawValue2: new { Value = "VALUE2" }, + differenceType: DifferenceTypes.TypeMismatch); + + var targetDifference = DifferenceProvider.CreateDifference(settings, differenceTreeNode, sourceDifference); + + Assert.AreEqual(sourceDifference, targetDifference); + } + + [Test] + [TestCase(true)] + [TestCase(false)] + public void NoDifferenceFactorySourceTargetDifferenceEquality(bool includeRawValues) + { + var differenceTreeNode = new DifferenceTreeNode(new DifferenceTreeNodeMember()); + var settings = new ComparisonSettings(); + + settings.ConfigureDifference(options => + { + options.IncludeRawValues(includeRawValues); + }); + + var sourceDifference = new Difference( + memberPath: "PathXY", + value1: "VALUE1", + value2: "VALUE2", + rawValue1: new { Value = "VALUE1" }, + rawValue2: new { Value = "VALUE2" }, + differenceType: DifferenceTypes.TypeMismatch); + + var targetDifference = DifferenceProvider.CreateDifference(settings, differenceTreeNode, sourceDifference); + + Assert.AreEqual(includeRawValues, sourceDifference == targetDifference); + Assert.AreEqual(includeRawValues, targetDifference.RawValue1 != null); + Assert.AreEqual(includeRawValues, targetDifference.RawValue2 != null); + } + + [Test] + public void XXX() + { + var differenceTreeNode = new DifferenceTreeNode(new DifferenceTreeNodeMember()); + var settings = new ComparisonSettings(); + + settings.ConfigureDifference(options => + { + options.IncludeRawValues(true); + options.UseDifferenceFactory(diff => diff); + }); + + var sourceDifference = new Difference( + memberPath: "PathXY", + value1: "VALUE1", + value2: "VALUE2", + rawValue1: new { Value = "VALUE1" }, + rawValue2: new { Value = "VALUE2" }, + differenceType: DifferenceTypes.TypeMismatch); + + var targetDifference = DifferenceProvider.CreateDifference(settings, differenceTreeNode, sourceDifference); + + //Assert.AreEqual(options-, null); + } } } diff --git a/ObjectsComparer/ObjectsComparer/Difference.cs b/ObjectsComparer/ObjectsComparer/Difference.cs index 2bbc141..be99b78 100644 --- a/ObjectsComparer/ObjectsComparer/Difference.cs +++ b/ObjectsComparer/ObjectsComparer/Difference.cs @@ -25,20 +25,34 @@ public class Difference /// public DifferenceTypes DifferenceType { get; } + /// + /// The first object itself. + /// + public object RawValue1 { get; } + + /// + /// The second object itself. + /// + public object RawValue2 { get; } + /// /// Initializes a new instance of the class. /// /// Member Path. /// Value of the first object, converted to string. /// Value of the second object, converted to string. + /// The first object itself. + /// The second object itself. /// Type of the difference. - public Difference(string memberPath, string value1, string value2, + public Difference(string memberPath, string value1, string value2, object rawValue1 = null, object rawValue2 = null, DifferenceTypes differenceType = DifferenceTypes.ValueMismatch) { MemberPath = memberPath; Value1 = value1; Value2 = value2; DifferenceType = differenceType; + RawValue1 = rawValue1; + RawValue2 = rawValue2; } /// diff --git a/ObjectsComparer/ObjectsComparer/DifferenceOptions.cs b/ObjectsComparer/ObjectsComparer/DifferenceOptions.cs index ac9817a..3d46080 100644 --- a/ObjectsComparer/ObjectsComparer/DifferenceOptions.cs +++ b/ObjectsComparer/ObjectsComparer/DifferenceOptions.cs @@ -4,6 +4,9 @@ namespace ObjectsComparer { + /// + /// Options for operation. + /// public class DifferenceOptions { DifferenceOptions() @@ -15,58 +18,35 @@ public class DifferenceOptions /// internal static DifferenceOptions Default() => new DifferenceOptions(); - public bool RawValuesIncluded { get; private set; } = false; + public bool? RawValuesIncluded { get; private set; } = false; - public void IncludeRawValues(bool value) + /// + /// Whether the instance should contain raw values. + /// + public DifferenceOptions IncludeRawValues(bool value) { RawValuesIncluded = value; - } - } - - //public class CreateDifferenceArgs - //{ - // public CreateDifferenceArgs(string memberPath, string value1, string value2, DifferenceTypes differenceType = DifferenceTypes.ValueMismatch, object rawValue1 = null, object rawValue2 = null) - // { - // MemberPath = memberPath; - // Value1 = value1; - // Value2 = value2; - // DifferenceType = differenceType; - // RawValue1 = rawValue1; - // RawValue2 = rawValue2; - // } - - // public string MemberPath { get; } - - // public string Value1 { get; } - - // public string Value2 { get; } - // public DifferenceTypes DifferenceType { get; } - - // public object RawValue1 { get; } + return this; + } - // public object RawValue2 { get; } - //} + internal Func DifferenceFactory = null; - public static class DifferenceProvider - { - public static Difference CreateDifference( - ComparisonSettings settings, - IDifferenceTreeNode differenceTreeNode, - string memberPath, - string value1, - string value2, - DifferenceTypes differenceType = DifferenceTypes.ValueMismatch, - object rawValue1 = null, - object rawValue2 = null) + /// + /// Factory for instances. This takes precendence over . + /// + /// + /// First parameter: The source difference.
+ /// Returns: Transformed difference or the source difference itself. + /// + /// + public DifferenceOptions UseDifferenceFactory(Func factory) { - var options = DifferenceOptions.Default(); - settings.DifferenceOptionsAction?.Invoke(differenceTreeNode, options); - - //var difference = new Difference(); - - throw new NotImplementedException(); + DifferenceFactory = factory ?? throw new ArgumentNullException(nameof(factory)); + RawValuesIncluded = null; + return this; } + } } diff --git a/ObjectsComparer/ObjectsComparer/DifferenceProvider.cs b/ObjectsComparer/ObjectsComparer/DifferenceProvider.cs new file mode 100644 index 0000000..54e42ca --- /dev/null +++ b/ObjectsComparer/ObjectsComparer/DifferenceProvider.cs @@ -0,0 +1,49 @@ +using System; + +namespace ObjectsComparer +{ + public static class DifferenceProvider + { + public static Difference CreateDifference(ComparisonSettings settings, IDifferenceTreeNode differenceTreeNode, Difference sourceDifference) + { + if (settings is null) + { + throw new ArgumentNullException(nameof(settings)); + } + + if (differenceTreeNode is null) + { + throw new ArgumentNullException(nameof(differenceTreeNode)); + } + + if (sourceDifference is null) + { + throw new ArgumentNullException(nameof(sourceDifference)); + } + + var options = DifferenceOptions.Default(); + + settings.DifferenceOptionsAction?.Invoke(differenceTreeNode, options); + + var customDifference = sourceDifference; + + if (options.DifferenceFactory != null) + { + customDifference = options.DifferenceFactory(sourceDifference); + } + else + { + if (options.RawValuesIncluded != true && (sourceDifference.RawValue1 != null || sourceDifference.RawValue2 != null)) + { + customDifference = new Difference( + memberPath: sourceDifference.MemberPath, + value1: sourceDifference.Value1, + value2: sourceDifference.Value2, + differenceType: DifferenceTypes.TypeMismatch); + } + } + + return customDifference; + } + } +} From 36d55344464855a47a4d39d2e2544361dad1844e Mon Sep 17 00:00:00 2001 From: Daniel Nemec Date: Mon, 6 Jun 2022 15:02:18 +0200 Subject: [PATCH 161/181] Corrent Difference ctor. Add IncludeRawValuesShortcutCorrectlySet test method. Add ComparisonSettings.ConfigureDifference operation. --- .../DifferenceConfigurationTests.cs | 14 ++++++-------- .../ObjectsComparer/ComparisonSettings.cs | 5 +++++ ObjectsComparer/ObjectsComparer/Difference.cs | 4 ++-- 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/ObjectsComparer/ObjectsComparer.Tests/DifferenceConfigurationTests.cs b/ObjectsComparer/ObjectsComparer.Tests/DifferenceConfigurationTests.cs index f29787c..0e4f618 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/DifferenceConfigurationTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/DifferenceConfigurationTests.cs @@ -66,7 +66,7 @@ public void DifferenceFactoryOverIncludeRawValues(bool includeRawValues) var differenceTreeNode = new DifferenceTreeNode(new DifferenceTreeNodeMember()); var settings = new ComparisonSettings(); - settings.ConfigureDifference(options => + settings.ConfigureDifference(options => { options.IncludeRawValues(includeRawValues); options.UseDifferenceFactory(defDifference => defDifference); @@ -114,16 +114,14 @@ public void NoDifferenceFactorySourceTargetDifferenceEquality(bool includeRawVal } [Test] - public void XXX() + [TestCase(true)] + [TestCase(false)] + public void IncludeRawValuesShortcutCorrectlySet(bool includeRawValues) { var differenceTreeNode = new DifferenceTreeNode(new DifferenceTreeNodeMember()); var settings = new ComparisonSettings(); - settings.ConfigureDifference(options => - { - options.IncludeRawValues(true); - options.UseDifferenceFactory(diff => diff); - }); + settings.ConfigureDifference(includeRawValues); var sourceDifference = new Difference( memberPath: "PathXY", @@ -135,7 +133,7 @@ public void XXX() var targetDifference = DifferenceProvider.CreateDifference(settings, differenceTreeNode, sourceDifference); - //Assert.AreEqual(options-, null); + Assert.IsTrue(includeRawValues ? targetDifference.RawValue1 != null : targetDifference.RawValue1 == null); } } } diff --git a/ObjectsComparer/ObjectsComparer/ComparisonSettings.cs b/ObjectsComparer/ObjectsComparer/ComparisonSettings.cs index e7f32db..6e3ca69 100644 --- a/ObjectsComparer/ObjectsComparer/ComparisonSettings.cs +++ b/ObjectsComparer/ObjectsComparer/ComparisonSettings.cs @@ -143,5 +143,10 @@ public void ConfigureDifference(Action differenceOptions) { ConfigureDifference((_, options) => differenceOptions(options)); } + + public void ConfigureDifference(bool includeRawValues) + { + ConfigureDifference(options => options.IncludeRawValues(includeRawValues)); + } } } diff --git a/ObjectsComparer/ObjectsComparer/Difference.cs b/ObjectsComparer/ObjectsComparer/Difference.cs index be99b78..d38be54 100644 --- a/ObjectsComparer/ObjectsComparer/Difference.cs +++ b/ObjectsComparer/ObjectsComparer/Difference.cs @@ -44,8 +44,8 @@ public class Difference /// The first object itself. /// The second object itself. /// Type of the difference. - public Difference(string memberPath, string value1, string value2, object rawValue1 = null, object rawValue2 = null, - DifferenceTypes differenceType = DifferenceTypes.ValueMismatch) + public Difference(string memberPath, string value1, string value2, + DifferenceTypes differenceType = DifferenceTypes.ValueMismatch, object rawValue1 = null, object rawValue2 = null) { MemberPath = memberPath; Value1 = value1; From e82247f91ad8facf16113da641e6647438f83798 Mon Sep 17 00:00:00 2001 From: Daniel Nemec Date: Wed, 8 Jun 2022 14:16:44 +0200 Subject: [PATCH 162/181] Edit DifferenceOptions. --- .../DifferenceConfigurationTests.cs | 106 +++++++----------- .../ObjectsComparer/DifferenceOptions.cs | 31 +++-- .../ObjectsComparer/DifferenceProvider.cs | 18 +-- 3 files changed, 66 insertions(+), 89 deletions(-) diff --git a/ObjectsComparer/ObjectsComparer.Tests/DifferenceConfigurationTests.cs b/ObjectsComparer/ObjectsComparer.Tests/DifferenceConfigurationTests.cs index 0e4f618..79f8368 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/DifferenceConfigurationTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/DifferenceConfigurationTests.cs @@ -14,64 +14,53 @@ namespace ObjectsComparer.Tests public class DifferenceConfigurationTests { [Test] - public void RawValuesIncludedDefault() + public void CreateDifferenceDefaultBehavior() { - var differenceOptions = DifferenceOptions.Default(); - Assert.IsFalse(differenceOptions.RawValuesIncluded); - } + var sourceDifference = new Difference( + memberPath: "PathXY", + value1: "VALUE1", + value2: "VALUE2", + rawValue1: new { Value = "VALUE1" }, + rawValue2: new { Value = "VALUE2" }, + differenceType: DifferenceTypes.TypeMismatch); - [Test] - [TestCase(true)] - [TestCase(false)] - public void RawValuesIncluded(bool included) - { + var differenceTreeNode = new DifferenceTreeNode(new DifferenceTreeNodeMember()); var settings = new ComparisonSettings(); - settings.ConfigureDifference(options => options.IncludeRawValues(included)); - - var differenceOptions = DifferenceOptions.Default(); - settings.DifferenceOptionsAction(null, differenceOptions); + var targetDifference = DifferenceProvider.CreateDifference(settings, differenceTreeNode, sourceDifference); - Assert.AreEqual(included, differenceOptions.RawValuesIncluded); + Assert.IsTrue(targetDifference.MemberPath == targetDifference.MemberPath); + Assert.IsTrue(targetDifference.Value1 == targetDifference.Value1); + Assert.IsTrue(targetDifference.Value2 == targetDifference.Value2); + Assert.IsTrue(targetDifference.RawValue2 == null); + Assert.IsTrue(targetDifference.RawValue1 == null); + Assert.IsTrue(targetDifference.DifferenceType == targetDifference.DifferenceType); } [Test] - [TestCase("Property1", "Property1", true)] - [TestCase("Property2", "X", false)] - public void RawValuesIncludedConditionalCorrectlySet(string propertyName, string expectedPropertyName, bool expected) + public void CreateDifferenceIncludeRawValues() { - var differenceTreeNode = new DifferenceTreeNode(new DifferenceTreeNodeMember(name: propertyName)); + var sourceDifference = new Difference( + memberPath: "PathXY", + value1: "VALUE1", + value2: "VALUE2", + rawValue1: new { Value = "VALUE1" }, + rawValue2: new { Value = "VALUE2" }, + differenceType: DifferenceTypes.TypeMismatch); + var differenceTreeNode = new DifferenceTreeNode(new DifferenceTreeNodeMember()); var settings = new ComparisonSettings(); - settings.ConfigureDifference((currentProperty, options) => - { - if (currentProperty.Member.Name == expectedPropertyName) - { - options.IncludeRawValues(true); - } - }); + settings.ConfigureDifference(includeRawValues: true); - var differenceOptions = DifferenceOptions.Default(); - settings.DifferenceOptionsAction(differenceTreeNode, differenceOptions); + var targetDifference = DifferenceProvider.CreateDifference(settings, differenceTreeNode, sourceDifference); - Assert.AreEqual(expected, differenceOptions.RawValuesIncluded); + Assert.IsTrue(targetDifference == sourceDifference); } [Test] - [TestCase(true)] - [TestCase(false)] - public void DifferenceFactoryOverIncludeRawValues(bool includeRawValues) + public void CreateDifferenceNotIncludeRawValues() { - var differenceTreeNode = new DifferenceTreeNode(new DifferenceTreeNodeMember()); - var settings = new ComparisonSettings(); - - settings.ConfigureDifference(options => - { - options.IncludeRawValues(includeRawValues); - options.UseDifferenceFactory(defDifference => defDifference); - }); - var sourceDifference = new Difference( memberPath: "PathXY", value1: "VALUE1", @@ -80,10 +69,20 @@ public void DifferenceFactoryOverIncludeRawValues(bool includeRawValues) rawValue2: new { Value = "VALUE2" }, differenceType: DifferenceTypes.TypeMismatch); + var differenceTreeNode = new DifferenceTreeNode(new DifferenceTreeNodeMember()); + var settings = new ComparisonSettings(); + + settings.ConfigureDifference(includeRawValues: false); + var targetDifference = DifferenceProvider.CreateDifference(settings, differenceTreeNode, sourceDifference); - Assert.AreEqual(sourceDifference, targetDifference); - } + Assert.IsTrue(targetDifference.MemberPath == targetDifference.MemberPath); + Assert.IsTrue(targetDifference.Value1 == targetDifference.Value1); + Assert.IsTrue(targetDifference.Value2 == targetDifference.Value2); + Assert.IsTrue(targetDifference.RawValue2 == null); + Assert.IsTrue(targetDifference.RawValue1 == null); + Assert.IsFalse(targetDifference == sourceDifference); + } [Test] [TestCase(true)] @@ -112,29 +111,6 @@ public void NoDifferenceFactorySourceTargetDifferenceEquality(bool includeRawVal Assert.AreEqual(includeRawValues, targetDifference.RawValue1 != null); Assert.AreEqual(includeRawValues, targetDifference.RawValue2 != null); } - - [Test] - [TestCase(true)] - [TestCase(false)] - public void IncludeRawValuesShortcutCorrectlySet(bool includeRawValues) - { - var differenceTreeNode = new DifferenceTreeNode(new DifferenceTreeNodeMember()); - var settings = new ComparisonSettings(); - - settings.ConfigureDifference(includeRawValues); - - var sourceDifference = new Difference( - memberPath: "PathXY", - value1: "VALUE1", - value2: "VALUE2", - rawValue1: new { Value = "VALUE1" }, - rawValue2: new { Value = "VALUE2" }, - differenceType: DifferenceTypes.TypeMismatch); - - var targetDifference = DifferenceProvider.CreateDifference(settings, differenceTreeNode, sourceDifference); - - Assert.IsTrue(includeRawValues ? targetDifference.RawValue1 != null : targetDifference.RawValue1 == null); - } } } diff --git a/ObjectsComparer/ObjectsComparer/DifferenceOptions.cs b/ObjectsComparer/ObjectsComparer/DifferenceOptions.cs index 3d46080..2e2ff29 100644 --- a/ObjectsComparer/ObjectsComparer/DifferenceOptions.cs +++ b/ObjectsComparer/ObjectsComparer/DifferenceOptions.cs @@ -18,22 +18,41 @@ public class DifferenceOptions /// internal static DifferenceOptions Default() => new DifferenceOptions(); - public bool? RawValuesIncluded { get; private set; } = false; - /// /// Whether the instance should contain raw values. /// public DifferenceOptions IncludeRawValues(bool value) { - RawValuesIncluded = value; + DifferenceFactory = value ? d => d : DefaultDifferenceFactory; return this; } - internal Func DifferenceFactory = null; + /// + /// Factory for instances. + /// + internal Func DifferenceFactory { get; private set; } = DefaultDifferenceFactory; /// - /// Factory for instances. This takes precendence over . + /// Default difference factory. + /// If the source difference contains raw values it creates a new instance based on the source difference without those values. Otherwise, it returns the source difference itself. + /// + public static Func DefaultDifferenceFactory => sourceDifference => + { + if (sourceDifference.RawValue1 == null && sourceDifference.RawValue2 == null) + { + return sourceDifference; + } + + return new Difference( + memberPath: sourceDifference.MemberPath, + value1: sourceDifference.Value1, + value2: sourceDifference.Value2, + differenceType: sourceDifference.DifferenceType); + }; + + /// + /// Factory for instances. /// /// /// First parameter: The source difference.
@@ -43,10 +62,8 @@ public DifferenceOptions IncludeRawValues(bool value) public DifferenceOptions UseDifferenceFactory(Func factory) { DifferenceFactory = factory ?? throw new ArgumentNullException(nameof(factory)); - RawValuesIncluded = null; return this; } - } } diff --git a/ObjectsComparer/ObjectsComparer/DifferenceProvider.cs b/ObjectsComparer/ObjectsComparer/DifferenceProvider.cs index 54e42ca..9b9c4b8 100644 --- a/ObjectsComparer/ObjectsComparer/DifferenceProvider.cs +++ b/ObjectsComparer/ObjectsComparer/DifferenceProvider.cs @@ -25,23 +25,7 @@ public static Difference CreateDifference(ComparisonSettings settings, IDifferen settings.DifferenceOptionsAction?.Invoke(differenceTreeNode, options); - var customDifference = sourceDifference; - - if (options.DifferenceFactory != null) - { - customDifference = options.DifferenceFactory(sourceDifference); - } - else - { - if (options.RawValuesIncluded != true && (sourceDifference.RawValue1 != null || sourceDifference.RawValue2 != null)) - { - customDifference = new Difference( - memberPath: sourceDifference.MemberPath, - value1: sourceDifference.Value1, - value2: sourceDifference.Value2, - differenceType: DifferenceTypes.TypeMismatch); - } - } + var customDifference = options.DifferenceFactory(sourceDifference); return customDifference; } From b10f412ae1b1675e438108f34b433f3d0c44e9b8 Mon Sep 17 00:00:00 2001 From: Daniel Nemec Date: Sun, 12 Jun 2022 18:00:37 +0200 Subject: [PATCH 163/181] Add CreateDifferenceArgs. --- .../ObjectsComparer/DifferenceOptions.cs | 34 ++++++++++--------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/ObjectsComparer/ObjectsComparer/DifferenceOptions.cs b/ObjectsComparer/ObjectsComparer/DifferenceOptions.cs index 2e2ff29..5acf57d 100644 --- a/ObjectsComparer/ObjectsComparer/DifferenceOptions.cs +++ b/ObjectsComparer/ObjectsComparer/DifferenceOptions.cs @@ -23,7 +23,7 @@ public class DifferenceOptions /// public DifferenceOptions IncludeRawValues(bool value) { - DifferenceFactory = value ? d => d : DefaultDifferenceFactory; + //DifferenceFactory = value ? d => d : DefaultDifferenceFactory; return this; } @@ -31,25 +31,13 @@ public DifferenceOptions IncludeRawValues(bool value) /// /// Factory for instances. /// - internal Func DifferenceFactory { get; private set; } = DefaultDifferenceFactory; + internal Func DifferenceFactory { get; private set; } = DefaultDifferenceFactory; /// /// Default difference factory. /// If the source difference contains raw values it creates a new instance based on the source difference without those values. Otherwise, it returns the source difference itself. /// - public static Func DefaultDifferenceFactory => sourceDifference => - { - if (sourceDifference.RawValue1 == null && sourceDifference.RawValue2 == null) - { - return sourceDifference; - } - - return new Difference( - memberPath: sourceDifference.MemberPath, - value1: sourceDifference.Value1, - value2: sourceDifference.Value2, - differenceType: sourceDifference.DifferenceType); - }; + public static Func DefaultDifferenceFactory => args => args.DefaultDifference; /// /// Factory for instances. @@ -59,11 +47,25 @@ public DifferenceOptions IncludeRawValues(bool value) /// Returns: Transformed difference or the source difference itself. /// /// - public DifferenceOptions UseDifferenceFactory(Func factory) + public DifferenceOptions UseDifferenceFactory(Func factory) { DifferenceFactory = factory ?? throw new ArgumentNullException(nameof(factory)); return this; } } + public class CreateDifferenceArgs + { + public object RawValue1 { get; } + + public object RawValue2 { get; } + public Difference DefaultDifference { get; } + + public CreateDifferenceArgs(Difference defaultDifference, object rawValue1 = null, object rawValue2 = null) + { + DefaultDifference = defaultDifference ?? throw new ArgumentNullException(nameof(defaultDifference)); + RawValue1 = rawValue1; + RawValue2 = rawValue2; + } + } } From ac47b0529529e2b5b2e404d4a364fb76d07cc86e Mon Sep 17 00:00:00 2001 From: nemec Date: Fri, 24 Jun 2022 17:48:47 +0200 Subject: [PATCH 164/181] Edit DifferenceOptions. --- .../ObjectsComparer/CreateDifferenceArgs.cs | 26 +++++++++++ .../ObjectsComparer/DifferenceOptions.cs | 45 +++++++------------ 2 files changed, 42 insertions(+), 29 deletions(-) create mode 100644 ObjectsComparer/ObjectsComparer/CreateDifferenceArgs.cs diff --git a/ObjectsComparer/ObjectsComparer/CreateDifferenceArgs.cs b/ObjectsComparer/ObjectsComparer/CreateDifferenceArgs.cs new file mode 100644 index 0000000..067bbb0 --- /dev/null +++ b/ObjectsComparer/ObjectsComparer/CreateDifferenceArgs.cs @@ -0,0 +1,26 @@ +using System; + +namespace ObjectsComparer +{ + /// + /// Arguments for the factory. + /// + public class CreateDifferenceArgs + { + public object RawValue1 { get; } + + public object RawValue2 { get; } + + /// + /// The default difference that a factory can return as its fallback. + /// + public Difference DefaultDifference { get; } + + public CreateDifferenceArgs(Difference defaultDifference, object rawValue1 = null, object rawValue2 = null) + { + DefaultDifference = defaultDifference ?? throw new ArgumentNullException(nameof(defaultDifference)); + RawValue1 = rawValue1; + RawValue2 = rawValue2; + } + } +} diff --git a/ObjectsComparer/ObjectsComparer/DifferenceOptions.cs b/ObjectsComparer/ObjectsComparer/DifferenceOptions.cs index 5acf57d..fe517a4 100644 --- a/ObjectsComparer/ObjectsComparer/DifferenceOptions.cs +++ b/ObjectsComparer/ObjectsComparer/DifferenceOptions.cs @@ -18,32 +18,33 @@ public class DifferenceOptions /// internal static DifferenceOptions Default() => new DifferenceOptions(); - /// - /// Whether the instance should contain raw values. - /// - public DifferenceOptions IncludeRawValues(bool value) - { - //DifferenceFactory = value ? d => d : DefaultDifferenceFactory; + ///// + ///// Whether the instance should contain raw values. + ///// + //public DifferenceOptions IncludeRawValues(bool value) + //{ + // //DifferenceFactory = value ? d => d : DefaultDifferenceFactory; - return this; - } + // return this; + //} /// /// Factory for instances. /// - internal Func DifferenceFactory { get; private set; } = DefaultDifferenceFactory; + internal Func DifferenceFactory { get; private set; } = null; - /// - /// Default difference factory. - /// If the source difference contains raw values it creates a new instance based on the source difference without those values. Otherwise, it returns the source difference itself. - /// - public static Func DefaultDifferenceFactory => args => args.DefaultDifference; + ///// + ///// Default difference factory. + ///// If the source difference contains raw values it creates a new instance based on the source difference without those values. Otherwise, it returns the source difference itself. + ///// + //public static Func DefaultDifferenceFactory => args => args.DefaultDifference; /// /// Factory for instances. /// /// - /// First parameter: The source difference.
+ /// Null value is allowed here and means that a default behavior of creation of the difference is required. + /// Func first parameter: The args for the difference creation.
/// Returns: Transformed difference or the source difference itself. /// /// @@ -54,18 +55,4 @@ public DifferenceOptions UseDifferenceFactory(Func Date: Sun, 26 Jun 2022 18:11:45 +0200 Subject: [PATCH 165/181] Add BaseComparer.CreateDifference, AddDifferenceToTree methods. --- .../DifferenceConfigurationTests.cs | 13 +++---- .../ObjectsComparer/BaseComparer.cs | 36 +++++++++++++++++++ .../ObjectsComparer/ComparisonSettings.cs | 26 ++++++++++---- .../ObjectsComparer/DifferenceProvider.cs | 17 +++++---- .../DifferenceTreeNodeProvider.cs | 8 +---- 5 files changed, 72 insertions(+), 28 deletions(-) diff --git a/ObjectsComparer/ObjectsComparer.Tests/DifferenceConfigurationTests.cs b/ObjectsComparer/ObjectsComparer.Tests/DifferenceConfigurationTests.cs index 79f8368..f990fe6 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/DifferenceConfigurationTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/DifferenceConfigurationTests.cs @@ -27,7 +27,7 @@ public void CreateDifferenceDefaultBehavior() var differenceTreeNode = new DifferenceTreeNode(new DifferenceTreeNodeMember()); var settings = new ComparisonSettings(); - var targetDifference = DifferenceProvider.CreateDifference(settings, differenceTreeNode, sourceDifference); + var targetDifference = DifferenceProvider.CreateDifference(settings, differenceTreeNode, sourceDifference, null, null); Assert.IsTrue(targetDifference.MemberPath == targetDifference.MemberPath); Assert.IsTrue(targetDifference.Value1 == targetDifference.Value1); @@ -53,7 +53,7 @@ public void CreateDifferenceIncludeRawValues() settings.ConfigureDifference(includeRawValues: true); - var targetDifference = DifferenceProvider.CreateDifference(settings, differenceTreeNode, sourceDifference); + var targetDifference = DifferenceProvider.CreateDifference(settings, differenceTreeNode, sourceDifference,null, null); Assert.IsTrue(targetDifference == sourceDifference); } @@ -74,7 +74,7 @@ public void CreateDifferenceNotIncludeRawValues() settings.ConfigureDifference(includeRawValues: false); - var targetDifference = DifferenceProvider.CreateDifference(settings, differenceTreeNode, sourceDifference); + var targetDifference = DifferenceProvider.CreateDifference(settings, differenceTreeNode, sourceDifference, null, null); Assert.IsTrue(targetDifference.MemberPath == targetDifference.MemberPath); Assert.IsTrue(targetDifference.Value1 == targetDifference.Value1); @@ -92,10 +92,7 @@ public void NoDifferenceFactorySourceTargetDifferenceEquality(bool includeRawVal var differenceTreeNode = new DifferenceTreeNode(new DifferenceTreeNodeMember()); var settings = new ComparisonSettings(); - settings.ConfigureDifference(options => - { - options.IncludeRawValues(includeRawValues); - }); + settings.ConfigureDifference(includeRawValues); var sourceDifference = new Difference( memberPath: "PathXY", @@ -105,7 +102,7 @@ public void NoDifferenceFactorySourceTargetDifferenceEquality(bool includeRawVal rawValue2: new { Value = "VALUE2" }, differenceType: DifferenceTypes.TypeMismatch); - var targetDifference = DifferenceProvider.CreateDifference(settings, differenceTreeNode, sourceDifference); + var targetDifference = DifferenceProvider.CreateDifference(settings, differenceTreeNode, sourceDifference, null, null); Assert.AreEqual(includeRawValues, sourceDifference == targetDifference); Assert.AreEqual(includeRawValues, targetDifference.RawValue1 != null); diff --git a/ObjectsComparer/ObjectsComparer/BaseComparer.cs b/ObjectsComparer/ObjectsComparer/BaseComparer.cs index 5710370..4dbb502 100644 --- a/ObjectsComparer/ObjectsComparer/BaseComparer.cs +++ b/ObjectsComparer/ObjectsComparer/BaseComparer.cs @@ -205,5 +205,41 @@ protected virtual DifferenceLocation AddDifferenceToTree(Difference difference, return new DifferenceLocation(difference, differenceTreeNode); } + + protected virtual DifferenceLocation AddDifferenceToTree(IDifferenceTreeNode differenceTreeNode, string memberPath, string value1, string value2, + DifferenceTypes differenceType = DifferenceTypes.ValueMismatch, object rawValue1 = null, object rawValue2 = null) + { + var difference = CreateDifference(differenceTreeNode, memberPath, value1, value2, differenceType, rawValue1, rawValue2); + + return new DifferenceLocation(difference, differenceTreeNode); + } + + protected virtual Difference CreateDifference(IDifferenceTreeNode differenceTreeNode, string memberPath, string value1, string value2, + DifferenceTypes differenceType = DifferenceTypes.ValueMismatch, object rawValue1 = null, object rawValue2 = null) + { + if (differenceTreeNode is null) + { + throw new ArgumentNullException(nameof(differenceTreeNode)); + } + + var differenceOptions = DifferenceOptions.Default(); + var defaultDifference = new Difference(memberPath, value1, value2, differenceType); + + Settings.DifferenceOptionsAction?.Invoke(differenceTreeNode, differenceOptions); + + if (differenceOptions.DifferenceFactory == null) + { + return defaultDifference; + } + + var customDifference = differenceOptions.DifferenceFactory(new CreateDifferenceArgs(defaultDifference, rawValue1, rawValue2)); + + if (customDifference == null) + { + throw new NullReferenceException("DifferenceFactory returned null."); + } + + return customDifference; + } } } \ No newline at end of file diff --git a/ObjectsComparer/ObjectsComparer/ComparisonSettings.cs b/ObjectsComparer/ObjectsComparer/ComparisonSettings.cs index 6e3ca69..1bd740c 100644 --- a/ObjectsComparer/ObjectsComparer/ComparisonSettings.cs +++ b/ObjectsComparer/ObjectsComparer/ComparisonSettings.cs @@ -139,14 +139,28 @@ public void ConfigureDifference(Action d DifferenceOptionsAction = differenceOptions ?? throw new ArgumentNullException(nameof(differenceOptions)); } - public void ConfigureDifference(Action differenceOptions) - { - ConfigureDifference((_, options) => differenceOptions(options)); - } - public void ConfigureDifference(bool includeRawValues) { - ConfigureDifference(options => options.IncludeRawValues(includeRawValues)); + DifferenceOptionsAction = (_, options) => + { + if (includeRawValues) + { + options.UseDifferenceFactory(args => + { + return new Difference( + args.DefaultDifference.MemberPath, + args.DefaultDifference.Value1, + args.DefaultDifference.Value2, + args.DefaultDifference.DifferenceType, + args.RawValue1, + args.RawValue2); + }); + } + else + { + options.UseDifferenceFactory(args => args.DefaultDifference); + } + }; } } } diff --git a/ObjectsComparer/ObjectsComparer/DifferenceProvider.cs b/ObjectsComparer/ObjectsComparer/DifferenceProvider.cs index 9b9c4b8..b83ad82 100644 --- a/ObjectsComparer/ObjectsComparer/DifferenceProvider.cs +++ b/ObjectsComparer/ObjectsComparer/DifferenceProvider.cs @@ -4,7 +4,7 @@ namespace ObjectsComparer { public static class DifferenceProvider { - public static Difference CreateDifference(ComparisonSettings settings, IDifferenceTreeNode differenceTreeNode, Difference sourceDifference) + public static Difference CreateDifference(ComparisonSettings settings, IDifferenceTreeNode differenceTreeNode, Difference defaultDifference, object rawValue1, object rawValue2) { if (settings is null) { @@ -16,18 +16,21 @@ public static Difference CreateDifference(ComparisonSettings settings, IDifferen throw new ArgumentNullException(nameof(differenceTreeNode)); } - if (sourceDifference is null) + if (defaultDifference is null) { - throw new ArgumentNullException(nameof(sourceDifference)); + throw new ArgumentNullException(nameof(defaultDifference)); } - var options = DifferenceOptions.Default(); + var differenceOptions = DifferenceOptions.Default(); - settings.DifferenceOptionsAction?.Invoke(differenceTreeNode, options); + settings.DifferenceOptionsAction?.Invoke(differenceTreeNode, differenceOptions); - var customDifference = options.DifferenceFactory(sourceDifference); + if (differenceOptions.DifferenceFactory == null) + { + return defaultDifference; + } - return customDifference; + return differenceOptions.DifferenceFactory(new CreateDifferenceArgs(defaultDifference, rawValue1, rawValue2)); } } } diff --git a/ObjectsComparer/ObjectsComparer/DifferenceTree/DifferenceTreeNodeProvider.cs b/ObjectsComparer/ObjectsComparer/DifferenceTree/DifferenceTreeNodeProvider.cs index 05afc71..dc330b8 100644 --- a/ObjectsComparer/ObjectsComparer/DifferenceTree/DifferenceTreeNodeProvider.cs +++ b/ObjectsComparer/ObjectsComparer/DifferenceTree/DifferenceTreeNodeProvider.cs @@ -52,13 +52,7 @@ public static IDifferenceTreeNode CreateNode(ComparisonSettings comparisonSettin if (options.DifferenceTreeNodeMemberFactory != null) { var customDifferenceTreeNodeMember = options.DifferenceTreeNodeMemberFactory.Invoke(differenceTreeNodeMember); - - if (customDifferenceTreeNodeMember == null) - { - throw new InvalidOperationException("Difference tree node member factory returned null member."); - } - - differenceTreeNodeMember = customDifferenceTreeNodeMember; + differenceTreeNodeMember = customDifferenceTreeNodeMember ?? throw new InvalidOperationException("Difference tree node member factory returned null member."); } if (options.DifferenceTreeNodeFactory != null) From 906a9d5e5f5e1831950ee27ababc6985ddceeb2f Mon Sep 17 00:00:00 2001 From: nemec Date: Sun, 26 Jun 2022 21:10:10 +0200 Subject: [PATCH 166/181] Edit ComparisonSettings.ConfigureDifference. --- .../DifferenceConfigurationTests.cs | 56 +++++++++++++------ ObjectsComparer/ObjectsComparer/Comparer~1.cs | 9 ++- .../ObjectsComparer/ComparisonSettings.cs | 32 +++++------ .../ObjectsComparer/DifferenceOptions.cs | 2 +- 4 files changed, 60 insertions(+), 39 deletions(-) diff --git a/ObjectsComparer/ObjectsComparer.Tests/DifferenceConfigurationTests.cs b/ObjectsComparer/ObjectsComparer.Tests/DifferenceConfigurationTests.cs index f990fe6..a9d6b89 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/DifferenceConfigurationTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/DifferenceConfigurationTests.cs @@ -14,27 +14,51 @@ namespace ObjectsComparer.Tests public class DifferenceConfigurationTests { [Test] - public void CreateDifferenceDefaultBehavior() + public void PreserveRawValuesDefaultBehavior() { - var sourceDifference = new Difference( - memberPath: "PathXY", - value1: "VALUE1", - value2: "VALUE2", - rawValue1: new { Value = "VALUE1" }, - rawValue2: new { Value = "VALUE2" }, - differenceType: DifferenceTypes.TypeMismatch); + var a1 = new A() { IntProperty = 10 }; + var a2 = new A() { IntProperty = 11 }; + + var comparer = new Comparer
(); + + var differences = comparer.CalculateDifferences(a1, a2).ToArray(); + + Assert.IsTrue(differences[0].RawValue1 == null); + Assert.IsTrue(differences[0].RawValue2 == null); + } + + [Test] + public void PreserveRawValues() + { + var a1 = new A() { IntProperty = 10 }; + var a2 = new A() { IntProperty = 11 }; + + var settings = new ComparisonSettings(); + settings.ConfigureDifference(includeRawValues: true); + + var comparer = new Comparer(settings); + + var differences = comparer.CalculateDifferences(a1, a2).ToArray(); + + Assert.IsTrue((int)differences[0].RawValue1 == 10); + Assert.IsTrue((int)differences[0].RawValue2 == 11); + } + + [Test] + public void DontPreserveRawValues() + { + var a1 = new A() { IntProperty = 10 }; + var a2 = new A() { IntProperty = 11 }; - var differenceTreeNode = new DifferenceTreeNode(new DifferenceTreeNodeMember()); var settings = new ComparisonSettings(); + settings.ConfigureDifference(includeRawValues: false); - var targetDifference = DifferenceProvider.CreateDifference(settings, differenceTreeNode, sourceDifference, null, null); + var comparer = new Comparer(settings); - Assert.IsTrue(targetDifference.MemberPath == targetDifference.MemberPath); - Assert.IsTrue(targetDifference.Value1 == targetDifference.Value1); - Assert.IsTrue(targetDifference.Value2 == targetDifference.Value2); - Assert.IsTrue(targetDifference.RawValue2 == null); - Assert.IsTrue(targetDifference.RawValue1 == null); - Assert.IsTrue(targetDifference.DifferenceType == targetDifference.DifferenceType); + var differences = comparer.CalculateDifferences(a1, a2).ToArray(); + + Assert.IsTrue(differences[0].RawValue1 == null); + Assert.IsTrue(differences[0].RawValue2 == null); } [Test] diff --git a/ObjectsComparer/ObjectsComparer/Comparer~1.cs b/ObjectsComparer/ObjectsComparer/Comparer~1.cs index 61e753c..95fd5e8 100644 --- a/ObjectsComparer/ObjectsComparer/Comparer~1.cs +++ b/ObjectsComparer/ObjectsComparer/Comparer~1.cs @@ -83,7 +83,8 @@ IEnumerable BuildDifferenceTree(T obj1, T obj2, MemberInfo m comparer = comparer ?? DefaultValueComparer; if (!comparer.Compare(obj1, obj2, Settings)) { - yield return AddDifferenceToTree(new Difference(string.Empty, comparer.ToString(obj1), comparer.ToString(obj2)), differenceTreeNode); + yield return AddDifferenceToTree(differenceTreeNode, string.Empty, comparer.ToString(obj1), comparer.ToString(obj2), DifferenceTypes.ValueMismatch, obj1, obj2); + //yield return AddDifferenceToTree(new Difference(string.Empty, comparer.ToString(obj1), comparer.ToString(obj2)), differenceTreeNode); DaN AddDifferenceToTree } yield break; @@ -107,7 +108,8 @@ IEnumerable BuildDifferenceTree(T obj1, T obj2, MemberInfo m { if (!DefaultValueComparer.Compare(obj1, obj2, Settings)) { - yield return AddDifferenceToTree(new Difference(string.Empty, DefaultValueComparer.ToString(obj1), DefaultValueComparer.ToString(obj2)), differenceTreeNode); + yield return AddDifferenceToTree(differenceTreeNode, string.Empty, DefaultValueComparer.ToString(obj1), DefaultValueComparer.ToString(obj2), DifferenceTypes.ValueMismatch, obj1, obj2); + //yield return AddDifferenceToTree(new Difference(string.Empty, DefaultValueComparer.ToString(obj1), DefaultValueComparer.ToString(obj2)), differenceTreeNode); DaN AddDifferenceToTree } yield break; @@ -162,7 +164,8 @@ IEnumerable BuildDifferenceTree(T obj1, T obj2, MemberInfo m if (!valueComparer.Compare(value1, value2, Settings)) { - yield return AddDifferenceToTree(new Difference(member.Name, valueComparer.ToString(value1), valueComparer.ToString(value2)), memberNode); + yield return AddDifferenceToTree(memberNode, member.Name, valueComparer.ToString(value1), valueComparer.ToString(value2), DifferenceTypes.ValueMismatch, value1, value2); + //yield return AddDifferenceToTree(new Difference(member.Name, valueComparer.ToString(value1), valueComparer.ToString(value2)), memberNode); //DaN AddDifferenceToTree } } } diff --git a/ObjectsComparer/ObjectsComparer/ComparisonSettings.cs b/ObjectsComparer/ObjectsComparer/ComparisonSettings.cs index 1bd740c..a01b563 100644 --- a/ObjectsComparer/ObjectsComparer/ComparisonSettings.cs +++ b/ObjectsComparer/ObjectsComparer/ComparisonSettings.cs @@ -141,26 +141,20 @@ public void ConfigureDifference(Action d public void ConfigureDifference(bool includeRawValues) { - DifferenceOptionsAction = (_, options) => + if (includeRawValues) { - if (includeRawValues) - { - options.UseDifferenceFactory(args => - { - return new Difference( - args.DefaultDifference.MemberPath, - args.DefaultDifference.Value1, - args.DefaultDifference.Value2, - args.DefaultDifference.DifferenceType, - args.RawValue1, - args.RawValue2); - }); - } - else - { - options.UseDifferenceFactory(args => args.DefaultDifference); - } - }; + ConfigureDifference((_, options) => options.UseDifferenceFactory(args => new Difference( + args.DefaultDifference.MemberPath, + args.DefaultDifference.Value1, + args.DefaultDifference.Value2, + args.DefaultDifference.DifferenceType, + args.RawValue1, + args.RawValue2))); + } + else + { + ConfigureDifference((_, options) => options.UseDifferenceFactory(null)); + } } } } diff --git a/ObjectsComparer/ObjectsComparer/DifferenceOptions.cs b/ObjectsComparer/ObjectsComparer/DifferenceOptions.cs index fe517a4..9ad36eb 100644 --- a/ObjectsComparer/ObjectsComparer/DifferenceOptions.cs +++ b/ObjectsComparer/ObjectsComparer/DifferenceOptions.cs @@ -50,7 +50,7 @@ public class DifferenceOptions /// public DifferenceOptions UseDifferenceFactory(Func factory) { - DifferenceFactory = factory ?? throw new ArgumentNullException(nameof(factory)); + DifferenceFactory = factory; return this; } From 77d8bc037a9b9f3d0379871829367376295771bb Mon Sep 17 00:00:00 2001 From: Daniel Nemec Date: Mon, 27 Jun 2022 14:35:15 +0200 Subject: [PATCH 167/181] Add DifferenceConfigurationTests test methods. --- .../DifferenceConfigurationTests.cs | 26 +++++++++++++++++++ .../ObjectsComparer/ComparisonSettings.cs | 15 +---------- .../ObjectsComparer/DifferenceOptions.cs | 20 ++++++++++++++ 3 files changed, 47 insertions(+), 14 deletions(-) diff --git a/ObjectsComparer/ObjectsComparer.Tests/DifferenceConfigurationTests.cs b/ObjectsComparer/ObjectsComparer.Tests/DifferenceConfigurationTests.cs index a9d6b89..3c47b3a 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/DifferenceConfigurationTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/DifferenceConfigurationTests.cs @@ -61,6 +61,32 @@ public void DontPreserveRawValues() Assert.IsTrue(differences[0].RawValue2 == null); } + [Test] + public void PreserveRawValuesConditionaly() + { + var a1 = new A() { IntProperty = 10, TestProperty1 = "TestProperty1value" }; + var a2 = new A() { IntProperty = 11, TestProperty1 = "TestProperty2value" }; + + var settings = new ComparisonSettings(); + + settings.ConfigureDifference((currentProperty, options) => + { + options.IncludeRawValues(currentProperty.Member.Name == "IntProperty"); + }); + + var comparer = new Comparer(settings); + + var differences = comparer.CalculateDifferences(a1, a2).ToArray(); + + Assert.IsTrue(differences[0].MemberPath == "IntProperty"); + Assert.IsTrue((int)differences[0].RawValue1 == 10); + Assert.IsTrue((int)differences[0].RawValue2 == 11); + + Assert.IsTrue(differences[1].MemberPath == "TestProperty1"); + Assert.IsTrue(differences[1].RawValue1 == null); + Assert.IsTrue(differences[1].RawValue2 == null); + } + [Test] public void CreateDifferenceIncludeRawValues() { diff --git a/ObjectsComparer/ObjectsComparer/ComparisonSettings.cs b/ObjectsComparer/ObjectsComparer/ComparisonSettings.cs index a01b563..19cb924 100644 --- a/ObjectsComparer/ObjectsComparer/ComparisonSettings.cs +++ b/ObjectsComparer/ObjectsComparer/ComparisonSettings.cs @@ -141,20 +141,7 @@ public void ConfigureDifference(Action d public void ConfigureDifference(bool includeRawValues) { - if (includeRawValues) - { - ConfigureDifference((_, options) => options.UseDifferenceFactory(args => new Difference( - args.DefaultDifference.MemberPath, - args.DefaultDifference.Value1, - args.DefaultDifference.Value2, - args.DefaultDifference.DifferenceType, - args.RawValue1, - args.RawValue2))); - } - else - { - ConfigureDifference((_, options) => options.UseDifferenceFactory(null)); - } + ConfigureDifference((_, options) => options.IncludeRawValues(includeRawValues)); } } } diff --git a/ObjectsComparer/ObjectsComparer/DifferenceOptions.cs b/ObjectsComparer/ObjectsComparer/DifferenceOptions.cs index 9ad36eb..e275b47 100644 --- a/ObjectsComparer/ObjectsComparer/DifferenceOptions.cs +++ b/ObjectsComparer/ObjectsComparer/DifferenceOptions.cs @@ -54,5 +54,25 @@ public DifferenceOptions UseDifferenceFactory(Func new Difference( + args.DefaultDifference.MemberPath, + args.DefaultDifference.Value1, + args.DefaultDifference.Value2, + args.DefaultDifference.DifferenceType, + args.RawValue1, + args.RawValue2)); + } + else + { + UseDifferenceFactory(null); + } + + return this; + } } } From fd7bc2de7ae234566b2a6203f275b58a06c07610 Mon Sep 17 00:00:00 2001 From: Daniel Nemec Date: Tue, 28 Jun 2022 14:32:18 +0200 Subject: [PATCH 168/181] Edit AddDifferenceToTree. --- .../ObjectsComparer/BaseComparer.cs | 2 + .../AbstractDynamicObjectsComprer.cs | 50 ++++++++++++------- .../CustomComparers/EnumerablesComparer.cs | 8 +-- .../EnumerablesComparerBase.cs | 36 +++++++++---- .../CustomComparers/EnumerablesComparer~1.cs | 3 +- .../CustomComparers/HashSetsComparer~1.cs | 16 +++--- .../MultidimensionalArrayComparer~1.cs | 10 ++-- .../CustomComparers/TypesComparer.cs | 3 +- 8 files changed, 82 insertions(+), 46 deletions(-) diff --git a/ObjectsComparer/ObjectsComparer/BaseComparer.cs b/ObjectsComparer/ObjectsComparer/BaseComparer.cs index 4dbb502..3dba394 100644 --- a/ObjectsComparer/ObjectsComparer/BaseComparer.cs +++ b/ObjectsComparer/ObjectsComparer/BaseComparer.cs @@ -185,10 +185,12 @@ public void IgnoreMember(Func filter) OverridesCollection.AddComparer(DoNotCompareValueComparer.Instance, filter); } + /// /// Adds an to the end of the 's . /// /// The instance. + [Obsolete("Use 2. method", true)] protected virtual DifferenceLocation AddDifferenceToTree(Difference difference, IDifferenceTreeNode differenceTreeNode) { if (difference is null) diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractDynamicObjectsComprer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractDynamicObjectsComprer.cs index 12a028a..9438277 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractDynamicObjectsComprer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractDynamicObjectsComprer.cs @@ -82,21 +82,30 @@ IEnumerable IDifferenceTreeBuilder.BuildDifferenceTree(Type { if (!existsInObject1) { - var difference = AddDifferenceToTree( - new Difference(propertyKey, string.Empty, valueComparer.ToString(value2), DifferenceTypes.MissedMemberInFirstObject), - keyDifferenceTreeNode); + var differenceLocation = AddDifferenceToTree(keyDifferenceTreeNode, propertyKey, string.Empty, valueComparer.ToString(value2), DifferenceTypes.ValueMismatch, null, value2); + //var differenceLocation = AddDifferenceToTree( + // new Difference(propertyKey, string.Empty, valueComparer.ToString(value2), DifferenceTypes.MissedMemberInFirstObject), + // keyDifferenceTreeNode); - yield return difference; + yield return differenceLocation; continue; } if (!existsInObject2) { - var difference = AddDifferenceToTree( - new Difference(propertyKey, valueComparer.ToString(value1), string.Empty, DifferenceTypes.MissedMemberInSecondObject), - keyDifferenceTreeNode); + var differenceLocation = AddDifferenceToTree( + keyDifferenceTreeNode, + propertyKey, + valueComparer.ToString(value1), + string.Empty, + DifferenceTypes.MissedMemberInSecondObject, + value1, + null); + //var differenceLocation = AddDifferenceToTree( + // new Difference(propertyKey, valueComparer.ToString(value1), string.Empty, DifferenceTypes.MissedMemberInSecondObject), + // keyDifferenceTreeNode); - yield return difference; + yield return differenceLocation; continue; } } @@ -107,11 +116,12 @@ IEnumerable IDifferenceTreeBuilder.BuildDifferenceTree(Type OverridesCollection.GetComparer(propertyKey) ?? DefaultValueComparer; - var difference = AddDifferenceToTree( - new Difference(propertyKey, valueComparer.ToString(value1), valueComparer2.ToString(value2), DifferenceTypes.TypeMismatch), - keyDifferenceTreeNode); + //var differenceLocation = AddDifferenceToTree( + // new Difference(propertyKey, valueComparer.ToString(value1), valueComparer2.ToString(value2), DifferenceTypes.TypeMismatch), + // keyDifferenceTreeNode); + var differenceLocation = AddDifferenceToTree(keyDifferenceTreeNode, propertyKey, valueComparer.ToString(value1), valueComparer2.ToString(value2), DifferenceTypes.TypeMismatch, value1, value2); - yield return difference; + yield return differenceLocation; continue; } @@ -123,11 +133,12 @@ IEnumerable IDifferenceTreeBuilder.BuildDifferenceTree(Type OverridesCollection.GetComparer(value2.GetType()) ?? OverridesCollection.GetComparer(propertyKey) ?? DefaultValueComparer : DefaultValueComparer; - var difference = AddDifferenceToTree( - new Difference(propertyKey, valueComparer.ToString(value1), valueComparer2.ToString(value2), DifferenceTypes.TypeMismatch), - keyDifferenceTreeNode); + //var differenceLocation = AddDifferenceToTree( + // new Difference(propertyKey, valueComparer.ToString(value1), valueComparer2.ToString(value2), DifferenceTypes.TypeMismatch), + // keyDifferenceTreeNode); + var differenceLocation = AddDifferenceToTree(keyDifferenceTreeNode, propertyKey, valueComparer.ToString(value1), valueComparer2.ToString(value2), DifferenceTypes.TypeMismatch, value1, value2); - yield return difference; + yield return differenceLocation; continue; } @@ -135,9 +146,10 @@ IEnumerable IDifferenceTreeBuilder.BuildDifferenceTree(Type { if (!customComparer.Compare(value1, value2, Settings)) { - var differenceLocation = AddDifferenceToTree( - new Difference(propertyKey, customComparer.ToString(value1), customComparer.ToString(value2)), - keyDifferenceTreeNode); + //var differenceLocation = AddDifferenceToTree( + // new Difference(propertyKey, customComparer.ToString(value1), customComparer.ToString(value2)), + // keyDifferenceTreeNode); + var differenceLocation = AddDifferenceToTree(keyDifferenceTreeNode, propertyKey, customComparer.ToString(value1), customComparer.ToString(value2), DifferenceTypes.ValueMismatch, value1, value2); yield return differenceLocation; } diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs index f3c4e37..ba2c750 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs @@ -36,7 +36,8 @@ IEnumerable IDifferenceTreeBuilder.BuildDifferenceTree(Type if (!Settings.EmptyAndNullEnumerablesEqual && (obj1 == null || obj2 == null) && obj1 != obj2) { - yield return AddDifferenceToTree(new Difference("[]", obj1?.ToString() ?? string.Empty, obj2?.ToString() ?? string.Empty), listDifferenceTreeNode); + //yield return AddDifferenceToTree(new Difference("[]", obj1?.ToString() ?? string.Empty, obj2?.ToString() ?? string.Empty), listDifferenceTreeNode); + yield return AddDifferenceToTree(listDifferenceTreeNode, "[]", obj1?.ToString() ?? string.Empty, obj2?.ToString() ?? string.Empty, DifferenceTypes.ValueMismatch, obj1, obj2); yield break; } @@ -59,14 +60,15 @@ IEnumerable IDifferenceTreeBuilder.BuildDifferenceTree(Type } var array1 = ((IEnumerable)obj1).Cast().ToArray(); - var array2 = ((IEnumerable)obj2).Cast().ToArray(); + var array2 = ((IEnumerable)obj2).Cast().ToArray(); var listComparisonOptions = ListComparisonOptions.Default(); Settings.ListComparisonOptionsAction?.Invoke(listDifferenceTreeNode, listComparisonOptions); if (array1.Length != array2.Length) { - yield return AddDifferenceToTree(new Difference("", array1.Length.ToString(), array2.Length.ToString(), DifferenceTypes.NumberOfElementsMismatch), listDifferenceTreeNode); + //yield return AddDifferenceToTree(new Difference("", array1.Length.ToString(), array2.Length.ToString(), DifferenceTypes.NumberOfElementsMismatch), listDifferenceTreeNode); + yield return AddDifferenceToTree(listDifferenceTreeNode, "", array1.Length.ToString(), array2.Length.ToString(), DifferenceTypes.NumberOfElementsMismatch, array1, array2); if (listComparisonOptions.UnequalListsComparisonEnabled == false) { diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparerBase.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparerBase.cs index a35cd18..c8f6c48 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparerBase.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparerBase.cs @@ -56,7 +56,8 @@ protected virtual IEnumerable CalculateDifferencesByKey(I var nullElementIdentifier = keyOptions.GetNullElementIdentifier(new FormatNullElementIdentifierArgs(element1Index)); - yield return AddDifferenceToTree(new Difference($"[{nullElementIdentifier}]", string.Empty, string.Empty, DifferenceTypes.MissedElementInSecondObject), elementDifferenceTreeNode); + //yield return AddDifferenceToTree(new Difference($"[{nullElementIdentifier}]", string.Empty, string.Empty, DifferenceTypes.MissedElementInSecondObject), elementDifferenceTreeNode); + yield return AddDifferenceToTree(elementDifferenceTreeNode, $"[{nullElementIdentifier}]", string.Empty, string.Empty, DifferenceTypes.MissedElementInSecondObject); continue; } @@ -88,7 +89,8 @@ protected virtual IEnumerable CalculateDifferencesByKey(I else { var valueComparer1 = OverridesCollection.GetComparer(element1.GetType()) ?? DefaultValueComparer; - yield return AddDifferenceToTree(new Difference($"[{formattedElement1Key}]", valueComparer1.ToString(element1), string.Empty, DifferenceTypes.MissedElementInSecondObject), elementDifferenceTreeNode); + //yield return AddDifferenceToTree(new Difference($"[{formattedElement1Key}]", valueComparer1.ToString(element1), string.Empty, DifferenceTypes.MissedElementInSecondObject), elementDifferenceTreeNode); + yield return AddDifferenceToTree(elementDifferenceTreeNode, $"[{formattedElement1Key}]", valueComparer1.ToString(element1), string.Empty, DifferenceTypes.MissedElementInSecondObject, element1); } } @@ -106,7 +108,8 @@ protected virtual IEnumerable CalculateDifferencesByKey(I var nullElementIdentifier = keyOptions.GetNullElementIdentifier(new FormatNullElementIdentifierArgs(element2Index)); - yield return AddDifferenceToTree(new Difference($"[{nullElementIdentifier}]", string.Empty, string.Empty, DifferenceTypes.MissedElementInFirstObject), elementDifferenceTreeNode); + //yield return AddDifferenceToTree(new Difference($"[{nullElementIdentifier}]", string.Empty, string.Empty, DifferenceTypes.MissedElementInFirstObject), elementDifferenceTreeNode); + yield return AddDifferenceToTree(elementDifferenceTreeNode, $"[{nullElementIdentifier}]", string.Empty, string.Empty, DifferenceTypes.MissedElementInFirstObject); continue; } @@ -126,7 +129,8 @@ protected virtual IEnumerable CalculateDifferencesByKey(I { var formattedElement2Key = keyOptions.GetFormattedElementKey(new FormatListElementKeyArgs(element2Index, element2Key, element2)); var valueComparer2 = OverridesCollection.GetComparer(element2.GetType()) ?? DefaultValueComparer; - yield return AddDifferenceToTree(new Difference($"[{formattedElement2Key}]", string.Empty, valueComparer2.ToString(element2), DifferenceTypes.MissedElementInFirstObject), elementDifferenceTreeNode); + //yield return AddDifferenceToTree(new Difference($"[{formattedElement2Key}]", string.Empty, valueComparer2.ToString(element2), DifferenceTypes.MissedElementInFirstObject), elementDifferenceTreeNode); + yield return AddDifferenceToTree(elementDifferenceTreeNode, $"[{formattedElement2Key}]", string.Empty, valueComparer2.ToString(element2), DifferenceTypes.MissedElementInFirstObject, null, element2); } } } @@ -157,19 +161,22 @@ protected virtual IEnumerable CalculateDifferencesByIndex if (array1[i] == null) { - yield return AddDifferenceToTree(new Difference($"[{i}]", string.Empty, valueComparer2.ToString(array2[i])), elementDifferenceTreeNode); + //yield return AddDifferenceToTree(new Difference($"[{i}]", string.Empty, valueComparer2.ToString(array2[i])), elementDifferenceTreeNode); + yield return AddDifferenceToTree(elementDifferenceTreeNode, $"[{i}]", string.Empty, valueComparer2.ToString(array2[i]), DifferenceTypes.ValueMismatch, null, array2[i]); continue; } if (array2[i] == null) { - yield return AddDifferenceToTree(new Difference($"[{i}]", valueComparer1.ToString(array1[i]), string.Empty), elementDifferenceTreeNode); + //yield return AddDifferenceToTree(new Difference($"[{i}]", valueComparer1.ToString(array1[i]), string.Empty), elementDifferenceTreeNode); + yield return AddDifferenceToTree(elementDifferenceTreeNode, $"[{i}]", valueComparer1.ToString(array1[i]), string.Empty, DifferenceTypes.ValueMismatch, array1[i]); continue; } if (array1[i].GetType() != array2[i].GetType()) { - yield return AddDifferenceToTree(new Difference($"[{i}]", valueComparer1.ToString(array1[i]), valueComparer2.ToString(array2[i]), DifferenceTypes.TypeMismatch), elementDifferenceTreeNode); + //yield return AddDifferenceToTree(new Difference($"[{i}]", valueComparer1.ToString(array1[i]), valueComparer2.ToString(array2[i]), DifferenceTypes.TypeMismatch), elementDifferenceTreeNode); + yield return AddDifferenceToTree(elementDifferenceTreeNode, $"[{i}]", valueComparer1.ToString(array1[i]), valueComparer2.ToString(array2[i]), DifferenceTypes.TypeMismatch, array1[i], array2[i]); continue; } @@ -191,13 +198,20 @@ protected virtual IEnumerable CalculateDifferencesByIndex { var valueComparer = largerArray[i] != null ? OverridesCollection.GetComparer(largerArray[i].GetType()) ?? DefaultValueComparer : DefaultValueComparer; - var difference = new Difference( + //var difference = new Difference( + // memberPath: $"[{i}]", + // value1: array1Count > array2Count ? valueComparer.ToString(largerArray[i]) : string.Empty, + // value2: array2Count > array1Count ? valueComparer.ToString(largerArray[i]) : string.Empty, + // differenceType: array1Count > array2Count ? DifferenceTypes.MissedElementInSecondObject : DifferenceTypes.MissedElementInFirstObject); + + //yield return AddDifferenceToTree(difference, DifferenceTreeNodeProvider.CreateNode(Settings, listDifferenceTreeNode)); + yield return AddDifferenceToTree(DifferenceTreeNodeProvider.CreateNode(Settings, listDifferenceTreeNode), memberPath: $"[{i}]", value1: array1Count > array2Count ? valueComparer.ToString(largerArray[i]) : string.Empty, value2: array2Count > array1Count ? valueComparer.ToString(largerArray[i]) : string.Empty, - differenceType: array1Count > array2Count ? DifferenceTypes.MissedElementInSecondObject : DifferenceTypes.MissedElementInFirstObject); - - yield return AddDifferenceToTree(difference, DifferenceTreeNodeProvider.CreateNode(Settings, listDifferenceTreeNode)); + differenceType: array1Count > array2Count ? DifferenceTypes.MissedElementInSecondObject : DifferenceTypes.MissedElementInFirstObject, + array1Count > array2Count ? largerArray[i] : (object)null, + array2Count > array1Count ? largerArray[i] : (object)null); } } } diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer~1.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer~1.cs index 3aeda59..7f1991d 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer~1.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer~1.cs @@ -66,7 +66,8 @@ public IEnumerable BuildDifferenceTree(Type type, object obj { if (!type.GetTypeInfo().IsArray) { - yield return AddDifferenceToTree(new Difference("", list1.Count().ToString(), list2.Count().ToString(), DifferenceTypes.NumberOfElementsMismatch), listDifferenceTreeNode); + //yield return AddDifferenceToTree(new Difference("", list1.Count().ToString(), list2.Count().ToString(), DifferenceTypes.NumberOfElementsMismatch), listDifferenceTreeNode); + yield return AddDifferenceToTree(listDifferenceTreeNode, "", list1.Count().ToString(), list2.Count().ToString(), DifferenceTypes.NumberOfElementsMismatch); } if (listComparisonOptions.UnequalListsComparisonEnabled == false) diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/HashSetsComparer~1.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/HashSetsComparer~1.cs index 400b4e0..c4d1c18 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/HashSetsComparer~1.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/HashSetsComparer~1.cs @@ -63,11 +63,12 @@ public IEnumerable BuildDifferenceTree(Type type, object obj { if (!hashSet2.Contains(element)) { - var difference = AddDifferenceToTree( - new Difference("", valueComparer.ToString(element), string.Empty, DifferenceTypes.MissedElementInSecondObject), - differenceTreeNode); + //var differenceLocation = AddDifferenceToTree( + // new Difference("", valueComparer.ToString(element), string.Empty, DifferenceTypes.MissedElementInSecondObject), + // differenceTreeNode); + var differenceLocation = AddDifferenceToTree(differenceTreeNode, "", valueComparer.ToString(element), string.Empty, DifferenceTypes.MissedElementInSecondObject, element, null); - yield return difference; + yield return differenceLocation; } } @@ -75,10 +76,11 @@ public IEnumerable BuildDifferenceTree(Type type, object obj { if (!hashSet1.Contains(element)) { - var difference = AddDifferenceToTree(new Difference("", string.Empty, valueComparer.ToString(element), - DifferenceTypes.MissedElementInFirstObject), differenceTreeNode); + //var differenceLocation = AddDifferenceToTree(new Difference("", string.Empty, valueComparer.ToString(element), + // DifferenceTypes.MissedElementInFirstObject), differenceTreeNode); + var differenceLocation = AddDifferenceToTree(differenceTreeNode, "", string.Empty, valueComparer.ToString(element), DifferenceTypes.MissedElementInFirstObject, null, element); - yield return difference; + yield return differenceLocation; } } } diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/MultidimensionalArrayComparer~1.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/MultidimensionalArrayComparer~1.cs index b2783b7..14ab80d 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/MultidimensionalArrayComparer~1.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/MultidimensionalArrayComparer~1.cs @@ -60,8 +60,9 @@ public IEnumerable BuildDifferenceTree(Type type, object obj if (array1.Rank != array2.Rank) { - var difference = AddDifferenceToTree(new Difference("Rank", array1.Rank.ToString(), array2.Rank.ToString()), differenceTreeNode); - yield return difference; + //var difference = AddDifferenceToTree(new Difference("Rank", array1.Rank.ToString(), array2.Rank.ToString()), differenceTreeNode); + var differenceLocation = AddDifferenceToTree(differenceTreeNode, "Rank", array1.Rank.ToString(), array2.Rank.ToString()); + yield return differenceLocation; yield break; } @@ -75,8 +76,9 @@ public IEnumerable BuildDifferenceTree(Type type, object obj if (length1 != length2) { dimensionsFailure = true; - var difference = AddDifferenceToTree(new Difference($"Dimension{i}", length1.ToString(), length2.ToString()), differenceTreeNode); - yield return difference; + //var differenceLocation = AddDifferenceToTree(new Difference($"Dimension{i}", length1.ToString(), length2.ToString()), differenceTreeNode); + var differenceLocation = AddDifferenceToTree(differenceTreeNode, $"Dimension{i}", length1.ToString(), length2.ToString()); + yield return differenceLocation; } } diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/TypesComparer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/TypesComparer.cs index e85cdfe..456a5d4 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/TypesComparer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/TypesComparer.cs @@ -49,7 +49,8 @@ public IEnumerable BuildDifferenceTree(Type type, object obj if (type1Str != type2Str) { //yield return new Difference(string.Empty, type1Str, type2Str); - yield return AddDifferenceToTree(new Difference(string.Empty, type1Str, type2Str), differenceTreeNode); + //yield return AddDifferenceToTree(new Difference(string.Empty, type1Str, type2Str), differenceTreeNode); + yield return AddDifferenceToTree(differenceTreeNode, string.Empty, type1Str, type2Str, DifferenceTypes.ValueMismatch, obj1, obj2); } } From ae2355c3c9524676ad786a8a30e428c9075288bb Mon Sep 17 00:00:00 2001 From: nemec Date: Tue, 28 Jun 2022 23:22:52 +0200 Subject: [PATCH 169/181] Correct mistakes: BaseComparer.AddDifferenceToTree, AbstractDynamicObjectsComprer.BuildDifferenceTree. --- .../DifferenceConfigurationTests.cs | 142 +++++++++--------- .../ObjectsComparer/BaseComparer.cs | 1 + .../AbstractDynamicObjectsComprer.cs | 2 +- 3 files changed, 73 insertions(+), 72 deletions(-) diff --git a/ObjectsComparer/ObjectsComparer.Tests/DifferenceConfigurationTests.cs b/ObjectsComparer/ObjectsComparer.Tests/DifferenceConfigurationTests.cs index 3c47b3a..7dcea82 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/DifferenceConfigurationTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/DifferenceConfigurationTests.cs @@ -87,77 +87,77 @@ public void PreserveRawValuesConditionaly() Assert.IsTrue(differences[1].RawValue2 == null); } - [Test] - public void CreateDifferenceIncludeRawValues() - { - var sourceDifference = new Difference( - memberPath: "PathXY", - value1: "VALUE1", - value2: "VALUE2", - rawValue1: new { Value = "VALUE1" }, - rawValue2: new { Value = "VALUE2" }, - differenceType: DifferenceTypes.TypeMismatch); - - var differenceTreeNode = new DifferenceTreeNode(new DifferenceTreeNodeMember()); - var settings = new ComparisonSettings(); - - settings.ConfigureDifference(includeRawValues: true); - - var targetDifference = DifferenceProvider.CreateDifference(settings, differenceTreeNode, sourceDifference,null, null); - - Assert.IsTrue(targetDifference == sourceDifference); - } - - [Test] - public void CreateDifferenceNotIncludeRawValues() - { - var sourceDifference = new Difference( - memberPath: "PathXY", - value1: "VALUE1", - value2: "VALUE2", - rawValue1: new { Value = "VALUE1" }, - rawValue2: new { Value = "VALUE2" }, - differenceType: DifferenceTypes.TypeMismatch); - - var differenceTreeNode = new DifferenceTreeNode(new DifferenceTreeNodeMember()); - var settings = new ComparisonSettings(); - - settings.ConfigureDifference(includeRawValues: false); - - var targetDifference = DifferenceProvider.CreateDifference(settings, differenceTreeNode, sourceDifference, null, null); - - Assert.IsTrue(targetDifference.MemberPath == targetDifference.MemberPath); - Assert.IsTrue(targetDifference.Value1 == targetDifference.Value1); - Assert.IsTrue(targetDifference.Value2 == targetDifference.Value2); - Assert.IsTrue(targetDifference.RawValue2 == null); - Assert.IsTrue(targetDifference.RawValue1 == null); - Assert.IsFalse(targetDifference == sourceDifference); - } - - [Test] - [TestCase(true)] - [TestCase(false)] - public void NoDifferenceFactorySourceTargetDifferenceEquality(bool includeRawValues) - { - var differenceTreeNode = new DifferenceTreeNode(new DifferenceTreeNodeMember()); - var settings = new ComparisonSettings(); - - settings.ConfigureDifference(includeRawValues); - - var sourceDifference = new Difference( - memberPath: "PathXY", - value1: "VALUE1", - value2: "VALUE2", - rawValue1: new { Value = "VALUE1" }, - rawValue2: new { Value = "VALUE2" }, - differenceType: DifferenceTypes.TypeMismatch); - - var targetDifference = DifferenceProvider.CreateDifference(settings, differenceTreeNode, sourceDifference, null, null); - - Assert.AreEqual(includeRawValues, sourceDifference == targetDifference); - Assert.AreEqual(includeRawValues, targetDifference.RawValue1 != null); - Assert.AreEqual(includeRawValues, targetDifference.RawValue2 != null); - } + //[Test] + //public void CreateDifferenceIncludeRawValues() + //{ + // var sourceDifference = new Difference( + // memberPath: "PathXY", + // value1: "VALUE1", + // value2: "VALUE2", + // rawValue1: new { Value = "VALUE1" }, + // rawValue2: new { Value = "VALUE2" }, + // differenceType: DifferenceTypes.TypeMismatch); + + // var differenceTreeNode = new DifferenceTreeNode(new DifferenceTreeNodeMember()); + // var settings = new ComparisonSettings(); + + // settings.ConfigureDifference(includeRawValues: true); + + // var targetDifference = DifferenceProvider.CreateDifference(settings, differenceTreeNode, sourceDifference,null, null); + + // Assert.IsTrue(targetDifference == sourceDifference); + //} + + //[Test] + //public void CreateDifferenceNotIncludeRawValues() + //{ + // var sourceDifference = new Difference( + // memberPath: "PathXY", + // value1: "VALUE1", + // value2: "VALUE2", + // rawValue1: new { Value = "VALUE1" }, + // rawValue2: new { Value = "VALUE2" }, + // differenceType: DifferenceTypes.TypeMismatch); + + // var differenceTreeNode = new DifferenceTreeNode(new DifferenceTreeNodeMember()); + // var settings = new ComparisonSettings(); + + // settings.ConfigureDifference(includeRawValues: false); + + // var targetDifference = DifferenceProvider.CreateDifference(settings, differenceTreeNode, sourceDifference, null, null); + + // Assert.IsTrue(targetDifference.MemberPath == targetDifference.MemberPath); + // Assert.IsTrue(targetDifference.Value1 == targetDifference.Value1); + // Assert.IsTrue(targetDifference.Value2 == targetDifference.Value2); + // Assert.IsTrue(targetDifference.RawValue2 == null); + // Assert.IsTrue(targetDifference.RawValue1 == null); + // Assert.IsFalse(targetDifference == sourceDifference); + // } + + //[Test] + //[TestCase(true)] + //[TestCase(false)] + //public void NoDifferenceFactorySourceTargetDifferenceEquality(bool includeRawValues) + //{ + // var differenceTreeNode = new DifferenceTreeNode(new DifferenceTreeNodeMember()); + // var settings = new ComparisonSettings(); + + // settings.ConfigureDifference(includeRawValues); + + // var sourceDifference = new Difference( + // memberPath: "PathXY", + // value1: "VALUE1", + // value2: "VALUE2", + // rawValue1: new { Value = "VALUE1" }, + // rawValue2: new { Value = "VALUE2" }, + // differenceType: DifferenceTypes.TypeMismatch); + + // var targetDifference = DifferenceProvider.CreateDifference(settings, differenceTreeNode, sourceDifference, null, null); + + // Assert.AreEqual(includeRawValues, sourceDifference == targetDifference); + // Assert.AreEqual(includeRawValues, targetDifference.RawValue1 != null); + // Assert.AreEqual(includeRawValues, targetDifference.RawValue2 != null); + //} } } diff --git a/ObjectsComparer/ObjectsComparer/BaseComparer.cs b/ObjectsComparer/ObjectsComparer/BaseComparer.cs index 3dba394..036a937 100644 --- a/ObjectsComparer/ObjectsComparer/BaseComparer.cs +++ b/ObjectsComparer/ObjectsComparer/BaseComparer.cs @@ -212,6 +212,7 @@ protected virtual DifferenceLocation AddDifferenceToTree(IDifferenceTreeNode dif DifferenceTypes differenceType = DifferenceTypes.ValueMismatch, object rawValue1 = null, object rawValue2 = null) { var difference = CreateDifference(differenceTreeNode, memberPath, value1, value2, differenceType, rawValue1, rawValue2); + differenceTreeNode.AddDifference(difference); return new DifferenceLocation(difference, differenceTreeNode); } diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractDynamicObjectsComprer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractDynamicObjectsComprer.cs index 9438277..693cd77 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractDynamicObjectsComprer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractDynamicObjectsComprer.cs @@ -82,7 +82,7 @@ IEnumerable IDifferenceTreeBuilder.BuildDifferenceTree(Type { if (!existsInObject1) { - var differenceLocation = AddDifferenceToTree(keyDifferenceTreeNode, propertyKey, string.Empty, valueComparer.ToString(value2), DifferenceTypes.ValueMismatch, null, value2); + var differenceLocation = AddDifferenceToTree(keyDifferenceTreeNode, propertyKey, string.Empty, valueComparer.ToString(value2), DifferenceTypes.MissedMemberInFirstObject, null, value2); //var differenceLocation = AddDifferenceToTree( // new Difference(propertyKey, string.Empty, valueComparer.ToString(value2), DifferenceTypes.MissedMemberInFirstObject), // keyDifferenceTreeNode); From a52423a5ca08eb0753ed0faede2209f6e6663507 Mon Sep 17 00:00:00 2001 From: nemec Date: Fri, 1 Jul 2022 16:38:15 +0200 Subject: [PATCH 170/181] Add CustomizeMemberPath test method. --- .../DifferenceConfigurationTests.cs | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/ObjectsComparer/ObjectsComparer.Tests/DifferenceConfigurationTests.cs b/ObjectsComparer/ObjectsComparer.Tests/DifferenceConfigurationTests.cs index 7dcea82..e597d87 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/DifferenceConfigurationTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/DifferenceConfigurationTests.cs @@ -87,6 +87,30 @@ public void PreserveRawValuesConditionaly() Assert.IsTrue(differences[1].RawValue2 == null); } + [Test] + public void CustomizeMemberPath() + { + var a1 = new A() { IntProperty = 10, TestProperty2 = "value1", ListOfC = new List { new C { Property1 = "property1" } } }; + var a2 = new A() { IntProperty = 11, TestProperty2 = "value2", ListOfC = new List { new C { Property1 = "property2" } } }; + + var settings = new ComparisonSettings(); + + settings.ConfigureDifference((currentProperty, options) => + { + if (currentProperty.Member.Name == nameof(A.IntProperty)) + { + options.UseDifferenceFactory(args => new Difference("Integer property", args.DefaultDifference.Value1, args.DefaultDifference.Value2)); + } + }); + + var comparer = new Comparer(settings); + + var differences = comparer.CalculateDifferences(a1, a2).ToArray(); + + Assert.IsTrue(differences.Any(diff=> diff.MemberPath == "Integer property")); + Assert.IsTrue(differences.Any(diff => diff.MemberPath == "TestProperty2")); + } + //[Test] //public void CreateDifferenceIncludeRawValues() //{ From 8cc6f371b98571a0603c3606ed8f0be5d6cd3f5b Mon Sep 17 00:00:00 2001 From: Daniel Nemec Date: Sun, 3 Jul 2022 23:25:57 +0200 Subject: [PATCH 171/181] Make ComparisonSettings's actions vsible. Add BaseComparer.InsertPathToDifference. Add InsertPathFactoryArgs. --- .../DifferenceConfigurationTests.cs | 359 +++++++++--------- .../DifferenceTreeNodeTests.cs | 89 ++++- .../ObjectsComparer/BaseComparer.cs | 14 + ObjectsComparer/ObjectsComparer/Comparer~1.cs | 5 +- .../ObjectsComparer/ComparisonSettings.cs | 41 +- .../AbstractDynamicObjectsComprer.cs | 17 +- .../CustomComparers/EnumerablesComparer.cs | 2 - .../EnumerablesComparerBase.cs | 14 - .../CustomComparers/EnumerablesComparer~1.cs | 1 - .../CustomComparers/HashSetsComparer~1.cs | 5 - .../MultidimensionalArrayComparer~1.cs | 2 - .../CustomComparers/TypesComparer.cs | 2 - .../ObjectsComparer/DifferenceOptions.cs | 20 +- .../ObjectsComparer/DifferencePathOptions.cs | 32 ++ .../ObjectsComparer/DifferenceProvider.cs | 36 -- .../DifferenceTreeBuilderExtensions.cs | 16 +- .../ObjectsComparer/InsertPathFactoryArgs.cs | 21 + 17 files changed, 390 insertions(+), 286 deletions(-) create mode 100644 ObjectsComparer/ObjectsComparer/DifferencePathOptions.cs delete mode 100644 ObjectsComparer/ObjectsComparer/DifferenceProvider.cs create mode 100644 ObjectsComparer/ObjectsComparer/InsertPathFactoryArgs.cs diff --git a/ObjectsComparer/ObjectsComparer.Tests/DifferenceConfigurationTests.cs b/ObjectsComparer/ObjectsComparer.Tests/DifferenceConfigurationTests.cs index e597d87..f40bd47 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/DifferenceConfigurationTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/DifferenceConfigurationTests.cs @@ -10,178 +10,191 @@ namespace ObjectsComparer.Tests { - [TestFixture] - public class DifferenceConfigurationTests - { - [Test] - public void PreserveRawValuesDefaultBehavior() - { - var a1 = new A() { IntProperty = 10 }; - var a2 = new A() { IntProperty = 11 }; - - var comparer = new Comparer(); - - var differences = comparer.CalculateDifferences(a1, a2).ToArray(); - - Assert.IsTrue(differences[0].RawValue1 == null); - Assert.IsTrue(differences[0].RawValue2 == null); - } - - [Test] - public void PreserveRawValues() - { - var a1 = new A() { IntProperty = 10 }; - var a2 = new A() { IntProperty = 11 }; - - var settings = new ComparisonSettings(); - settings.ConfigureDifference(includeRawValues: true); - - var comparer = new Comparer(settings); - - var differences = comparer.CalculateDifferences(a1, a2).ToArray(); - - Assert.IsTrue((int)differences[0].RawValue1 == 10); - Assert.IsTrue((int)differences[0].RawValue2 == 11); - } - - [Test] - public void DontPreserveRawValues() - { - var a1 = new A() { IntProperty = 10 }; - var a2 = new A() { IntProperty = 11 }; - - var settings = new ComparisonSettings(); - settings.ConfigureDifference(includeRawValues: false); - - var comparer = new Comparer(settings); - - var differences = comparer.CalculateDifferences(a1, a2).ToArray(); - - Assert.IsTrue(differences[0].RawValue1 == null); - Assert.IsTrue(differences[0].RawValue2 == null); - } - - [Test] - public void PreserveRawValuesConditionaly() - { - var a1 = new A() { IntProperty = 10, TestProperty1 = "TestProperty1value" }; - var a2 = new A() { IntProperty = 11, TestProperty1 = "TestProperty2value" }; - - var settings = new ComparisonSettings(); - - settings.ConfigureDifference((currentProperty, options) => - { - options.IncludeRawValues(currentProperty.Member.Name == "IntProperty"); - }); - - var comparer = new Comparer(settings); - - var differences = comparer.CalculateDifferences(a1, a2).ToArray(); - - Assert.IsTrue(differences[0].MemberPath == "IntProperty"); - Assert.IsTrue((int)differences[0].RawValue1 == 10); - Assert.IsTrue((int)differences[0].RawValue2 == 11); - - Assert.IsTrue(differences[1].MemberPath == "TestProperty1"); - Assert.IsTrue(differences[1].RawValue1 == null); - Assert.IsTrue(differences[1].RawValue2 == null); - } - - [Test] - public void CustomizeMemberPath() - { - var a1 = new A() { IntProperty = 10, TestProperty2 = "value1", ListOfC = new List { new C { Property1 = "property1" } } }; - var a2 = new A() { IntProperty = 11, TestProperty2 = "value2", ListOfC = new List { new C { Property1 = "property2" } } }; - - var settings = new ComparisonSettings(); - - settings.ConfigureDifference((currentProperty, options) => - { - if (currentProperty.Member.Name == nameof(A.IntProperty)) - { - options.UseDifferenceFactory(args => new Difference("Integer property", args.DefaultDifference.Value1, args.DefaultDifference.Value2)); - } - }); - - var comparer = new Comparer(settings); - - var differences = comparer.CalculateDifferences(a1, a2).ToArray(); - - Assert.IsTrue(differences.Any(diff=> diff.MemberPath == "Integer property")); - Assert.IsTrue(differences.Any(diff => diff.MemberPath == "TestProperty2")); - } - - //[Test] - //public void CreateDifferenceIncludeRawValues() - //{ - // var sourceDifference = new Difference( - // memberPath: "PathXY", - // value1: "VALUE1", - // value2: "VALUE2", - // rawValue1: new { Value = "VALUE1" }, - // rawValue2: new { Value = "VALUE2" }, - // differenceType: DifferenceTypes.TypeMismatch); - - // var differenceTreeNode = new DifferenceTreeNode(new DifferenceTreeNodeMember()); - // var settings = new ComparisonSettings(); - - // settings.ConfigureDifference(includeRawValues: true); - - // var targetDifference = DifferenceProvider.CreateDifference(settings, differenceTreeNode, sourceDifference,null, null); - - // Assert.IsTrue(targetDifference == sourceDifference); - //} - - //[Test] - //public void CreateDifferenceNotIncludeRawValues() - //{ - // var sourceDifference = new Difference( - // memberPath: "PathXY", - // value1: "VALUE1", - // value2: "VALUE2", - // rawValue1: new { Value = "VALUE1" }, - // rawValue2: new { Value = "VALUE2" }, - // differenceType: DifferenceTypes.TypeMismatch); - - // var differenceTreeNode = new DifferenceTreeNode(new DifferenceTreeNodeMember()); - // var settings = new ComparisonSettings(); - - // settings.ConfigureDifference(includeRawValues: false); - - // var targetDifference = DifferenceProvider.CreateDifference(settings, differenceTreeNode, sourceDifference, null, null); - - // Assert.IsTrue(targetDifference.MemberPath == targetDifference.MemberPath); - // Assert.IsTrue(targetDifference.Value1 == targetDifference.Value1); - // Assert.IsTrue(targetDifference.Value2 == targetDifference.Value2); - // Assert.IsTrue(targetDifference.RawValue2 == null); - // Assert.IsTrue(targetDifference.RawValue1 == null); - // Assert.IsFalse(targetDifference == sourceDifference); - // } - - //[Test] - //[TestCase(true)] - //[TestCase(false)] - //public void NoDifferenceFactorySourceTargetDifferenceEquality(bool includeRawValues) - //{ - // var differenceTreeNode = new DifferenceTreeNode(new DifferenceTreeNodeMember()); - // var settings = new ComparisonSettings(); - - // settings.ConfigureDifference(includeRawValues); - - // var sourceDifference = new Difference( - // memberPath: "PathXY", - // value1: "VALUE1", - // value2: "VALUE2", - // rawValue1: new { Value = "VALUE1" }, - // rawValue2: new { Value = "VALUE2" }, - // differenceType: DifferenceTypes.TypeMismatch); - - // var targetDifference = DifferenceProvider.CreateDifference(settings, differenceTreeNode, sourceDifference, null, null); - - // Assert.AreEqual(includeRawValues, sourceDifference == targetDifference); - // Assert.AreEqual(includeRawValues, targetDifference.RawValue1 != null); - // Assert.AreEqual(includeRawValues, targetDifference.RawValue2 != null); - //} - } + [TestFixture] + public class DifferenceConfigurationTests + { + [Test] + public void PreserveRawValuesDefaultBehavior() + { + var a1 = new A() { IntProperty = 10 }; + var a2 = new A() { IntProperty = 11 }; + + var comparer = new Comparer(); + + var differences = comparer.CalculateDifferences(a1, a2).ToArray(); + + Assert.IsTrue(differences[0].RawValue1 == null); + Assert.IsTrue(differences[0].RawValue2 == null); + } + + [Test] + public void PreserveRawValues() + { + var a1 = new A() { IntProperty = 10 }; + var a2 = new A() { IntProperty = 11 }; + + var settings = new ComparisonSettings(); + settings.ConfigureDifference(includeRawValues: true); + + var comparer = new Comparer(settings); + + var differences = comparer.CalculateDifferences(a1, a2).ToArray(); + + Assert.IsTrue((int)differences[0].RawValue1 == 10); + Assert.IsTrue((int)differences[0].RawValue2 == 11); + } + + [Test] + public void DontPreserveRawValues() + { + var a1 = new A() { IntProperty = 10 }; + var a2 = new A() { IntProperty = 11 }; + + var settings = new ComparisonSettings(); + settings.ConfigureDifference(includeRawValues: false); + + var comparer = new Comparer(settings); + + var differences = comparer.CalculateDifferences(a1, a2).ToArray(); + + Assert.IsTrue(differences[0].RawValue1 == null); + Assert.IsTrue(differences[0].RawValue2 == null); + } + + [Test] + public void PreserveRawValuesConditionaly() + { + var a1 = new A() { IntProperty = 10, TestProperty1 = "TestProperty1value" }; + var a2 = new A() { IntProperty = 11, TestProperty1 = "TestProperty2value" }; + + var settings = new ComparisonSettings(); + + settings.ConfigureDifference((currentProperty, options) => + { + options.IncludeRawValues(currentProperty.Member.Name == "IntProperty"); + }); + + var comparer = new Comparer(settings); + + var differences = comparer.CalculateDifferences(a1, a2).ToArray(); + + Assert.IsTrue(differences[0].MemberPath == "IntProperty"); + Assert.IsTrue((int)differences[0].RawValue1 == 10); + Assert.IsTrue((int)differences[0].RawValue2 == 11); + + Assert.IsTrue(differences[1].MemberPath == "TestProperty1"); + Assert.IsTrue(differences[1].RawValue1 == null); + Assert.IsTrue(differences[1].RawValue2 == null); + } + + [Test] + public void CustomizeMemberPath() + { + var a1 = new A() { IntProperty = 10, TestProperty2 = "value1", ListOfC = new List { new C { Property1 = "property1" } } }; + var a2 = new A() { IntProperty = 11, TestProperty2 = "value2", ListOfC = new List { new C { Property1 = "property2" } } }; + + var settings = new ComparisonSettings(); + + settings + .ConfigureDifference((currentProperty, options) => + { + if (currentProperty.Member.Name == nameof(A.IntProperty)) + { + options.UseDifferenceFactory(args => new Difference("Integer property", args.DefaultDifference.Value1, args.DefaultDifference.Value2)); + } + else if (currentProperty.Member.Name == nameof(C.Property1)) + { + options.UseDifferenceFactory(args => new Difference("First property", args.DefaultDifference.Value1, args.DefaultDifference.Value2)); + } + }) + .ConfigureDifferencePath((parentProperty, options) => + { + if (parentProperty.Member.Name == nameof(A.ListOfC)) + { + options.UseInsertPathFactory(args => "Collection of C objects"); + } + }); + + var comparer = new Comparer(settings); + + var differences = comparer.CalculateDifferences(a1, a2).ToArray(); + + Assert.IsTrue(differences.Any(diff => diff.MemberPath == "Integer property")); + Assert.IsTrue(differences.Any(diff => diff.MemberPath == "TestProperty2")); + Assert.IsTrue(differences.Any(diff => diff.MemberPath == "Collection of C objects[0].First property")); + } + + //[Test] + //public void CreateDifferenceIncludeRawValues() + //{ + // var sourceDifference = new Difference( + // memberPath: "PathXY", + // value1: "VALUE1", + // value2: "VALUE2", + // rawValue1: new { Value = "VALUE1" }, + // rawValue2: new { Value = "VALUE2" }, + // differenceType: DifferenceTypes.TypeMismatch); + + // var differenceTreeNode = new DifferenceTreeNode(new DifferenceTreeNodeMember()); + // var settings = new ComparisonSettings(); + + // settings.ConfigureDifference(includeRawValues: true); + + // var targetDifference = DifferenceProvider.CreateDifference(settings, differenceTreeNode, sourceDifference,null, null); + + // Assert.IsTrue(targetDifference == sourceDifference); + //} + + //[Test] + //public void CreateDifferenceNotIncludeRawValues() + //{ + // var sourceDifference = new Difference( + // memberPath: "PathXY", + // value1: "VALUE1", + // value2: "VALUE2", + // rawValue1: new { Value = "VALUE1" }, + // rawValue2: new { Value = "VALUE2" }, + // differenceType: DifferenceTypes.TypeMismatch); + + // var differenceTreeNode = new DifferenceTreeNode(new DifferenceTreeNodeMember()); + // var settings = new ComparisonSettings(); + + // settings.ConfigureDifference(includeRawValues: false); + + // var targetDifference = DifferenceProvider.CreateDifference(settings, differenceTreeNode, sourceDifference, null, null); + + // Assert.IsTrue(targetDifference.MemberPath == targetDifference.MemberPath); + // Assert.IsTrue(targetDifference.Value1 == targetDifference.Value1); + // Assert.IsTrue(targetDifference.Value2 == targetDifference.Value2); + // Assert.IsTrue(targetDifference.RawValue2 == null); + // Assert.IsTrue(targetDifference.RawValue1 == null); + // Assert.IsFalse(targetDifference == sourceDifference); + // } + + //[Test] + //[TestCase(true)] + //[TestCase(false)] + //public void NoDifferenceFactorySourceTargetDifferenceEquality(bool includeRawValues) + //{ + // var differenceTreeNode = new DifferenceTreeNode(new DifferenceTreeNodeMember()); + // var settings = new ComparisonSettings(); + + // settings.ConfigureDifference(includeRawValues); + + // var sourceDifference = new Difference( + // memberPath: "PathXY", + // value1: "VALUE1", + // value2: "VALUE2", + // rawValue1: new { Value = "VALUE1" }, + // rawValue2: new { Value = "VALUE2" }, + // differenceType: DifferenceTypes.TypeMismatch); + + // var targetDifference = DifferenceProvider.CreateDifference(settings, differenceTreeNode, sourceDifference, null, null); + + // Assert.AreEqual(includeRawValues, sourceDifference == targetDifference); + // Assert.AreEqual(includeRawValues, targetDifference.RawValue1 != null); + // Assert.AreEqual(includeRawValues, targetDifference.RawValue2 != null); + //} + } } diff --git a/ObjectsComparer/ObjectsComparer.Tests/DifferenceTreeNodeTests.cs b/ObjectsComparer/ObjectsComparer.Tests/DifferenceTreeNodeTests.cs index 06957c6..05c61af 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/DifferenceTreeNodeTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/DifferenceTreeNodeTests.cs @@ -95,6 +95,70 @@ public void TestThrowDifferenceTreeBuilderNotImplementedException() Assert.Throws(() => comparer.TryBuildDifferenceTree("hello", "hi", rootNode).ToArray()); } + [Test] + public void TestThrowDifferenceTreeBuilderNotImplemented_ConfigureListComparison() + { + var settings = new ComparisonSettings(); + + settings.ConfigureListComparison(); + + var factory = new CustomComparersFactory(); + var comparer = factory.GetObjectsComparer(settings); + + var a1 = new A { ClassB = new B() }; + var a2 = new A { ClassB = new B() }; + + Assert.Throws(() => comparer.CalculateDifferences(a1, a2).ToArray()); + } + + [Test] + public void TestThrowDifferenceTreeBuilderNotImplemented_ConfigureDifference() + { + var settings = new ComparisonSettings(); + + settings.ConfigureDifference(false); + + var factory = new CustomComparersFactory(); + var comparer = factory.GetObjectsComparer(settings); + + var a1 = new A { ClassB = new B() }; + var a2 = new A { ClassB = new B() }; + + Assert.Throws(() => comparer.CalculateDifferences(a1, a2).ToArray()); + } + + [Test] + public void TestThrowDifferenceTreeBuilderNotImplemented_ConfigureDifferenceTree() + { + var settings = new ComparisonSettings(); + + settings.ConfigureDifferenceTree((_, options) => { }); + + var factory = new CustomComparersFactory(); + var comparer = factory.GetObjectsComparer(settings); + + var a1 = new A { ClassB = new B() }; + var a2 = new A { ClassB = new B() }; + + Assert.Throws(() => comparer.CalculateDifferences(a1, a2).ToArray()); + } + + [Test] + public void TestThrowDifferenceTreeBuilderNotImplemented_ConfigureDifferencePath() + { + var settings = new ComparisonSettings(); + + settings.ConfigureDifferencePath((_, options) => { }); + + var factory = new CustomComparersFactory(); + var comparer = factory.GetObjectsComparer(settings); + + var a1 = new A { ClassB = new B() }; + var a2 = new A { ClassB = new B() }; + + Assert.Throws(() => comparer.CalculateDifferences(a1, a2).ToArray()); + } + [Test] public void EnumerateConditional() { @@ -190,12 +254,17 @@ class CustomComparersFactory : ComparersFactory { public override IComparer GetObjectsComparer(ComparisonSettings settings = null, BaseComparer parentComparer = null) { - if (typeof(T) != typeof(string)) + if (typeof(T) == typeof(B)) + { + return (IComparer)new CustomClassBComparer(settings, parentComparer, this); + } + + if (typeof(T) == typeof(string)) { - return base.GetObjectsComparer(settings, parentComparer); + return (IComparer)new CustomStringComparer(settings, parentComparer, this); } - return (IComparer)new CustomStringComparer(settings, parentComparer, this); + return base.GetObjectsComparer(settings, parentComparer); } } @@ -206,6 +275,20 @@ public CustomStringComparer(ComparisonSettings settings, BaseComparer parentComp } public override IEnumerable CalculateDifferences(string obj1, string obj2) + { + //var comparer = Factory.GetObjectsComparer(obj1.GetType()); + //return comparer.CalculateDifferences(obj1, obj2); + throw new NotImplementedException(); + } + } + + class CustomClassBComparer : AbstractComparer + { + public CustomClassBComparer(ComparisonSettings settings, BaseComparer parentComparer, IComparersFactory factory) : base(settings, parentComparer, factory) + { + } + + public override IEnumerable CalculateDifferences(B obj1, B obj2) { throw new NotImplementedException(); } diff --git a/ObjectsComparer/ObjectsComparer/BaseComparer.cs b/ObjectsComparer/ObjectsComparer/BaseComparer.cs index 036a937..e7d379e 100644 --- a/ObjectsComparer/ObjectsComparer/BaseComparer.cs +++ b/ObjectsComparer/ObjectsComparer/BaseComparer.cs @@ -244,5 +244,19 @@ protected virtual Difference CreateDifference(IDifferenceTreeNode differenceTree return customDifference; } + + protected virtual void InsertPathToDifference(Difference difference, string defaultRootElementPath, IDifferenceTreeNode rootNode, IDifferenceTreeNode differenceNode) + { + var differencePathOptions = DifferencePathOptions.Default(); + + Settings.DifferencePathOptionsAction?.Invoke(rootNode, differencePathOptions); + + if (differencePathOptions.InsertPathFactory != null) + { + defaultRootElementPath = differencePathOptions.InsertPathFactory(new InsertPathFactoryArgs(defaultRootElementPath, differenceNode)); + } + + difference.InsertPath(defaultRootElementPath); + } } } \ No newline at end of file diff --git a/ObjectsComparer/ObjectsComparer/Comparer~1.cs b/ObjectsComparer/ObjectsComparer/Comparer~1.cs index 95fd5e8..fc1bc17 100644 --- a/ObjectsComparer/ObjectsComparer/Comparer~1.cs +++ b/ObjectsComparer/ObjectsComparer/Comparer~1.cs @@ -84,7 +84,6 @@ IEnumerable BuildDifferenceTree(T obj1, T obj2, MemberInfo m if (!comparer.Compare(obj1, obj2, Settings)) { yield return AddDifferenceToTree(differenceTreeNode, string.Empty, comparer.ToString(obj1), comparer.ToString(obj2), DifferenceTypes.ValueMismatch, obj1, obj2); - //yield return AddDifferenceToTree(new Difference(string.Empty, comparer.ToString(obj1), comparer.ToString(obj2)), differenceTreeNode); DaN AddDifferenceToTree } yield break; @@ -109,7 +108,6 @@ IEnumerable BuildDifferenceTree(T obj1, T obj2, MemberInfo m if (!DefaultValueComparer.Compare(obj1, obj2, Settings)) { yield return AddDifferenceToTree(differenceTreeNode, string.Empty, DefaultValueComparer.ToString(obj1), DefaultValueComparer.ToString(obj2), DifferenceTypes.ValueMismatch, obj1, obj2); - //yield return AddDifferenceToTree(new Difference(string.Empty, DefaultValueComparer.ToString(obj1), DefaultValueComparer.ToString(obj2)), differenceTreeNode); DaN AddDifferenceToTree } yield break; @@ -155,7 +153,7 @@ IEnumerable BuildDifferenceTree(T obj1, T obj2, MemberInfo m foreach (var failure in objectDataComparer.TryBuildDifferenceTree(type, value1, value2, memberNode)) { - failure.Difference.InsertPath(member.Name); + InsertPathToDifference(failure.Difference, member.Name, memberNode, failure.TreeNode); yield return failure; } @@ -165,7 +163,6 @@ IEnumerable BuildDifferenceTree(T obj1, T obj2, MemberInfo m if (!valueComparer.Compare(value1, value2, Settings)) { yield return AddDifferenceToTree(memberNode, member.Name, valueComparer.ToString(value1), valueComparer.ToString(value2), DifferenceTypes.ValueMismatch, value1, value2); - //yield return AddDifferenceToTree(new Difference(member.Name, valueComparer.ToString(value1), valueComparer.ToString(value2)), memberNode); //DaN AddDifferenceToTree } } } diff --git a/ObjectsComparer/ObjectsComparer/ComparisonSettings.cs b/ObjectsComparer/ObjectsComparer/ComparisonSettings.cs index 19cb924..d70502c 100644 --- a/ObjectsComparer/ObjectsComparer/ComparisonSettings.cs +++ b/ObjectsComparer/ObjectsComparer/ComparisonSettings.cs @@ -67,7 +67,7 @@ public T GetCustomSetting(string key = null) throw new KeyNotFoundException(); } - internal Action ListComparisonOptionsAction { get; private set; } = null; + public Action ListComparisonOptionsAction { get; private set; } = null; /// /// - /// First parameter: The parent of the property to which the path is inserted. + /// First parameter type: The parent of the member to which the path is inserted. /// public ComparisonSettings ConfigureDifferencePath(Action options) { diff --git a/ObjectsComparer/ObjectsComparer/DifferenceOptions.cs b/ObjectsComparer/ObjectsComparer/DifferenceOptions.cs index 00cd6ff..116b3f7 100644 --- a/ObjectsComparer/ObjectsComparer/DifferenceOptions.cs +++ b/ObjectsComparer/ObjectsComparer/DifferenceOptions.cs @@ -28,7 +28,7 @@ public class DifferenceOptions /// /// /// Null value is allowed here and means that a default behavior of creation of the difference is required.
- /// Func first parameter: The args for the difference creation.
+ /// First parameter type: The args for the difference creation, see .
/// Returns: Transformed difference or the source difference itself. /// /// diff --git a/ObjectsComparer/ObjectsComparer/DifferencePathOptions.cs b/ObjectsComparer/ObjectsComparer/DifferencePathOptions.cs index 2ddcc1b..f8e83d5 100644 --- a/ObjectsComparer/ObjectsComparer/DifferencePathOptions.cs +++ b/ObjectsComparer/ObjectsComparer/DifferencePathOptions.cs @@ -2,6 +2,9 @@ namespace ObjectsComparer { + /// + /// Configures the insertion into the difference path. + /// public class DifferencePathOptions { DifferencePathOptions() @@ -20,8 +23,8 @@ public class DifferencePathOptions /// /// /// Null value is allowed here and means that a default behavior of the insertion into the difference path is required.
- /// Func first parameter: The args for the path insertion.
- /// Returns: Transformed root path element or the not transformed root path element itself. + /// First parameter type: The args for the path insertion, see .
+ /// Returns: Transformed root path element or not transformed root path element itself. /// public void UseInsertPathFactory(Func factory) { diff --git a/ObjectsComparer/ObjectsComparer/DifferenceTree/ComparerExtensions.cs b/ObjectsComparer/ObjectsComparer/DifferenceTree/ComparerExtensions.cs index dfe597a..7999e2b 100644 --- a/ObjectsComparer/ObjectsComparer/DifferenceTree/ComparerExtensions.cs +++ b/ObjectsComparer/ObjectsComparer/DifferenceTree/ComparerExtensions.cs @@ -11,10 +11,14 @@ public static class ComparerExtensions /// /// Calculates the difference tree. /// - /// Current comparison context, see . The return value tells the comparison process whether to look for another difference. If the argument is null the process is looking for all the differences. - /// Occurs when (and only when) the comparison process reaches the last member of the objects being compared. - /// The root node of the difference tree. - public static IDifferenceTreeNode CalculateDifferenceTree(this IComparer comparer, Type type, object obj1, object obj2, Func findNextDifference = null, Action differenceTreeCompleted = null) + /// + /// Comparison process listener. If the argument is null the process is looking for all the differences at once.
+ /// First parameter type: Current comparison context, see .
+ /// Second parameter type: Whether to look for another difference. If value = false the comparison process will be terminated immediately. + /// + /// Occurs if (and only if) the comparison process reaches the last member of the objects being compared. + /// The root node of the difference tree, see . + public static IDifferenceTreeNode CalculateDifferenceTree(this IComparer comparer, Type type, object obj1, object obj2, Func comparisonListener = null, Action differenceTreeCompleted = null) { if (comparer is null) { @@ -26,7 +30,7 @@ public static IDifferenceTreeNode CalculateDifferenceTree(this IComparer compare throw new ArgumentNullException(nameof(type)); } - findNextDifference = findNextDifference ?? ((_) => true); + comparisonListener = comparisonListener ?? ((_) => true); //Anything but ImplicitDifferenceTreeNode. var rootNode = DifferenceTreeNodeProvider.CreateNode(comparer.Settings, ancestor: null); @@ -36,7 +40,7 @@ public static IDifferenceTreeNode CalculateDifferenceTree(this IComparer compare differenceLocationList.EnumerateConditional( currentLocation => { - return findNextDifference(new ComparisonContext(rootNode, currentLocation.Difference, currentLocation.TreeNode)); + return comparisonListener(new ComparisonContext(rootNode, currentLocation.Difference, currentLocation.TreeNode)); }, differenceTreeCompleted); @@ -46,17 +50,21 @@ public static IDifferenceTreeNode CalculateDifferenceTree(this IComparer compare /// /// Calculates the difference tree. /// - /// Current comparison context. The return value tells the comparison process whether to look for another difference. If the argument is null the process is looking for all the differences. - /// Occurs when (and only when) the comparison process reaches the last member of the objects being compared. - /// The root node of the difference tree. - public static IDifferenceTreeNode CalculateDifferenceTree(this IComparer comparer, T obj1, T obj2, Func findNextDifference = null, Action differenceTreeCompleted = null) + /// + /// Comparison process listener. If the argument is null the process is looking for all the differences at once.
+ /// First parameter type: Current comparison context, see .
+ /// Second parameter type: Whether to look for another difference. If value = false the comparison process will be terminated immediately. + /// + /// Occurs if (and only if) the comparison process reaches the last member of the objects being compared. + /// The root node of the difference tree, see . + public static IDifferenceTreeNode CalculateDifferenceTree(this IComparer comparer, T obj1, T obj2, Func comparisonListener = null, Action differenceTreeCompleted = null) { if (comparer is null) { throw new ArgumentNullException(nameof(comparer)); } - findNextDifference = findNextDifference ?? ((_) => true); + comparisonListener = comparisonListener ?? ((_) => true); //Anything but ImplicitDifferenceTreeNode. var rootNode = DifferenceTreeNodeProvider.CreateNode(comparer.Settings, ancestor: null); @@ -66,7 +74,7 @@ public static IDifferenceTreeNode CalculateDifferenceTree(this IComparer c differenceLocationList.EnumerateConditional( currentLocation => { - return findNextDifference(new ComparisonContext(rootNode, currentLocation.Difference, currentLocation.TreeNode)); + return comparisonListener(new ComparisonContext(rootNode, currentLocation.Difference, currentLocation.TreeNode)); }, differenceTreeCompleted); diff --git a/ObjectsComparer/ObjectsComparer/DifferenceTree/ComparisonContext.cs b/ObjectsComparer/ObjectsComparer/DifferenceTree/ComparisonContext.cs index 7205a0c..71f664e 100644 --- a/ObjectsComparer/ObjectsComparer/DifferenceTree/ComparisonContext.cs +++ b/ObjectsComparer/ObjectsComparer/DifferenceTree/ComparisonContext.cs @@ -3,21 +3,21 @@ namespace ObjectsComparer { /// - /// The current context of the comparison in the process of creating the difference tree. For more info, see , or . + /// The context of the comparison in the process of creating the difference tree. For more info, see , or . /// public class ComparisonContext { public IDifferenceTreeNode RootNode { get; } - public Difference CurrentDifference { get; } + public Difference Difference { get; } - public IDifferenceTreeNode CurrentNode { get; } + public IDifferenceTreeNode Node { get; } public ComparisonContext(IDifferenceTreeNode rootNode, Difference currentDifference, IDifferenceTreeNode currentNode = null) { RootNode = rootNode ?? throw new ArgumentNullException(nameof(rootNode)); - CurrentDifference = currentDifference ?? throw new ArgumentNullException(nameof(currentDifference)); - CurrentNode = currentNode; + Difference = currentDifference ?? throw new ArgumentNullException(nameof(currentDifference)); + Node = currentNode; } } } diff --git a/ObjectsComparer/ObjectsComparer/DifferenceTree/DifferenceTreeOptions.cs b/ObjectsComparer/ObjectsComparer/DifferenceTree/DifferenceTreeOptions.cs index c342b58..5edbd90 100644 --- a/ObjectsComparer/ObjectsComparer/DifferenceTree/DifferenceTreeOptions.cs +++ b/ObjectsComparer/ObjectsComparer/DifferenceTree/DifferenceTreeOptions.cs @@ -18,11 +18,13 @@ internal static DifferenceTreeOptions Default() internal Func DifferenceTreeNodeFactory { get; private set; } internal Func DifferenceTreeNodeMemberFactory { get; private set; } - + /// /// Factory for instances. /// - /// + /// + /// First parameter type: The member the tree node is created for. It can be replaced by a custom instance. + /// public void UseDifferenceTreeNodeFactory(Func factory) { DifferenceTreeNodeFactory = factory ?? throw new ArgumentNullException(nameof(factory)); @@ -31,6 +33,9 @@ public void UseDifferenceTreeNodeFactory(Func /// Factory for instances. /// + /// + /// First parameter type: Default member, can be used as a falback. + /// public void UseDifferenceTreeNodeMemberFactory(Func factory) { DifferenceTreeNodeMemberFactory = factory ?? throw new ArgumentNullException(nameof(factory)); diff --git a/ObjectsComparer/ObjectsComparer/InsertPathFactoryArgs.cs b/ObjectsComparer/ObjectsComparer/InsertPathFactoryArgs.cs index 2f1453e..918008a 100644 --- a/ObjectsComparer/ObjectsComparer/InsertPathFactoryArgs.cs +++ b/ObjectsComparer/ObjectsComparer/InsertPathFactoryArgs.cs @@ -1,5 +1,8 @@ namespace ObjectsComparer { + /// + /// Arguments for . + /// public class InsertPathFactoryArgs { public InsertPathFactoryArgs(string defaultRootElementPath, IDifferenceTreeNode childNode) diff --git a/ObjectsComparer/ObjectsComparer/ListElementComparisonByKeyOptions.cs b/ObjectsComparer/ObjectsComparer/ListElementComparisonByKeyOptions.cs index 81f78d1..c445fc4 100644 --- a/ObjectsComparer/ObjectsComparer/ListElementComparisonByKeyOptions.cs +++ b/ObjectsComparer/ObjectsComparer/ListElementComparisonByKeyOptions.cs @@ -144,7 +144,8 @@ public ListElementComparisonByKeyOptions UseKey(string[] keys, bool caseSensitiv /// /// Key identification. It attempts to find the key using the parameter. /// - /// First parameter: The element whose key is required. Return value: The element's key. + /// First parameter type: The element whose key is required, see .
+ /// Return value: The element's key. public ListElementComparisonByKeyOptions UseKey(Func keyProvider) { if (keyProvider is null) @@ -281,7 +282,10 @@ public ListElementComparisonByKeyOptions FormatElementKey(Func property.
/// By default, template will be used to format the identifier. /// - /// First parameter: Element index. Return value: Formatted identifier. + /// + /// First parameter type: Element index.
+ /// Second parameter type: Formatted identifier. + /// public ListElementComparisonByKeyOptions FormatNullElementIdentifier(Func formatter) { if (formatter is null) From a64a5264a6076d5477a3989b7fa10b9e1353e3fb Mon Sep 17 00:00:00 2001 From: nemec Date: Wed, 13 Jul 2022 23:47:01 +0200 Subject: [PATCH 178/181] Edit difference test methods. --- .../Comparer_GenericEnumerableTests.cs | 96 ++++++++++++++++++- .../TestClasses/Address.cs | 3 + .../TestClasses/Person.cs | 2 + .../TestClasses/Student.cs | 2 + .../ObjectsComparer/ComparisonSettings.cs | 44 +++++++-- 5 files changed, 135 insertions(+), 12 deletions(-) diff --git a/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs b/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs index 301db5a..7856997 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs @@ -13,6 +13,8 @@ using System.Collections; using System.Reflection; using System.IO; +using System.ComponentModel; +using DescriptionAttribute = System.ComponentModel.DescriptionAttribute; namespace ObjectsComparer.Tests { @@ -2012,7 +2014,7 @@ public void CalculateCompletedDifferenceTree() ListOfAddress2 */ - using (var sr = new System.IO.StringReader(differenceTreeStr)) + using (var sr = new StringReader(differenceTreeStr)) { var expectedLine = sr.ReadLine(); Assert.AreEqual(expectedLine.Trim(), "?"); @@ -2175,7 +2177,7 @@ public void CalculateDifferencesTranslateMembers() }; var settings = new ComparisonSettings(); - settings.ConfigureDifference(defaultMemberName => TranslateToCzech(defaultMemberName)); + settings.ConfigureDifferences(defaultMember => TranslateToCzech(defaultMember.Name)); var comparer = new Comparer(settings); var differences = comparer.CalculateDifferences(student1, student2).ToArray(); @@ -2184,6 +2186,77 @@ public void CalculateDifferencesTranslateMembers() Assert.IsTrue(differences.Any(d => d.DifferenceType == DifferenceTypes.ValueMismatch && d.MemberPath == "Osoba.Seznam adres 1[0].Stát" && d.Value1 == "Czech republic" && d.Value2 == "Czechia")); } + [Test] + public void CalculateDifferenceTreeTranslateMembersUsingAttributes() + { + var student1 = new Student + { + Person = new Person + { + ListOfAddress1 = new List
+ { + new Address { City = "Prague", Country = "Czech republic" }, + new Address { City = "Pilsen", Country = "Czech republic" } + } + } + }; + + var student2 = new Student + { + Person = new Person + { + ListOfAddress1 = new List
+ { + new Address { City = "Olomouc", Country = "Czechia" }, + new Address { City = "Pilsen", Country = "Czech republic" } + } + } + }; + + var settings = new ComparisonSettings(); + settings.ConfigureDifferences(defaultMember => TranslateToCzech(defaultMember)); + var comparer = new Comparer(settings); + var rootNode = comparer.CalculateDifferenceTree(student1, student2); + rootNode.Shrink(); + + Assert.AreEqual(2, rootNode.GetDifferences(recursive: true).Count()); + + var stringBuilder = new StringBuilder(); + WalkDifferenceTree(rootNode, 0, stringBuilder); + var differenceTreeStr = stringBuilder.ToString(); + + /* differenceTreeStr (shrinked): + ? + Člověk + Kolekce adres + [0] + Aglomerace (město) + Difference: DifferenceType=ValueMismatch, MemberPath='Člověk.Kolekce adres[0].Aglomerace (město)', Value1='Prague', Value2='Olomouc'. + Země (stát) + Difference: DifferenceType=ValueMismatch, MemberPath='Člověk.Kolekce adres[0].Země (stát)', Value1='Czech republic', Value2='Czechia'. + */ + + using (var sr = new StringReader(differenceTreeStr)) + { + var expectedLine = sr.ReadLine(); + Assert.AreEqual(expectedLine.Trim(), "?"); + expectedLine = sr.ReadLine(); + Assert.AreEqual(expectedLine.Trim(), "Člověk"); + expectedLine = sr.ReadLine(); + Assert.AreEqual(expectedLine.Trim(), "Kolekce adres"); + expectedLine = sr.ReadLine(); + Assert.AreEqual(expectedLine.Trim(), "[0]"); + expectedLine = sr.ReadLine(); + Assert.AreEqual(expectedLine.Trim(), "Aglomerace (město)"); + expectedLine = sr.ReadLine(); + Assert.AreEqual(expectedLine.Trim(), "Difference: DifferenceType=ValueMismatch, MemberPath='Člověk.Kolekce adres[0].Aglomerace (město)', Value1='Prague', Value2='Olomouc'."); + expectedLine = sr.ReadLine(); + Assert.AreEqual(expectedLine.Trim(), "Země (stát)"); + expectedLine = sr.ReadLine(); + Assert.AreEqual(expectedLine.Trim(), "Difference: DifferenceType=ValueMismatch, MemberPath='Člověk.Kolekce adres[0].Země (stát)', Value1='Czech republic', Value2='Czechia'."); + } + } + [Test] public void CalculateDifferenceTreeTranslateMembers() { @@ -2212,7 +2285,7 @@ public void CalculateDifferenceTreeTranslateMembers() }; var settings = new ComparisonSettings(); - settings.ConfigureDifference(defaultMemberName => TranslateToCzech(defaultMemberName)); + settings.ConfigureDifferences(defaultMember => TranslateToCzech(defaultMember?.Name)); var comparer = new Comparer(settings); var rootNode = comparer.CalculateDifferenceTree(student1, student2); rootNode.Shrink(); @@ -2255,6 +2328,23 @@ Seznam adres 1 } } + string TranslateToCzech(MemberInfo member) + { + if (member == null) + { + return null; + } + + var descriptionAttr = member.GetCustomAttribute(); + + if (descriptionAttr != null) + { + return descriptionAttr.Description; + } + + return TranslateToCzech(member.Name); + } + string TranslateToCzech(string original) { var translated = original; diff --git a/ObjectsComparer/ObjectsComparer.Tests/TestClasses/Address.cs b/ObjectsComparer/ObjectsComparer.Tests/TestClasses/Address.cs index 1981bde..e3d90c5 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/TestClasses/Address.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/TestClasses/Address.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.ComponentModel; namespace ObjectsComparer.Tests.TestClasses { @@ -6,8 +7,10 @@ public class Address { public int Id { get; set; } + [Description("Aglomerace (město)")] public string City { get; set; } + [Description("Země (stát)")] public string Country { get; set; } public string State { get; set; } diff --git a/ObjectsComparer/ObjectsComparer.Tests/TestClasses/Person.cs b/ObjectsComparer/ObjectsComparer.Tests/TestClasses/Person.cs index b561c60..6b8e100 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/TestClasses/Person.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/TestClasses/Person.cs @@ -1,5 +1,6 @@ using System.Collections; using System.Collections.Generic; +using System.ComponentModel; namespace ObjectsComparer.Tests.TestClasses { @@ -13,6 +14,7 @@ public class Person public string PhoneNumber { get; set; } + [Description("Kolekce adres")] public List
ListOfAddress1 { get; set; } public List
ListOfAddress2 { get; set; } diff --git a/ObjectsComparer/ObjectsComparer.Tests/TestClasses/Student.cs b/ObjectsComparer/ObjectsComparer.Tests/TestClasses/Student.cs index a68ca71..ef01419 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/TestClasses/Student.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/TestClasses/Student.cs @@ -1,9 +1,11 @@ using System.Collections.Generic; +using System.ComponentModel; namespace ObjectsComparer.Tests.TestClasses { public class Student { + [Description("Člověk")] public Person Person { get; set; } } } diff --git a/ObjectsComparer/ObjectsComparer/ComparisonSettings.cs b/ObjectsComparer/ObjectsComparer/ComparisonSettings.cs index f7beb03..3baf3e5 100644 --- a/ObjectsComparer/ObjectsComparer/ComparisonSettings.cs +++ b/ObjectsComparer/ObjectsComparer/ComparisonSettings.cs @@ -1,5 +1,7 @@ using System; using System.Collections.Generic; +using System.Reflection; +using System.Collections; namespace ObjectsComparer { @@ -15,7 +17,7 @@ public partial class ComparisonSettings public bool RecursiveComparison { get; set; } /// - /// If true, empty and null values will be considered as equal values. False by default. + /// If true, empty and null values will be considered as equal values. False by default. /// public bool EmptyAndNullEnumerablesEqual { get; set; } @@ -166,26 +168,50 @@ public ComparisonSettings ConfigureDifference(bool includeRawValues) return this; } - public ComparisonSettings ConfigureDifference(Func memberNameProvider, bool includeRawValues = false) + //public ComparisonSettings ConfigureDifferences(Func memberNameProvider, bool includeRawValues = false) + //{ + // ConfigureDifferenceTree((_, options) => + // options.UseDifferenceTreeNodeMemberFactory(defaultMember => + // new DifferenceTreeNodeMember( + // defaultMember.Info, + // memberNameProvider(defaultMember.Name)))); + + // ConfigureDifference((_, options) => + // options.UseDifferenceFactory(args => + // new Difference( + // memberPath: memberNameProvider(args.DefaultDifference.MemberPath), + // args.DefaultDifference.Value1, + // args.DefaultDifference.Value2, + // args.DefaultDifference.DifferenceType, + // rawValue1: includeRawValues ? args.RawValue1 : null, + // rawValue2: includeRawValues ? args.RawValue2 : null))); + + // ConfigureDifferencePath((_, options) => + // options.UseInsertPathFactory(args => memberNameProvider(args.DefaultRootElementPath))); + + // return this; + //} + + public ComparisonSettings ConfigureDifferences(Func memberNameProvider, bool includeRawValues = false) { - ConfigureDifferenceTree((_, options) => + ConfigureDifferenceTree((ancestor, options) => options.UseDifferenceTreeNodeMemberFactory(defaultMember => new DifferenceTreeNodeMember( - defaultMember.Info, - memberNameProvider(defaultMember.Name)))); + defaultMember?.Info, + memberNameProvider(defaultMember?.Info)))); - ConfigureDifference((_, options) => + ConfigureDifference((currentMember, options) => options.UseDifferenceFactory(args => new Difference( - memberPath: memberNameProvider(args.DefaultDifference.MemberPath), + memberPath: memberNameProvider(currentMember.Member.Info), args.DefaultDifference.Value1, args.DefaultDifference.Value2, args.DefaultDifference.DifferenceType, rawValue1: includeRawValues ? args.RawValue1 : null, rawValue2: includeRawValues ? args.RawValue2 : null))); - ConfigureDifferencePath((_, options) => - options.UseInsertPathFactory(args => memberNameProvider(args.DefaultRootElementPath))); + ConfigureDifferencePath((ancestor, options) => + options.UseInsertPathFactory(args => memberNameProvider(ancestor.Member.Info))); return this; } From aa4375c2addadb796756bd1393eda46425675539 Mon Sep 17 00:00:00 2001 From: Daniel Nemec Date: Thu, 14 Jul 2022 09:11:07 +0200 Subject: [PATCH 179/181] Move some test methods to DifferenceConfigurationTests. Edit comments. --- .../Comparer_GenericEnumerableTests.cs | 493 +---------------- .../DifferenceConfigurationTests.cs | 522 +++++++++++++++++- .../ObjectsComparer/ComparisonSettings.cs | 41 +- .../ObjectsComparer/DifferenceOptions.cs | 2 +- .../ObjectsComparer/DifferencePathOptions.cs | 2 +- .../DifferenceTree/ComparerExtensions.cs | 4 +- .../DifferenceTree/DifferenceTreeOptions.cs | 4 +- .../ListElementComparisonByKeyOptions.cs | 4 +- 8 files changed, 543 insertions(+), 529 deletions(-) diff --git a/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs b/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs index 7856997..2128bb0 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs @@ -1948,498 +1948,7 @@ public TestClassB ClassBProperty set => _classBProperty = value; } } - - [Test] - public void CalculateCompletedDifferenceTree() - { - var student1 = new Student - { - Person = new Person - { - ListOfAddress1 = new List
- { - new Address { City = "Prague", Country = "Czech republic" }, - new Address { City = "Pilsen", Country = "Czech republic" } - } - } - }; - - var student2 = new Student - { - Person = new Person - { - ListOfAddress1 = new List
- { - new Address { City = "Olomouc", Country = "Czechia" }, - new Address { City = "Pilsen", Country = "Czech republic" } - } - } - }; - - var comparer = new Comparer(); - - var rootNode = comparer.CalculateDifferenceTree(student1, student2); - - Assert.AreEqual(2, rootNode.GetDifferences(recursive: true).Count()); - - var stringBuilder = new StringBuilder(); - WalkDifferenceTree(rootNode, 0, stringBuilder); - var differenceTreeStr = stringBuilder.ToString(); - - /* - * differenceTreeStr: - ? - Person - FirstName - LastName - Birthdate - PhoneNumber - ListOfAddress1 - [0] - Id - City - Difference: DifferenceType=ValueMismatch, MemberPath='Person.ListOfAddress1[0].City', Value1='Prague', Value2='Olomouc'. - Country - Difference: DifferenceType=ValueMismatch, MemberPath='Person.ListOfAddress1[0].Country', Value1='Czech republic', Value2='Czechia'. - State - PostalCode - Street - [1] - Id - City - Country - State - PostalCode - Street - ListOfAddress2 - */ - - using (var sr = new StringReader(differenceTreeStr)) - { - var expectedLine = sr.ReadLine(); - Assert.AreEqual(expectedLine.Trim(), "?"); - expectedLine = sr.ReadLine(); - Assert.AreEqual(expectedLine.Trim(), "Person"); - expectedLine = sr.ReadLine(); - Assert.AreEqual(expectedLine.Trim(), "FirstName"); - expectedLine = sr.ReadLine(); - Assert.AreEqual(expectedLine.Trim(), "LastName"); - expectedLine = sr.ReadLine(); - Assert.AreEqual(expectedLine.Trim(), "Birthdate"); - expectedLine = sr.ReadLine(); - Assert.AreEqual(expectedLine.Trim(), "PhoneNumber"); - expectedLine = sr.ReadLine(); - Assert.AreEqual(expectedLine.Trim(), "ListOfAddress1"); - expectedLine = sr.ReadLine(); - Assert.AreEqual(expectedLine.Trim(), "[0]"); - expectedLine = sr.ReadLine(); - Assert.AreEqual(expectedLine.Trim(), "Id"); - expectedLine = sr.ReadLine(); - Assert.AreEqual(expectedLine.Trim(), "City"); - expectedLine = sr.ReadLine(); - Assert.AreEqual(expectedLine.Trim(), "Difference: DifferenceType=ValueMismatch, MemberPath='Person.ListOfAddress1[0].City', Value1='Prague', Value2='Olomouc'."); - expectedLine = sr.ReadLine(); - Assert.AreEqual(expectedLine.Trim(), "Country"); - expectedLine = sr.ReadLine(); - Assert.AreEqual(expectedLine.Trim(), "Difference: DifferenceType=ValueMismatch, MemberPath='Person.ListOfAddress1[0].Country', Value1='Czech republic', Value2='Czechia'."); - } - - rootNode.Shrink(); - - stringBuilder = new StringBuilder(); - WalkDifferenceTree(rootNode, 0, stringBuilder); - differenceTreeStr = stringBuilder.ToString(); - - /* differenceTreeStr (shrinked): - ? - Person - ListOfAddress1 - [0] - City - Difference: DifferenceType=ValueMismatch, MemberPath='Person.ListOfAddress1[0].City', Value1='Prague', Value2='Olomouc'. - Country - Difference: DifferenceType=ValueMismatch, MemberPath='Person.ListOfAddress1[0].Country', Value1='Czech republic', Value2='Czechia'. - */ - - using (var sr = new System.IO.StringReader(differenceTreeStr)) - { - var expectedLine = sr.ReadLine(); - Assert.AreEqual(expectedLine.Trim(), "?"); - expectedLine = sr.ReadLine(); - Assert.AreEqual(expectedLine.Trim(), "Person"); - expectedLine = sr.ReadLine(); - Assert.AreEqual(expectedLine.Trim(), "ListOfAddress1"); - expectedLine = sr.ReadLine(); - Assert.AreEqual(expectedLine.Trim(), "[0]"); - expectedLine = sr.ReadLine(); - Assert.AreEqual(expectedLine.Trim(), "City"); - expectedLine = sr.ReadLine(); - Assert.AreEqual(expectedLine.Trim(), "Difference: DifferenceType=ValueMismatch, MemberPath='Person.ListOfAddress1[0].City', Value1='Prague', Value2='Olomouc'."); - expectedLine = sr.ReadLine(); - Assert.AreEqual(expectedLine.Trim(), "Country"); - expectedLine = sr.ReadLine(); - Assert.AreEqual(expectedLine.Trim(), "Difference: DifferenceType=ValueMismatch, MemberPath='Person.ListOfAddress1[0].Country', Value1='Czech republic', Value2='Czechia'."); - } - } - - [Test] - public void CalculateUncompletedDifferenceTree() - { - var student1 = new Student - { - Person = new Person - { - ListOfAddress1 = new List
- { - new Address { City = "Prague", Country = "Czech republic" }, - new Address { City = "Pilsen", Country = "Czech republic" } - } - } - }; - - var student2 = new Student - { - Person = new Person - { - ListOfAddress1 = new List
- { - new Address { City = "Olomouc", Country = "Czechia" }, - new Address { City = "Pilsen", Country = "Czech republic" } - } - } - }; - - var comparer = new Comparer(); - - var rootNode = comparer.CalculateDifferenceTree(student1, student2, ctx => false); - - Assert.AreEqual(1, rootNode.GetDifferences(recursive: true).Count()); - - rootNode.Shrink(); - - var stringBuilder = new StringBuilder(); - WalkDifferenceTree(rootNode, 0, stringBuilder); - var differenceTreeStr = stringBuilder.ToString(); - - /* differenceTreeStr (shrinked): - ? - Person - ListOfAddress1 - [0] - City - Difference: DifferenceType=ValueMismatch, MemberPath='Person.ListOfAddress1[0].City', Value1='Prague', Value2='Olomouc'. - */ - - using (var sr = new System.IO.StringReader(differenceTreeStr)) - { - var expectedLine = sr.ReadLine(); - Assert.AreEqual(expectedLine.Trim(), "?"); - expectedLine = sr.ReadLine(); - Assert.AreEqual(expectedLine.Trim(), "Person"); - expectedLine = sr.ReadLine(); - Assert.AreEqual(expectedLine.Trim(), "ListOfAddress1"); - expectedLine = sr.ReadLine(); - Assert.AreEqual(expectedLine.Trim(), "[0]"); - expectedLine = sr.ReadLine(); - Assert.AreEqual(expectedLine.Trim(), "City"); - expectedLine = sr.ReadLine(); - Assert.AreEqual(expectedLine.Trim(), "Difference: DifferenceType=ValueMismatch, MemberPath='Person.ListOfAddress1[0].City', Value1='Prague', Value2='Olomouc'."); - expectedLine = sr.ReadLine(); - Assert.AreEqual(expectedLine, null); - } - } - - [Test] - public void CalculateDifferencesTranslateMembers() - { - var student1 = new Student - { - Person = new Person - { - ListOfAddress1 = new List
- { - new Address { City = "Prague", Country = "Czech republic" }, - new Address { City = "Pilsen", Country = "Czech republic" } - } - } - }; - - var student2 = new Student - { - Person = new Person - { - ListOfAddress1 = new List
- { - new Address { City = "Olomouc", Country = "Czechia" }, - new Address { City = "Pilsen", Country = "Czech republic" } - } - } - }; - - var settings = new ComparisonSettings(); - settings.ConfigureDifferences(defaultMember => TranslateToCzech(defaultMember.Name)); - var comparer = new Comparer(settings); - var differences = comparer.CalculateDifferences(student1, student2).ToArray(); - - Assert.AreEqual(2, differences.Count()); - Assert.IsTrue(differences.Any(d => d.DifferenceType == DifferenceTypes.ValueMismatch && d.MemberPath == "Osoba.Seznam adres 1[0].Město" && d.Value1 == "Prague" && d.Value2 == "Olomouc")); - Assert.IsTrue(differences.Any(d => d.DifferenceType == DifferenceTypes.ValueMismatch && d.MemberPath == "Osoba.Seznam adres 1[0].Stát" && d.Value1 == "Czech republic" && d.Value2 == "Czechia")); - } - - [Test] - public void CalculateDifferenceTreeTranslateMembersUsingAttributes() - { - var student1 = new Student - { - Person = new Person - { - ListOfAddress1 = new List
- { - new Address { City = "Prague", Country = "Czech republic" }, - new Address { City = "Pilsen", Country = "Czech republic" } - } - } - }; - - var student2 = new Student - { - Person = new Person - { - ListOfAddress1 = new List
- { - new Address { City = "Olomouc", Country = "Czechia" }, - new Address { City = "Pilsen", Country = "Czech republic" } - } - } - }; - - var settings = new ComparisonSettings(); - settings.ConfigureDifferences(defaultMember => TranslateToCzech(defaultMember)); - var comparer = new Comparer(settings); - var rootNode = comparer.CalculateDifferenceTree(student1, student2); - rootNode.Shrink(); - - Assert.AreEqual(2, rootNode.GetDifferences(recursive: true).Count()); - - var stringBuilder = new StringBuilder(); - WalkDifferenceTree(rootNode, 0, stringBuilder); - var differenceTreeStr = stringBuilder.ToString(); - - /* differenceTreeStr (shrinked): - ? - Člověk - Kolekce adres - [0] - Aglomerace (město) - Difference: DifferenceType=ValueMismatch, MemberPath='Člověk.Kolekce adres[0].Aglomerace (město)', Value1='Prague', Value2='Olomouc'. - Země (stát) - Difference: DifferenceType=ValueMismatch, MemberPath='Člověk.Kolekce adres[0].Země (stát)', Value1='Czech republic', Value2='Czechia'. - */ - - using (var sr = new StringReader(differenceTreeStr)) - { - var expectedLine = sr.ReadLine(); - Assert.AreEqual(expectedLine.Trim(), "?"); - expectedLine = sr.ReadLine(); - Assert.AreEqual(expectedLine.Trim(), "Člověk"); - expectedLine = sr.ReadLine(); - Assert.AreEqual(expectedLine.Trim(), "Kolekce adres"); - expectedLine = sr.ReadLine(); - Assert.AreEqual(expectedLine.Trim(), "[0]"); - expectedLine = sr.ReadLine(); - Assert.AreEqual(expectedLine.Trim(), "Aglomerace (město)"); - expectedLine = sr.ReadLine(); - Assert.AreEqual(expectedLine.Trim(), "Difference: DifferenceType=ValueMismatch, MemberPath='Člověk.Kolekce adres[0].Aglomerace (město)', Value1='Prague', Value2='Olomouc'."); - expectedLine = sr.ReadLine(); - Assert.AreEqual(expectedLine.Trim(), "Země (stát)"); - expectedLine = sr.ReadLine(); - Assert.AreEqual(expectedLine.Trim(), "Difference: DifferenceType=ValueMismatch, MemberPath='Člověk.Kolekce adres[0].Země (stát)', Value1='Czech republic', Value2='Czechia'."); - } - } - - [Test] - public void CalculateDifferenceTreeTranslateMembers() - { - var student1 = new Student - { - Person = new Person - { - ListOfAddress1 = new List
- { - new Address { City = "Prague", Country = "Czech republic" }, - new Address { City = "Pilsen", Country = "Czech republic" } - } - } - }; - - var student2 = new Student - { - Person = new Person - { - ListOfAddress1 = new List
- { - new Address { City = "Olomouc", Country = "Czechia" }, - new Address { City = "Pilsen", Country = "Czech republic" } - } - } - }; - - var settings = new ComparisonSettings(); - settings.ConfigureDifferences(defaultMember => TranslateToCzech(defaultMember?.Name)); - var comparer = new Comparer(settings); - var rootNode = comparer.CalculateDifferenceTree(student1, student2); - rootNode.Shrink(); - - Assert.AreEqual(2, rootNode.GetDifferences(recursive: true).Count()); - - var stringBuilder = new StringBuilder(); - WalkDifferenceTree(rootNode, 0, stringBuilder); - var differenceTreeStr = stringBuilder.ToString(); - - /* differenceTreeStr (shrinked): - ? - Osoba - Seznam adres 1 - [0] - Město - Difference: DifferenceType=ValueMismatch, MemberPath='Osoba.Seznam adres 1[0].Město', Value1='Prague', Value2='Olomouc'. - Stát - Difference: DifferenceType=ValueMismatch, MemberPath='Osoba.Seznam adres 1[0].Stát', Value1='Czech republic', Value2='Czechia'. - */ - - using (var sr = new StringReader(differenceTreeStr)) - { - var expectedLine = sr.ReadLine(); - Assert.AreEqual(expectedLine.Trim(), "?"); - expectedLine = sr.ReadLine(); - Assert.AreEqual(expectedLine.Trim(), "Osoba"); - expectedLine = sr.ReadLine(); - Assert.AreEqual(expectedLine.Trim(), "Seznam adres 1"); - expectedLine = sr.ReadLine(); - Assert.AreEqual(expectedLine.Trim(), "[0]"); - expectedLine = sr.ReadLine(); - Assert.AreEqual(expectedLine.Trim(), "Město"); - expectedLine = sr.ReadLine(); - Assert.AreEqual(expectedLine.Trim(), "Difference: DifferenceType=ValueMismatch, MemberPath='Osoba.Seznam adres 1[0].Město', Value1='Prague', Value2='Olomouc'."); - expectedLine = sr.ReadLine(); - Assert.AreEqual(expectedLine.Trim(), "Stát"); - expectedLine = sr.ReadLine(); - Assert.AreEqual(expectedLine.Trim(), "Difference: DifferenceType=ValueMismatch, MemberPath='Osoba.Seznam adres 1[0].Stát', Value1='Czech republic', Value2='Czechia'."); - } - } - - string TranslateToCzech(MemberInfo member) - { - if (member == null) - { - return null; - } - - var descriptionAttr = member.GetCustomAttribute(); - - if (descriptionAttr != null) - { - return descriptionAttr.Description; - } - - return TranslateToCzech(member.Name); - } - - string TranslateToCzech(string original) - { - var translated = original; - - switch (original) - { - case "Person": - translated = "Osoba"; - break; - case "FirstName": - translated = "Křestní jméno"; - break; - case "LastName": - translated = "Příjmení"; - break; - case "Birthdate": - translated = "Datum narození"; - break; - case "PhoneNumber": - translated = "Číslo telefonu"; - break; - case "ListOfAddress1": - translated = "Seznam adres 1"; - break; - case "City": - translated = "Město"; - break; - case "Country": - translated = "Stát"; - break; - default: - break; - } - - return translated; - } - - void WalkDifferenceTree(IDifferenceTreeNode node, int level, StringBuilder stringBuilder) - { - var blankMemberName = "?"; - string indent = String.Concat(Enumerable.Repeat(" ", 2 * level)); - - if (TreeNodeIsListItem(node) == false) - { - var memberName = node?.Member?.Name ?? blankMemberName; - var line = indent + memberName; - stringBuilder.AppendLine(line); - Debug.WriteLine(line); - } - - foreach (var diff in node.Differences) - { - var line = indent + String.Concat(Enumerable.Repeat(" ", 2)) + diff.ToString(); - stringBuilder.AppendLine(line); - Debug.WriteLine(line); - } - - level++; - - var descendants = node.Descendants.ToArray(); - - for (int i = 0; i < descendants.Length; i++) - { - var desc = descendants[i]; - - if (TreeNodeIsListItem(desc)) - { - var line = indent + String.Concat(Enumerable.Repeat(" ", 2)) + $"[{GetIndex(desc)}]"; - stringBuilder.AppendLine(line); - Debug.WriteLine(line); - } - - WalkDifferenceTree(desc, level, stringBuilder); - } - } - - int? GetIndex(IDifferenceTreeNode node) - { - var itemx = node.Ancestor.Descendants - .Select((descendant, index) => new { Index = index, Descendant = descendant }).Where(n => n.Descendant == node) - .FirstOrDefault(); - - return itemx?.Index; - } - - bool TreeNodeIsListItem(IDifferenceTreeNode node) - { - if (node.Ancestor?.Member?.Info is PropertyInfo pi && typeof(IEnumerable).IsAssignableFrom(pi.PropertyType) && pi.PropertyType != typeof(string)) - { - return true; - } - - return false; - } - + [Test] public void CompareObjectListsByComplexKey() { diff --git a/ObjectsComparer/ObjectsComparer.Tests/DifferenceConfigurationTests.cs b/ObjectsComparer/ObjectsComparer.Tests/DifferenceConfigurationTests.cs index 99f9188..6db59cb 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/DifferenceConfigurationTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/DifferenceConfigurationTests.cs @@ -6,6 +6,13 @@ using NSubstitute; using NUnit.Framework; using ObjectsComparer.Tests.TestClasses; +using System.Reflection; +using System.IO; +using System.Text; +using System.ComponentModel; +using System.Diagnostics; +using DescriptionAttribute = System.ComponentModel.DescriptionAttribute; +using System.Collections; namespace ObjectsComparer.Tests @@ -131,6 +138,519 @@ public void CustomizeMemberPath() Assert.IsTrue(differences.Any(diff => diff.MemberPath == "Collection of C objects[0].First property of class A")); Assert.IsTrue(differences.Any(diff => diff.MemberPath == "ClassB.First property of Class B")); } - } + + [Test] + public void CalculateCompletedDifferenceTree() + { + var student1 = new Student + { + Person = new Person + { + FirstName = "Daniel", + + ListOfAddress1 = new List
+ { + new Address { City = "Prague", Country = "Czech republic" }, + new Address { City = "Pilsen", Country = "Czech republic" } + } + } + }; + + var student2 = new Student + { + Person = new Person + { + FirstName = "Dan", + + ListOfAddress1 = new List
+ { + new Address { City = "Olomouc", Country = "Czechia" }, + new Address { City = "Pilsen", Country = "Czech republic" } + } + } + }; + + var comparer = new Comparer(); + + var rootNode = comparer.CalculateDifferenceTree(student1, student2); + + Assert.AreEqual(3, rootNode.GetDifferences(recursive: true).Count()); + + var stringBuilder = new StringBuilder(); + WalkDifferenceTree(rootNode, 0, stringBuilder); + var differenceTreeStr = stringBuilder.ToString(); + + /* + * differenceTreeStr: + ? + Person + FirstName + Difference: DifferenceType=ValueMismatch, MemberPath='Person.FirstName', Value1='Daniel', Value2='Dan'. + LastName + Birthdate + PhoneNumber + ListOfAddress1 + [0] + Id + City + Difference: DifferenceType=ValueMismatch, MemberPath='Person.ListOfAddress1[0].City', Value1='Prague', Value2='Olomouc'. + Country + Difference: DifferenceType=ValueMismatch, MemberPath='Person.ListOfAddress1[0].Country', Value1='Czech republic', Value2='Czechia'. + State + PostalCode + Street + [1] + Id + City + Country + State + PostalCode + Street + ListOfAddress2 + */ + + using (var sr = new StringReader(differenceTreeStr)) + { + var expectedLine = sr.ReadLine(); + Assert.AreEqual(expectedLine.Trim(), "?"); + expectedLine = sr.ReadLine(); + Assert.AreEqual(expectedLine.Trim(), "Person"); + expectedLine = sr.ReadLine(); + Assert.AreEqual(expectedLine.Trim(), "FirstName"); + expectedLine = sr.ReadLine(); + Assert.AreEqual(expectedLine.Trim(), "Difference: DifferenceType=ValueMismatch, MemberPath='Person.FirstName', Value1='Daniel', Value2='Dan'."); + expectedLine = sr.ReadLine(); + Assert.AreEqual(expectedLine.Trim(), "LastName"); + expectedLine = sr.ReadLine(); + Assert.AreEqual(expectedLine.Trim(), "Birthdate"); + expectedLine = sr.ReadLine(); + Assert.AreEqual(expectedLine.Trim(), "PhoneNumber"); + expectedLine = sr.ReadLine(); + Assert.AreEqual(expectedLine.Trim(), "ListOfAddress1"); + expectedLine = sr.ReadLine(); + Assert.AreEqual(expectedLine.Trim(), "[0]"); + expectedLine = sr.ReadLine(); + Assert.AreEqual(expectedLine.Trim(), "Id"); + expectedLine = sr.ReadLine(); + Assert.AreEqual(expectedLine.Trim(), "City"); + expectedLine = sr.ReadLine(); + Assert.AreEqual(expectedLine.Trim(), "Difference: DifferenceType=ValueMismatch, MemberPath='Person.ListOfAddress1[0].City', Value1='Prague', Value2='Olomouc'."); + expectedLine = sr.ReadLine(); + Assert.AreEqual(expectedLine.Trim(), "Country"); + expectedLine = sr.ReadLine(); + Assert.AreEqual(expectedLine.Trim(), "Difference: DifferenceType=ValueMismatch, MemberPath='Person.ListOfAddress1[0].Country', Value1='Czech republic', Value2='Czechia'."); + } + + rootNode.Shrink(); + + stringBuilder = new StringBuilder(); + WalkDifferenceTree(rootNode, 0, stringBuilder); + differenceTreeStr = stringBuilder.ToString(); + + /* differenceTreeStr (shrinked): + ? + Person + FirstName + Difference: DifferenceType=ValueMismatch, MemberPath='Person.FirstName', Value1='Daniel', Value2='Dan'. + ListOfAddress1 + [0] + City + Difference: DifferenceType=ValueMismatch, MemberPath='Person.ListOfAddress1[0].City', Value1='Prague', Value2='Olomouc'. + Country + Difference: DifferenceType=ValueMismatch, MemberPath='Person.ListOfAddress1[0].Country', Value1='Czech republic', Value2='Czechia'. + */ + + using (var sr = new System.IO.StringReader(differenceTreeStr)) + { + var expectedLine = sr.ReadLine(); + Assert.AreEqual(expectedLine.Trim(), "?"); + expectedLine = sr.ReadLine(); + Assert.AreEqual(expectedLine.Trim(), "Person"); + expectedLine = sr.ReadLine(); + Assert.AreEqual(expectedLine.Trim(), "FirstName"); + expectedLine = sr.ReadLine(); + Assert.AreEqual(expectedLine.Trim(), "Difference: DifferenceType=ValueMismatch, MemberPath='Person.FirstName', Value1='Daniel', Value2='Dan'."); + expectedLine = sr.ReadLine(); + Assert.AreEqual(expectedLine.Trim(), "ListOfAddress1"); + expectedLine = sr.ReadLine(); + Assert.AreEqual(expectedLine.Trim(), "[0]"); + expectedLine = sr.ReadLine(); + Assert.AreEqual(expectedLine.Trim(), "City"); + expectedLine = sr.ReadLine(); + Assert.AreEqual(expectedLine.Trim(), "Difference: DifferenceType=ValueMismatch, MemberPath='Person.ListOfAddress1[0].City', Value1='Prague', Value2='Olomouc'."); + expectedLine = sr.ReadLine(); + Assert.AreEqual(expectedLine.Trim(), "Country"); + expectedLine = sr.ReadLine(); + Assert.AreEqual(expectedLine.Trim(), "Difference: DifferenceType=ValueMismatch, MemberPath='Person.ListOfAddress1[0].Country', Value1='Czech republic', Value2='Czechia'."); + } + } + + [Test] + public void CalculateUncompletedDifferenceTree() + { + var student1 = new Student + { + Person = new Person + { + FirstName = "Daniel", + + ListOfAddress1 = new List
+ { + new Address { City = "Prague", Country = "Czech republic" }, + new Address { City = "Pilsen", Country = "Czech republic" } + } + } + }; + + var student2 = new Student + { + Person = new Person + { + FirstName = "Dan", + + ListOfAddress1 = new List
+ { + new Address { City = "Olomouc", Country = "Czechia" }, + new Address { City = "Pilsen", Country = "Czech republic" } + } + } + }; + + var comparer = new Comparer(); + + var rootNode = comparer.CalculateDifferenceTree( + student1, + student2, + currentContext => currentContext.RootNode.GetDifferences(recursive: true).Any() == false); + + Assert.AreEqual(1, rootNode.GetDifferences(recursive: true).Count()); + + rootNode.Shrink(); + + var stringBuilder = new StringBuilder(); + WalkDifferenceTree(rootNode, 0, stringBuilder); + var differenceTreeStr = stringBuilder.ToString(); + + /* differenceTreeStr (shrinked): + ? + Person + FirstName + Difference: DifferenceType=ValueMismatch, MemberPath='Person.FirstName', Value1='Daniel', Value2='Dan'. + */ + + using (var sr = new System.IO.StringReader(differenceTreeStr)) + { + var expectedLine = sr.ReadLine(); + Assert.AreEqual(expectedLine.Trim(), "?"); + expectedLine = sr.ReadLine(); + Assert.AreEqual(expectedLine.Trim(), "Person"); + expectedLine = sr.ReadLine(); + Assert.AreEqual(expectedLine.Trim(), "FirstName"); + expectedLine = sr.ReadLine(); + Assert.AreEqual(expectedLine.Trim(), "Difference: DifferenceType=ValueMismatch, MemberPath='Person.FirstName', Value1='Daniel', Value2='Dan'."); + expectedLine = sr.ReadLine(); + Assert.AreEqual(expectedLine, null); + } + } + + [Test] + public void CalculateDifferencesTranslateMembers() + { + var student1 = new Student + { + Person = new Person + { + ListOfAddress1 = new List
+ { + new Address { City = "Prague", Country = "Czech republic" }, + new Address { City = "Pilsen", Country = "Czech republic" } + } + } + }; + + var student2 = new Student + { + Person = new Person + { + ListOfAddress1 = new List
+ { + new Address { City = "Olomouc", Country = "Czechia" }, + new Address { City = "Pilsen", Country = "Czech republic" } + } + } + }; + + var settings = new ComparisonSettings(); + settings.ConfigureDifferences(defaultMember => TranslateToCzech(defaultMember?.Name)); + var comparer = new Comparer(settings); + var differences = comparer.CalculateDifferences(student1, student2).ToArray(); + + Assert.AreEqual(2, differences.Count()); + + Assert.IsTrue(differences.Any(d => + d.DifferenceType == DifferenceTypes.ValueMismatch && + d.MemberPath == "Osoba.Seznam adres 1[0].Město" && + d.Value1 == "Prague" && d.Value2 == "Olomouc")); + + Assert.IsTrue(differences.Any(d => + d.DifferenceType == DifferenceTypes.ValueMismatch && + d.MemberPath == "Osoba.Seznam adres 1[0].Stát" && + d.Value1 == "Czech republic" && d.Value2 == "Czechia")); + } + + [Test] + public void CalculateDifferenceTreeTranslateMembersUsingAttributes() + { + var student1 = new Student + { + Person = new Person + { + ListOfAddress1 = new List
+ { + new Address { City = "Prague", Country = "Czech republic" }, + new Address { City = "Pilsen", Country = "Czech republic" } + } + } + }; + + var student2 = new Student + { + Person = new Person + { + ListOfAddress1 = new List
+ { + new Address { City = "Olomouc", Country = "Czechia" }, + new Address { City = "Pilsen", Country = "Czech republic" } + } + } + }; + + var settings = new ComparisonSettings(); + settings.ConfigureDifferences(defaultMember => TranslateToCzech(defaultMember)); + var comparer = new Comparer(settings); + var rootNode = comparer.CalculateDifferenceTree(student1, student2); + rootNode.Shrink(); + + Assert.AreEqual(2, rootNode.GetDifferences(recursive: true).Count()); + + var stringBuilder = new StringBuilder(); + WalkDifferenceTree(rootNode, 0, stringBuilder); + var differenceTreeStr = stringBuilder.ToString(); + + /* differenceTreeStr (shrinked): + ? + Člověk + Kolekce adres + [0] + Aglomerace (město) + Difference: DifferenceType=ValueMismatch, MemberPath='Člověk.Kolekce adres[0].Aglomerace (město)', Value1='Prague', Value2='Olomouc'. + Země (stát) + Difference: DifferenceType=ValueMismatch, MemberPath='Člověk.Kolekce adres[0].Země (stát)', Value1='Czech republic', Value2='Czechia'. + */ + + using (var sr = new StringReader(differenceTreeStr)) + { + var expectedLine = sr.ReadLine(); + Assert.AreEqual(expectedLine.Trim(), "?"); + expectedLine = sr.ReadLine(); + Assert.AreEqual(expectedLine.Trim(), "Člověk"); + expectedLine = sr.ReadLine(); + Assert.AreEqual(expectedLine.Trim(), "Kolekce adres"); + expectedLine = sr.ReadLine(); + Assert.AreEqual(expectedLine.Trim(), "[0]"); + expectedLine = sr.ReadLine(); + Assert.AreEqual(expectedLine.Trim(), "Aglomerace (město)"); + expectedLine = sr.ReadLine(); + Assert.AreEqual(expectedLine.Trim(), "Difference: DifferenceType=ValueMismatch, MemberPath='Člověk.Kolekce adres[0].Aglomerace (město)', Value1='Prague', Value2='Olomouc'."); + expectedLine = sr.ReadLine(); + Assert.AreEqual(expectedLine.Trim(), "Země (stát)"); + expectedLine = sr.ReadLine(); + Assert.AreEqual(expectedLine.Trim(), "Difference: DifferenceType=ValueMismatch, MemberPath='Člověk.Kolekce adres[0].Země (stát)', Value1='Czech republic', Value2='Czechia'."); + } + } + + [Test] + public void CalculateDifferenceTreeTranslateMembers() + { + var student1 = new Student + { + Person = new Person + { + ListOfAddress1 = new List
+ { + new Address { City = "Prague", Country = "Czech republic" }, + new Address { City = "Pilsen", Country = "Czech republic" } + } + } + }; + + var student2 = new Student + { + Person = new Person + { + ListOfAddress1 = new List
+ { + new Address { City = "Olomouc", Country = "Czechia" }, + new Address { City = "Pilsen", Country = "Czech republic" } + } + } + }; + + var settings = new ComparisonSettings(); + settings.ConfigureDifferences(defaultMember => TranslateToCzech(defaultMember?.Name)); + var comparer = new Comparer(settings); + var rootNode = comparer.CalculateDifferenceTree(student1, student2); + rootNode.Shrink(); + + Assert.AreEqual(2, rootNode.GetDifferences(recursive: true).Count()); + + var stringBuilder = new StringBuilder(); + WalkDifferenceTree(rootNode, 0, stringBuilder); + var differenceTreeStr = stringBuilder.ToString(); + + /* differenceTreeStr (shrinked): + ? + Osoba + Seznam adres 1 + [0] + Město + Difference: DifferenceType=ValueMismatch, MemberPath='Osoba.Seznam adres 1[0].Město', Value1='Prague', Value2='Olomouc'. + Stát + Difference: DifferenceType=ValueMismatch, MemberPath='Osoba.Seznam adres 1[0].Stát', Value1='Czech republic', Value2='Czechia'. + */ + + using (var sr = new StringReader(differenceTreeStr)) + { + var expectedLine = sr.ReadLine(); + Assert.AreEqual(expectedLine.Trim(), "?"); + expectedLine = sr.ReadLine(); + Assert.AreEqual(expectedLine.Trim(), "Osoba"); + expectedLine = sr.ReadLine(); + Assert.AreEqual(expectedLine.Trim(), "Seznam adres 1"); + expectedLine = sr.ReadLine(); + Assert.AreEqual(expectedLine.Trim(), "[0]"); + expectedLine = sr.ReadLine(); + Assert.AreEqual(expectedLine.Trim(), "Město"); + expectedLine = sr.ReadLine(); + Assert.AreEqual(expectedLine.Trim(), "Difference: DifferenceType=ValueMismatch, MemberPath='Osoba.Seznam adres 1[0].Město', Value1='Prague', Value2='Olomouc'."); + expectedLine = sr.ReadLine(); + Assert.AreEqual(expectedLine.Trim(), "Stát"); + expectedLine = sr.ReadLine(); + Assert.AreEqual(expectedLine.Trim(), "Difference: DifferenceType=ValueMismatch, MemberPath='Osoba.Seznam adres 1[0].Stát', Value1='Czech republic', Value2='Czechia'."); + } + } + + string TranslateToCzech(MemberInfo member) + { + if (member == null) + { + return null; + } + + var descriptionAttr = member.GetCustomAttribute(); + + if (descriptionAttr != null) + { + return descriptionAttr.Description; + } + + return TranslateToCzech(member.Name); + } + + string TranslateToCzech(string original) + { + var translated = original; + + switch (original) + { + case "Person": + translated = "Osoba"; + break; + case "FirstName": + translated = "Křestní jméno"; + break; + case "LastName": + translated = "Příjmení"; + break; + case "Birthdate": + translated = "Datum narození"; + break; + case "PhoneNumber": + translated = "Číslo telefonu"; + break; + case "ListOfAddress1": + translated = "Seznam adres 1"; + break; + case "City": + translated = "Město"; + break; + case "Country": + translated = "Stát"; + break; + default: + break; + } + + return translated; + } + + void WalkDifferenceTree(IDifferenceTreeNode node, int level, StringBuilder stringBuilder) + { + var blankMemberName = "?"; + string indent = String.Concat(Enumerable.Repeat(" ", 2 * level)); + + if (TreeNodeIsListItem(node) == false) + { + var memberName = node?.Member?.Name ?? blankMemberName; + var line = indent + memberName; + stringBuilder.AppendLine(line); + Debug.WriteLine(line); + } + + foreach (var diff in node.Differences) + { + var line = indent + String.Concat(Enumerable.Repeat(" ", 2)) + diff.ToString(); + stringBuilder.AppendLine(line); + Debug.WriteLine(line); + } + + level++; + + var descendants = node.Descendants.ToArray(); + + for (int i = 0; i < descendants.Length; i++) + { + var desc = descendants[i]; + + if (TreeNodeIsListItem(desc)) + { + var line = indent + String.Concat(Enumerable.Repeat(" ", 2)) + $"[{GetIndex(desc)}]"; + stringBuilder.AppendLine(line); + Debug.WriteLine(line); + } + + WalkDifferenceTree(desc, level, stringBuilder); + } + } + + int? GetIndex(IDifferenceTreeNode node) + { + var itemx = node.Ancestor.Descendants + .Select((descendant, index) => new { Index = index, Descendant = descendant }).Where(n => n.Descendant == node) + .FirstOrDefault(); + + return itemx?.Index; + } + + bool TreeNodeIsListItem(IDifferenceTreeNode node) + { + if (node.Ancestor?.Member?.Info is PropertyInfo pi && typeof(IEnumerable).IsAssignableFrom(pi.PropertyType) && pi.PropertyType != typeof(string)) + { + return true; + } + + return false; + } + } } diff --git a/ObjectsComparer/ObjectsComparer/ComparisonSettings.cs b/ObjectsComparer/ObjectsComparer/ComparisonSettings.cs index 3baf3e5..bb34818 100644 --- a/ObjectsComparer/ObjectsComparer/ComparisonSettings.cs +++ b/ObjectsComparer/ObjectsComparer/ComparisonSettings.cs @@ -76,7 +76,7 @@ public T GetCustomSetting(string key = null) /// The term list has a general meaning here and includes almost all Enumerable objects. /// /// - /// First parameter type: Current list node. + /// First parameter: Current list node. /// public ComparisonSettings ConfigureListComparison(Action comparisonOptions) { @@ -134,7 +134,7 @@ public ComparisonSettings ConfigureListComparison(bool compareElementsByKey = fa /// Configures creation of the instance, see . /// /// - /// First parameter type: The ancestor member the tree node is configured for. + /// First parameter: The ancestor member the tree node is configured for. /// public ComparisonSettings ConfigureDifferenceTree(Action options) { @@ -149,7 +149,7 @@ public ComparisonSettings ConfigureDifferenceTree(Action instance, see . /// /// - /// First parameter type: The member the difference is configured for. + /// First parameter: The member the difference is configured for. /// public ComparisonSettings ConfigureDifference(Action differenceOptions) { @@ -168,30 +168,15 @@ public ComparisonSettings ConfigureDifference(bool includeRawValues) return this; } - //public ComparisonSettings ConfigureDifferences(Func memberNameProvider, bool includeRawValues = false) - //{ - // ConfigureDifferenceTree((_, options) => - // options.UseDifferenceTreeNodeMemberFactory(defaultMember => - // new DifferenceTreeNodeMember( - // defaultMember.Info, - // memberNameProvider(defaultMember.Name)))); - - // ConfigureDifference((_, options) => - // options.UseDifferenceFactory(args => - // new Difference( - // memberPath: memberNameProvider(args.DefaultDifference.MemberPath), - // args.DefaultDifference.Value1, - // args.DefaultDifference.Value2, - // args.DefaultDifference.DifferenceType, - // rawValue1: includeRawValues ? args.RawValue1 : null, - // rawValue2: includeRawValues ? args.RawValue2 : null))); - - // ConfigureDifferencePath((_, options) => - // options.UseInsertPathFactory(args => memberNameProvider(args.DefaultRootElementPath))); - - // return this; - //} - + /// + /// Wraps , and + /// by applying the argument to them. + /// + /// + /// Customizes the , .
+ /// First parameter: It can be null in some cases, for example, when it represents the root of the comparison. + /// + /// Whether raw values should be included in the instance. public ComparisonSettings ConfigureDifferences(Func memberNameProvider, bool includeRawValues = false) { ConfigureDifferenceTree((ancestor, options) => @@ -222,7 +207,7 @@ public ComparisonSettings ConfigureDifferences(Func memberNa /// Configures the insertion into the difference path, see . /// /// - /// First parameter type: The parent of the member to which the path is inserted. + /// First parameter: The parent of the member to which the path is inserted. /// public ComparisonSettings ConfigureDifferencePath(Action options) { diff --git a/ObjectsComparer/ObjectsComparer/DifferenceOptions.cs b/ObjectsComparer/ObjectsComparer/DifferenceOptions.cs index 116b3f7..75744b2 100644 --- a/ObjectsComparer/ObjectsComparer/DifferenceOptions.cs +++ b/ObjectsComparer/ObjectsComparer/DifferenceOptions.cs @@ -28,7 +28,7 @@ public class DifferenceOptions /// /// /// Null value is allowed here and means that a default behavior of creation of the difference is required.
- /// First parameter type: The args for the difference creation, see .
+ /// First parameter: The args for the difference creation, see .
/// Returns: Transformed difference or the source difference itself. /// /// diff --git a/ObjectsComparer/ObjectsComparer/DifferencePathOptions.cs b/ObjectsComparer/ObjectsComparer/DifferencePathOptions.cs index f8e83d5..1c071fb 100644 --- a/ObjectsComparer/ObjectsComparer/DifferencePathOptions.cs +++ b/ObjectsComparer/ObjectsComparer/DifferencePathOptions.cs @@ -23,7 +23,7 @@ public class DifferencePathOptions /// /// /// Null value is allowed here and means that a default behavior of the insertion into the difference path is required.
- /// First parameter type: The args for the path insertion, see .
+ /// First parameter: The args for the path insertion, see .
/// Returns: Transformed root path element or not transformed root path element itself. /// public void UseInsertPathFactory(Func factory) diff --git a/ObjectsComparer/ObjectsComparer/DifferenceTree/ComparerExtensions.cs b/ObjectsComparer/ObjectsComparer/DifferenceTree/ComparerExtensions.cs index 7999e2b..d24f401 100644 --- a/ObjectsComparer/ObjectsComparer/DifferenceTree/ComparerExtensions.cs +++ b/ObjectsComparer/ObjectsComparer/DifferenceTree/ComparerExtensions.cs @@ -13,7 +13,7 @@ public static class ComparerExtensions /// /// /// Comparison process listener. If the argument is null the process is looking for all the differences at once.
- /// First parameter type: Current comparison context, see .
+ /// First parameter: Current comparison context, see .
/// Second parameter type: Whether to look for another difference. If value = false the comparison process will be terminated immediately. /// /// Occurs if (and only if) the comparison process reaches the last member of the objects being compared. @@ -52,7 +52,7 @@ public static IDifferenceTreeNode CalculateDifferenceTree(this IComparer compare /// /// /// Comparison process listener. If the argument is null the process is looking for all the differences at once.
- /// First parameter type: Current comparison context, see .
+ /// First parameter: Current comparison context, see .
/// Second parameter type: Whether to look for another difference. If value = false the comparison process will be terminated immediately. /// /// Occurs if (and only if) the comparison process reaches the last member of the objects being compared. diff --git a/ObjectsComparer/ObjectsComparer/DifferenceTree/DifferenceTreeOptions.cs b/ObjectsComparer/ObjectsComparer/DifferenceTree/DifferenceTreeOptions.cs index 5edbd90..9b03fa6 100644 --- a/ObjectsComparer/ObjectsComparer/DifferenceTree/DifferenceTreeOptions.cs +++ b/ObjectsComparer/ObjectsComparer/DifferenceTree/DifferenceTreeOptions.cs @@ -23,7 +23,7 @@ internal static DifferenceTreeOptions Default() /// Factory for instances. /// /// - /// First parameter type: The member the tree node is created for. It can be replaced by a custom instance. + /// First parameter: The member the tree node is created for. It can be replaced by a custom instance. /// public void UseDifferenceTreeNodeFactory(Func factory) { @@ -34,7 +34,7 @@ public void UseDifferenceTreeNodeFactory(Func instances. /// /// - /// First parameter type: Default member, can be used as a falback. + /// First parameter: Default member, it can be used as a falback from the delegate. /// public void UseDifferenceTreeNodeMemberFactory(Func factory) { diff --git a/ObjectsComparer/ObjectsComparer/ListElementComparisonByKeyOptions.cs b/ObjectsComparer/ObjectsComparer/ListElementComparisonByKeyOptions.cs index c445fc4..3fba038 100644 --- a/ObjectsComparer/ObjectsComparer/ListElementComparisonByKeyOptions.cs +++ b/ObjectsComparer/ObjectsComparer/ListElementComparisonByKeyOptions.cs @@ -144,7 +144,7 @@ public ListElementComparisonByKeyOptions UseKey(string[] keys, bool caseSensitiv /// /// Key identification. It attempts to find the key using the parameter. /// - /// First parameter type: The element whose key is required, see .
+ /// First parameter: The element whose key is required, see .
/// Return value: The element's key. public ListElementComparisonByKeyOptions UseKey(Func keyProvider) { @@ -283,7 +283,7 @@ public ListElementComparisonByKeyOptions FormatElementKey(Func template will be used to format the identifier. /// /// - /// First parameter type: Element index.
+ /// First parameter: Element index.
/// Second parameter type: Formatted identifier. /// public ListElementComparisonByKeyOptions FormatNullElementIdentifier(Func formatter) From 175c51d400b1dccd52cc395ebb44fb9e54f1ade9 Mon Sep 17 00:00:00 2001 From: Daniel Nemec Date: Sat, 16 Jul 2022 13:38:12 +0200 Subject: [PATCH 180/181] Edit comments. --- .../DifferenceConfigurationTests.cs | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/ObjectsComparer/ObjectsComparer.Tests/DifferenceConfigurationTests.cs b/ObjectsComparer/ObjectsComparer.Tests/DifferenceConfigurationTests.cs index 6db59cb..7df0d1c 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/DifferenceConfigurationTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/DifferenceConfigurationTests.cs @@ -69,7 +69,7 @@ public void DontPreserveRawValues() } [Test] - public void PreserveRawValuesConditionaly() + public void PreserveRawValuesConditionally() { var a1 = new A() { IntProperty = 10, TestProperty1 = "TestProperty1value" }; var a2 = new A() { IntProperty = 11, TestProperty1 = "TestProperty2value" }; @@ -177,7 +177,7 @@ public void CalculateCompletedDifferenceTree() Assert.AreEqual(3, rootNode.GetDifferences(recursive: true).Count()); var stringBuilder = new StringBuilder(); - WalkDifferenceTree(rootNode, 0, stringBuilder); + WriteDifferenceTree(rootNode, 0, stringBuilder); var differenceTreeStr = stringBuilder.ToString(); /* @@ -244,7 +244,7 @@ public void CalculateCompletedDifferenceTree() rootNode.Shrink(); stringBuilder = new StringBuilder(); - WalkDifferenceTree(rootNode, 0, stringBuilder); + WriteDifferenceTree(rootNode, 0, stringBuilder); differenceTreeStr = stringBuilder.ToString(); /* differenceTreeStr (shrinked): @@ -260,7 +260,7 @@ public void CalculateCompletedDifferenceTree() Difference: DifferenceType=ValueMismatch, MemberPath='Person.ListOfAddress1[0].Country', Value1='Czech republic', Value2='Czechia'. */ - using (var sr = new System.IO.StringReader(differenceTreeStr)) + using (var sr = new StringReader(differenceTreeStr)) { var expectedLine = sr.ReadLine(); Assert.AreEqual(expectedLine.Trim(), "?"); @@ -328,7 +328,7 @@ public void CalculateUncompletedDifferenceTree() rootNode.Shrink(); var stringBuilder = new StringBuilder(); - WalkDifferenceTree(rootNode, 0, stringBuilder); + WriteDifferenceTree(rootNode, 0, stringBuilder); var differenceTreeStr = stringBuilder.ToString(); /* differenceTreeStr (shrinked): @@ -338,7 +338,7 @@ public void CalculateUncompletedDifferenceTree() Difference: DifferenceType=ValueMismatch, MemberPath='Person.FirstName', Value1='Daniel', Value2='Dan'. */ - using (var sr = new System.IO.StringReader(differenceTreeStr)) + using (var sr = new StringReader(differenceTreeStr)) { var expectedLine = sr.ReadLine(); Assert.AreEqual(expectedLine.Trim(), "?"); @@ -434,7 +434,7 @@ public void CalculateDifferenceTreeTranslateMembersUsingAttributes() Assert.AreEqual(2, rootNode.GetDifferences(recursive: true).Count()); var stringBuilder = new StringBuilder(); - WalkDifferenceTree(rootNode, 0, stringBuilder); + WriteDifferenceTree(rootNode, 0, stringBuilder); var differenceTreeStr = stringBuilder.ToString(); /* differenceTreeStr (shrinked): @@ -505,7 +505,7 @@ public void CalculateDifferenceTreeTranslateMembers() Assert.AreEqual(2, rootNode.GetDifferences(recursive: true).Count()); var stringBuilder = new StringBuilder(); - WalkDifferenceTree(rootNode, 0, stringBuilder); + WriteDifferenceTree(rootNode, 0, stringBuilder); var differenceTreeStr = stringBuilder.ToString(); /* differenceTreeStr (shrinked): @@ -594,7 +594,7 @@ string TranslateToCzech(string original) return translated; } - void WalkDifferenceTree(IDifferenceTreeNode node, int level, StringBuilder stringBuilder) + void WriteDifferenceTree(IDifferenceTreeNode node, int level, StringBuilder stringBuilder) { var blankMemberName = "?"; string indent = String.Concat(Enumerable.Repeat(" ", 2 * level)); @@ -629,7 +629,7 @@ void WalkDifferenceTree(IDifferenceTreeNode node, int level, StringBuilder strin Debug.WriteLine(line); } - WalkDifferenceTree(desc, level, stringBuilder); + WriteDifferenceTree(desc, level, stringBuilder); } } From 35cd3fc60898ff44639146efe4efb9a108a5a5f7 Mon Sep 17 00:00:00 2001 From: Daniel Nemec Date: Sun, 17 Jul 2022 15:51:14 +0200 Subject: [PATCH 181/181] Edit Example4Tests_BuiltInKeyComparison.List_Of_Different_Sizes_But_Is_Inequality tes method. --- .../Example4/Example4Tests_BuiltInKeyComparison.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ObjectsComparer/ObjectsComparer.Examples/Example4/Example4Tests_BuiltInKeyComparison.cs b/ObjectsComparer/ObjectsComparer.Examples/Example4/Example4Tests_BuiltInKeyComparison.cs index 4e3bb23..5cc1996 100644 --- a/ObjectsComparer/ObjectsComparer.Examples/Example4/Example4Tests_BuiltInKeyComparison.cs +++ b/ObjectsComparer/ObjectsComparer.Examples/Example4/Example4Tests_BuiltInKeyComparison.cs @@ -172,7 +172,7 @@ public void List_Of_Different_Sizes_But_Is_Inequality() Assert.IsTrue(differences.Any(d => d.MemberPath == "Items[1].Delay" && d.Value1 == "60" && d.Value2 == "80")); Assert.IsTrue(differences.Any(d => d.MemberPath == "Items[1].Name" && d.Value1 == "Item 1" && d.Value2 == "Item One")); Assert.IsTrue(differences.Any(d => d.MemberPath == "Items[1].Instruction" && d.Value1 == "Instruction 1" && d.Value2 == "Instruction One")); - Assert.IsTrue(differences.Any(d => d.DifferenceType == DifferenceTypes.MissedElementInFirstObject && d.Value1 == "" && d.Value2 == "ObjectsComparer.Examples.Example4.FormulaItem")); + Assert.IsTrue(differences.Any(d => d.MemberPath == "Items[2]" && d.DifferenceType == DifferenceTypes.MissedElementInFirstObject && d.Value1 == "" && d.Value2 == "ObjectsComparer.Examples.Example4.FormulaItem")); } [Test]
/// Configures list comparison behavior, especially the type of the comparison. For more info, see . @@ -91,9 +91,11 @@ public ComparisonSettings ConfigureListComparison(Action /// See . - public void ConfigureListComparison(Action comparisonOptions) + public ComparisonSettings ConfigureListComparison(Action comparisonOptions) { ConfigureListComparison((_, options) => comparisonOptions(options)); + + return this; } /// @@ -107,7 +109,7 @@ public void ConfigureListComparison(Action comparisonOpti /// /// Shortcut for operation. Default value = false. /// - public void ConfigureListComparison(bool compareElementsByKey = false, bool compareUnequalLists = false) + public ComparisonSettings ConfigureListComparison(bool compareElementsByKey = false, bool compareUnequalLists = false) { ConfigureListComparison(options => { @@ -118,30 +120,53 @@ public void ConfigureListComparison(bool compareElementsByKey = false, bool comp options.CompareElementsByKey(); } }); + + return this; } - internal Action DifferenceTreeOptionsAction { get; private set; } + public Action DifferenceTreeOptionsAction { get; private set; } /// /// Configures the difference tree behavior, see . /// /// /// - public void ConfigureDifferenceTree(Action options) + public ComparisonSettings ConfigureDifferenceTree(Action options) { DifferenceTreeOptionsAction = options ?? throw new ArgumentNullException(nameof(options)); + + return this; } - internal Action DifferenceOptionsAction; + public Action DifferenceOptionsAction; - public void ConfigureDifference(Action differenceOptions) + public ComparisonSettings ConfigureDifference(Action differenceOptions) { DifferenceOptionsAction = differenceOptions ?? throw new ArgumentNullException(nameof(differenceOptions)); + + return this; } - public void ConfigureDifference(bool includeRawValues) + public ComparisonSettings ConfigureDifference(bool includeRawValues) { ConfigureDifference((_, options) => options.IncludeRawValues(includeRawValues)); + + return this; + } + + public Action DifferencePathOptionsAction; + + /// + /// Behavior of the insertion into the difference path. + /// + /// + /// First parameter: The parent of the property to which the path is inserted. + /// + public ComparisonSettings ConfigureDifferencePath(Action options) + { + DifferencePathOptionsAction = options ?? throw new ArgumentNullException(nameof(options)); + + return this; } } } diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractDynamicObjectsComprer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractDynamicObjectsComprer.cs index 693cd77..9564e18 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractDynamicObjectsComprer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractDynamicObjectsComprer.cs @@ -83,9 +83,6 @@ IEnumerable IDifferenceTreeBuilder.BuildDifferenceTree(Type if (!existsInObject1) { var differenceLocation = AddDifferenceToTree(keyDifferenceTreeNode, propertyKey, string.Empty, valueComparer.ToString(value2), DifferenceTypes.MissedMemberInFirstObject, null, value2); - //var differenceLocation = AddDifferenceToTree( - // new Difference(propertyKey, string.Empty, valueComparer.ToString(value2), DifferenceTypes.MissedMemberInFirstObject), - // keyDifferenceTreeNode); yield return differenceLocation; continue; @@ -101,9 +98,6 @@ IEnumerable IDifferenceTreeBuilder.BuildDifferenceTree(Type DifferenceTypes.MissedMemberInSecondObject, value1, null); - //var differenceLocation = AddDifferenceToTree( - // new Difference(propertyKey, valueComparer.ToString(value1), string.Empty, DifferenceTypes.MissedMemberInSecondObject), - // keyDifferenceTreeNode); yield return differenceLocation; continue; @@ -116,9 +110,6 @@ IEnumerable IDifferenceTreeBuilder.BuildDifferenceTree(Type OverridesCollection.GetComparer(propertyKey) ?? DefaultValueComparer; - //var differenceLocation = AddDifferenceToTree( - // new Difference(propertyKey, valueComparer.ToString(value1), valueComparer2.ToString(value2), DifferenceTypes.TypeMismatch), - // keyDifferenceTreeNode); var differenceLocation = AddDifferenceToTree(keyDifferenceTreeNode, propertyKey, valueComparer.ToString(value1), valueComparer2.ToString(value2), DifferenceTypes.TypeMismatch, value1, value2); yield return differenceLocation; @@ -133,9 +124,6 @@ IEnumerable IDifferenceTreeBuilder.BuildDifferenceTree(Type OverridesCollection.GetComparer(value2.GetType()) ?? OverridesCollection.GetComparer(propertyKey) ?? DefaultValueComparer : DefaultValueComparer; - //var differenceLocation = AddDifferenceToTree( - // new Difference(propertyKey, valueComparer.ToString(value1), valueComparer2.ToString(value2), DifferenceTypes.TypeMismatch), - // keyDifferenceTreeNode); var differenceLocation = AddDifferenceToTree(keyDifferenceTreeNode, propertyKey, valueComparer.ToString(value1), valueComparer2.ToString(value2), DifferenceTypes.TypeMismatch, value1, value2); yield return differenceLocation; @@ -146,9 +134,6 @@ IEnumerable IDifferenceTreeBuilder.BuildDifferenceTree(Type { if (!customComparer.Compare(value1, value2, Settings)) { - //var differenceLocation = AddDifferenceToTree( - // new Difference(propertyKey, customComparer.ToString(value1), customComparer.ToString(value2)), - // keyDifferenceTreeNode); var differenceLocation = AddDifferenceToTree(keyDifferenceTreeNode, propertyKey, customComparer.ToString(value1), customComparer.ToString(value2), DifferenceTypes.ValueMismatch, value1, value2); yield return differenceLocation; @@ -160,7 +145,7 @@ IEnumerable IDifferenceTreeBuilder.BuildDifferenceTree(Type var comparer = Factory.GetObjectsComparer(propertyType, Settings, this); foreach (var failure in comparer.TryBuildDifferenceTree(propertyType, value1, value2, keyDifferenceTreeNode)) { - failure.Difference.InsertPath(propertyKey); + InsertPathToDifference(failure.Difference, propertyKey, keyDifferenceTreeNode,failure.TreeNode); yield return failure; } } diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs index ba2c750..b42509f 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer.cs @@ -36,7 +36,6 @@ IEnumerable IDifferenceTreeBuilder.BuildDifferenceTree(Type if (!Settings.EmptyAndNullEnumerablesEqual && (obj1 == null || obj2 == null) && obj1 != obj2) { - //yield return AddDifferenceToTree(new Difference("[]", obj1?.ToString() ?? string.Empty, obj2?.ToString() ?? string.Empty), listDifferenceTreeNode); yield return AddDifferenceToTree(listDifferenceTreeNode, "[]", obj1?.ToString() ?? string.Empty, obj2?.ToString() ?? string.Empty, DifferenceTypes.ValueMismatch, obj1, obj2); yield break; } @@ -67,7 +66,6 @@ IEnumerable IDifferenceTreeBuilder.BuildDifferenceTree(Type if (array1.Length != array2.Length) { - //yield return AddDifferenceToTree(new Difference("", array1.Length.ToString(), array2.Length.ToString(), DifferenceTypes.NumberOfElementsMismatch), listDifferenceTreeNode); yield return AddDifferenceToTree(listDifferenceTreeNode, "", array1.Length.ToString(), array2.Length.ToString(), DifferenceTypes.NumberOfElementsMismatch, array1, array2); if (listComparisonOptions.UnequalListsComparisonEnabled == false) diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparerBase.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparerBase.cs index c8f6c48..ed2b671 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparerBase.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparerBase.cs @@ -56,7 +56,6 @@ protected virtual IEnumerable CalculateDifferencesByKey(I var nullElementIdentifier = keyOptions.GetNullElementIdentifier(new FormatNullElementIdentifierArgs(element1Index)); - //yield return AddDifferenceToTree(new Difference($"[{nullElementIdentifier}]", string.Empty, string.Empty, DifferenceTypes.MissedElementInSecondObject), elementDifferenceTreeNode); yield return AddDifferenceToTree(elementDifferenceTreeNode, $"[{nullElementIdentifier}]", string.Empty, string.Empty, DifferenceTypes.MissedElementInSecondObject); continue; } @@ -89,7 +88,6 @@ protected virtual IEnumerable CalculateDifferencesByKey(I else { var valueComparer1 = OverridesCollection.GetComparer(element1.GetType()) ?? DefaultValueComparer; - //yield return AddDifferenceToTree(new Difference($"[{formattedElement1Key}]", valueComparer1.ToString(element1), string.Empty, DifferenceTypes.MissedElementInSecondObject), elementDifferenceTreeNode); yield return AddDifferenceToTree(elementDifferenceTreeNode, $"[{formattedElement1Key}]", valueComparer1.ToString(element1), string.Empty, DifferenceTypes.MissedElementInSecondObject, element1); } } @@ -108,7 +106,6 @@ protected virtual IEnumerable CalculateDifferencesByKey(I var nullElementIdentifier = keyOptions.GetNullElementIdentifier(new FormatNullElementIdentifierArgs(element2Index)); - //yield return AddDifferenceToTree(new Difference($"[{nullElementIdentifier}]", string.Empty, string.Empty, DifferenceTypes.MissedElementInFirstObject), elementDifferenceTreeNode); yield return AddDifferenceToTree(elementDifferenceTreeNode, $"[{nullElementIdentifier}]", string.Empty, string.Empty, DifferenceTypes.MissedElementInFirstObject); continue; } @@ -129,7 +126,6 @@ protected virtual IEnumerable CalculateDifferencesByKey(I { var formattedElement2Key = keyOptions.GetFormattedElementKey(new FormatListElementKeyArgs(element2Index, element2Key, element2)); var valueComparer2 = OverridesCollection.GetComparer(element2.GetType()) ?? DefaultValueComparer; - //yield return AddDifferenceToTree(new Difference($"[{formattedElement2Key}]", string.Empty, valueComparer2.ToString(element2), DifferenceTypes.MissedElementInFirstObject), elementDifferenceTreeNode); yield return AddDifferenceToTree(elementDifferenceTreeNode, $"[{formattedElement2Key}]", string.Empty, valueComparer2.ToString(element2), DifferenceTypes.MissedElementInFirstObject, null, element2); } } @@ -161,21 +157,18 @@ protected virtual IEnumerable CalculateDifferencesByIndex if (array1[i] == null) { - //yield return AddDifferenceToTree(new Difference($"[{i}]", string.Empty, valueComparer2.ToString(array2[i])), elementDifferenceTreeNode); yield return AddDifferenceToTree(elementDifferenceTreeNode, $"[{i}]", string.Empty, valueComparer2.ToString(array2[i]), DifferenceTypes.ValueMismatch, null, array2[i]); continue; } if (array2[i] == null) { - //yield return AddDifferenceToTree(new Difference($"[{i}]", valueComparer1.ToString(array1[i]), string.Empty), elementDifferenceTreeNode); yield return AddDifferenceToTree(elementDifferenceTreeNode, $"[{i}]", valueComparer1.ToString(array1[i]), string.Empty, DifferenceTypes.ValueMismatch, array1[i]); continue; } if (array1[i].GetType() != array2[i].GetType()) { - //yield return AddDifferenceToTree(new Difference($"[{i}]", valueComparer1.ToString(array1[i]), valueComparer2.ToString(array2[i]), DifferenceTypes.TypeMismatch), elementDifferenceTreeNode); yield return AddDifferenceToTree(elementDifferenceTreeNode, $"[{i}]", valueComparer1.ToString(array1[i]), valueComparer2.ToString(array2[i]), DifferenceTypes.TypeMismatch, array1[i], array2[i]); continue; } @@ -198,13 +191,6 @@ protected virtual IEnumerable CalculateDifferencesByIndex { var valueComparer = largerArray[i] != null ? OverridesCollection.GetComparer(largerArray[i].GetType()) ?? DefaultValueComparer : DefaultValueComparer; - //var difference = new Difference( - // memberPath: $"[{i}]", - // value1: array1Count > array2Count ? valueComparer.ToString(largerArray[i]) : string.Empty, - // value2: array2Count > array1Count ? valueComparer.ToString(largerArray[i]) : string.Empty, - // differenceType: array1Count > array2Count ? DifferenceTypes.MissedElementInSecondObject : DifferenceTypes.MissedElementInFirstObject); - - //yield return AddDifferenceToTree(difference, DifferenceTreeNodeProvider.CreateNode(Settings, listDifferenceTreeNode)); yield return AddDifferenceToTree(DifferenceTreeNodeProvider.CreateNode(Settings, listDifferenceTreeNode), memberPath: $"[{i}]", value1: array1Count > array2Count ? valueComparer.ToString(largerArray[i]) : string.Empty, diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer~1.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer~1.cs index 7f1991d..2c4c393 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer~1.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/EnumerablesComparer~1.cs @@ -66,7 +66,6 @@ public IEnumerable BuildDifferenceTree(Type type, object obj { if (!type.GetTypeInfo().IsArray) { - //yield return AddDifferenceToTree(new Difference("", list1.Count().ToString(), list2.Count().ToString(), DifferenceTypes.NumberOfElementsMismatch), listDifferenceTreeNode); yield return AddDifferenceToTree(listDifferenceTreeNode, "", list1.Count().ToString(), list2.Count().ToString(), DifferenceTypes.NumberOfElementsMismatch); } diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/HashSetsComparer~1.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/HashSetsComparer~1.cs index c4d1c18..da550da 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/HashSetsComparer~1.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/HashSetsComparer~1.cs @@ -63,9 +63,6 @@ public IEnumerable BuildDifferenceTree(Type type, object obj { if (!hashSet2.Contains(element)) { - //var differenceLocation = AddDifferenceToTree( - // new Difference("", valueComparer.ToString(element), string.Empty, DifferenceTypes.MissedElementInSecondObject), - // differenceTreeNode); var differenceLocation = AddDifferenceToTree(differenceTreeNode, "", valueComparer.ToString(element), string.Empty, DifferenceTypes.MissedElementInSecondObject, element, null); yield return differenceLocation; @@ -76,8 +73,6 @@ public IEnumerable BuildDifferenceTree(Type type, object obj { if (!hashSet1.Contains(element)) { - //var differenceLocation = AddDifferenceToTree(new Difference("", string.Empty, valueComparer.ToString(element), - // DifferenceTypes.MissedElementInFirstObject), differenceTreeNode); var differenceLocation = AddDifferenceToTree(differenceTreeNode, "", string.Empty, valueComparer.ToString(element), DifferenceTypes.MissedElementInFirstObject, null, element); yield return differenceLocation; diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/MultidimensionalArrayComparer~1.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/MultidimensionalArrayComparer~1.cs index 14ab80d..e009780 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/MultidimensionalArrayComparer~1.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/MultidimensionalArrayComparer~1.cs @@ -60,7 +60,6 @@ public IEnumerable BuildDifferenceTree(Type type, object obj if (array1.Rank != array2.Rank) { - //var difference = AddDifferenceToTree(new Difference("Rank", array1.Rank.ToString(), array2.Rank.ToString()), differenceTreeNode); var differenceLocation = AddDifferenceToTree(differenceTreeNode, "Rank", array1.Rank.ToString(), array2.Rank.ToString()); yield return differenceLocation; yield break; @@ -76,7 +75,6 @@ public IEnumerable BuildDifferenceTree(Type type, object obj if (length1 != length2) { dimensionsFailure = true; - //var differenceLocation = AddDifferenceToTree(new Difference($"Dimension{i}", length1.ToString(), length2.ToString()), differenceTreeNode); var differenceLocation = AddDifferenceToTree(differenceTreeNode, $"Dimension{i}", length1.ToString(), length2.ToString()); yield return differenceLocation; } diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/TypesComparer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/TypesComparer.cs index 456a5d4..25f126f 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/TypesComparer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/TypesComparer.cs @@ -48,8 +48,6 @@ public IEnumerable BuildDifferenceTree(Type type, object obj if (type1Str != type2Str) { - //yield return new Difference(string.Empty, type1Str, type2Str); - //yield return AddDifferenceToTree(new Difference(string.Empty, type1Str, type2Str), differenceTreeNode); yield return AddDifferenceToTree(differenceTreeNode, string.Empty, type1Str, type2Str, DifferenceTypes.ValueMismatch, obj1, obj2); } } diff --git a/ObjectsComparer/ObjectsComparer/DifferenceOptions.cs b/ObjectsComparer/ObjectsComparer/DifferenceOptions.cs index e275b47..00cd6ff 100644 --- a/ObjectsComparer/ObjectsComparer/DifferenceOptions.cs +++ b/ObjectsComparer/ObjectsComparer/DifferenceOptions.cs @@ -18,32 +18,16 @@ public class DifferenceOptions /// internal static DifferenceOptions Default() => new DifferenceOptions(); - ///// - ///// Whether the instance should contain raw values. - ///// - //public DifferenceOptions IncludeRawValues(bool value) - //{ - // //DifferenceFactory = value ? d => d : DefaultDifferenceFactory; - - // return this; - //} - /// /// Factory for instances. /// - internal Func DifferenceFactory { get; private set; } = null; - - ///// - ///// Default difference factory. - ///// If the source difference contains raw values it creates a new instance based on the source difference without those values. Otherwise, it returns the source difference itself. - ///// - //public static Func DefaultDifferenceFactory => args => args.DefaultDifference; + public Func DifferenceFactory { get; private set; } = null; /// /// Factory for instances. /// /// - /// Null value is allowed here and means that a default behavior of creation of the difference is required. + /// Null value is allowed here and means that a default behavior of creation of the difference is required.
/// Func first parameter: The args for the difference creation.
/// Returns: Transformed difference or the source difference itself. /// diff --git a/ObjectsComparer/ObjectsComparer/DifferencePathOptions.cs b/ObjectsComparer/ObjectsComparer/DifferencePathOptions.cs new file mode 100644 index 0000000..2ddcc1b --- /dev/null +++ b/ObjectsComparer/ObjectsComparer/DifferencePathOptions.cs @@ -0,0 +1,32 @@ +using System; + +namespace ObjectsComparer +{ + public class DifferencePathOptions + { + DifferencePathOptions() + { + } + + /// + /// Default options. + /// + internal static DifferencePathOptions Default() => new DifferencePathOptions(); + + public Func InsertPathFactory { get; private set; } = null; + + /// + /// Factory for insertion into the property. + /// + /// + /// Null value is allowed here and means that a default behavior of the insertion into the difference path is required.
+ /// Func first parameter: The args for the path insertion.
+ /// Returns: Transformed root path element or the not transformed root path element itself. + /// + public void UseInsertPathFactory(Func factory) + { + InsertPathFactory = factory; + } + + } +} diff --git a/ObjectsComparer/ObjectsComparer/DifferenceProvider.cs b/ObjectsComparer/ObjectsComparer/DifferenceProvider.cs deleted file mode 100644 index b83ad82..0000000 --- a/ObjectsComparer/ObjectsComparer/DifferenceProvider.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System; - -namespace ObjectsComparer -{ - public static class DifferenceProvider - { - public static Difference CreateDifference(ComparisonSettings settings, IDifferenceTreeNode differenceTreeNode, Difference defaultDifference, object rawValue1, object rawValue2) - { - if (settings is null) - { - throw new ArgumentNullException(nameof(settings)); - } - - if (differenceTreeNode is null) - { - throw new ArgumentNullException(nameof(differenceTreeNode)); - } - - if (defaultDifference is null) - { - throw new ArgumentNullException(nameof(defaultDifference)); - } - - var differenceOptions = DifferenceOptions.Default(); - - settings.DifferenceOptionsAction?.Invoke(differenceTreeNode, differenceOptions); - - if (differenceOptions.DifferenceFactory == null) - { - return defaultDifference; - } - - return differenceOptions.DifferenceFactory(new CreateDifferenceArgs(defaultDifference, rawValue1, rawValue2)); - } - } -} diff --git a/ObjectsComparer/ObjectsComparer/DifferenceTree/DifferenceTreeBuilderExtensions.cs b/ObjectsComparer/ObjectsComparer/DifferenceTree/DifferenceTreeBuilderExtensions.cs index d48674a..ff6abc0 100644 --- a/ObjectsComparer/ObjectsComparer/DifferenceTree/DifferenceTreeBuilderExtensions.cs +++ b/ObjectsComparer/ObjectsComparer/DifferenceTree/DifferenceTreeBuilderExtensions.cs @@ -126,12 +126,24 @@ internal static void ThrowDifferenceTreeBuilderNotImplemented(IDifferenceTreeNod if (comparisonSettings.ListComparisonOptionsAction != null) { - var message = $"Because the list comparison has bben explicitly configured, the {comparer.GetType().FullName} must implement {unImplementedInterface} interface " + + var message = $"Because the list comparison has been explicitly configured, the {comparer.GetType().FullName} must implement {unImplementedInterface} interface " + "or throwing the DifferenceTreeBuilderNotImplementedException must be disabled."; throw new DifferenceTreeBuilderNotImplementedException(message); } - //TODO: Check DifferenceOptionsAction + if (comparisonSettings.DifferenceOptionsAction != null) + { + var message = $"Because the difference has been explicitly configured, the {comparer.GetType().FullName} must implement {unImplementedInterface} interface " + + "or throwing the DifferenceTreeBuilderNotImplementedException must be disabled."; + throw new DifferenceTreeBuilderNotImplementedException(message); + } + + if (comparisonSettings.DifferencePathOptionsAction != null) + { + var message = $"Because the difference path has been explicitly configured, the {comparer.GetType().FullName} must implement {unImplementedInterface} interface " + + "or throwing the DifferenceTreeBuilderNotImplementedException must be disabled."; + throw new DifferenceTreeBuilderNotImplementedException(message); + } if (HasDifferenceTreeImplicitRoot(differenceTreeNode) == false) { diff --git a/ObjectsComparer/ObjectsComparer/InsertPathFactoryArgs.cs b/ObjectsComparer/ObjectsComparer/InsertPathFactoryArgs.cs new file mode 100644 index 0000000..2f1453e --- /dev/null +++ b/ObjectsComparer/ObjectsComparer/InsertPathFactoryArgs.cs @@ -0,0 +1,21 @@ +namespace ObjectsComparer +{ + public class InsertPathFactoryArgs + { + public InsertPathFactoryArgs(string defaultRootElementPath, IDifferenceTreeNode childNode) + { + DefaultRootElementPath = defaultRootElementPath; + ChildNode = childNode; + } + + /// + /// The path that will be inserted to the property by default. + /// + public string DefaultRootElementPath { get; } + + /// + /// The property to which the path is inserted. + /// + public IDifferenceTreeNode ChildNode { get; } + } +} From e555b72acfee1b31594d52c2a0cd5bcee1c81fb3 Mon Sep 17 00:00:00 2001 From: Daniel Nemec Date: Wed, 6 Jul 2022 18:02:22 +0200 Subject: [PATCH 172/181] Correct castedObject1 >castedObject2. --- .../CustomComparers/AbstractDynamicObjectsComprer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractDynamicObjectsComprer.cs b/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractDynamicObjectsComprer.cs index 9564e18..cb6655d 100644 --- a/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractDynamicObjectsComprer.cs +++ b/ObjectsComparer/ObjectsComparer/CustomComparers/AbstractDynamicObjectsComprer.cs @@ -55,7 +55,7 @@ IEnumerable IDifferenceTreeBuilder.BuildDifferenceTree(Type if (existsInObject2) { TryGetMemberValue(castedObject2, propertyKey, out value2); - TryGetMember(castedObject1, propertyKey, out member2); + TryGetMember(castedObject2, propertyKey, out member2); } var keyDifferenceTreeNode = DifferenceTreeNodeProvider.CreateNode(Settings, differenceTreeNode, member1 ?? member2, propertyKey); From 3bf863984d9eb00e04939bae49f83d25fbbdac60 Mon Sep 17 00:00:00 2001 From: Daniel Nemec Date: Wed, 6 Jul 2022 18:03:56 +0200 Subject: [PATCH 173/181] Make ListComparisonOptions public. --- ObjectsComparer/ObjectsComparer/ListComparisonOptions.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ObjectsComparer/ObjectsComparer/ListComparisonOptions.cs b/ObjectsComparer/ObjectsComparer/ListComparisonOptions.cs index d627891..d6d1d0f 100644 --- a/ObjectsComparer/ObjectsComparer/ListComparisonOptions.cs +++ b/ObjectsComparer/ObjectsComparer/ListComparisonOptions.cs @@ -18,7 +18,7 @@ public class ListComparisonOptions /// /// See . /// - internal bool UnequalListsComparisonEnabled { get; private set; } = false; + public bool UnequalListsComparisonEnabled { get; private set; } = false; ///
/// Whether to compare elements of the lists even if their number differs. Regardless of the , if lists are unequal, the difference of type will always be logged. Default value = false - unequal lists will not be compared. @@ -46,7 +46,7 @@ public ListComparisonOptions CompareElementsByIndex() return this; } - internal Action KeyOptionsAction { get; private set; } + public Action KeyOptionsAction { get; private set; } /// /// Compares list elements by key using element key provider. From f93e7774001cf909a0ed96de0aca5406a2b3895d Mon Sep 17 00:00:00 2001 From: Daniel Nemec Date: Wed, 6 Jul 2022 18:04:35 +0200 Subject: [PATCH 174/181] Edit test methods. Edit comments. --- .../Comparer_GenericEnumerableTests.cs | 110 +++++++++++++++--- .../Comparer_NonGenericEnumerableTests.cs | 7 +- .../DifferenceConfigurationTests.cs | 88 ++------------ .../ObjectsComparer/ComparisonSettings.cs | 12 +- .../DifferenceTreeNodeProvider.cs | 2 +- .../ImplicitDifferenceTreeNode.cs | 2 +- 6 files changed, 118 insertions(+), 103 deletions(-) diff --git a/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs b/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs index 4169306..f4ead2d 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs @@ -12,6 +12,7 @@ using System.Text; using System.Collections; using System.Reflection; +using System.IO; namespace ObjectsComparer.Tests { @@ -305,6 +306,7 @@ public void ClassArrayInequalityCount_CompareByKey_DoesNotThrow_ElementKeyNotFou var a2 = new A { ArrayOfB = new[] { new B { Property1 = "Str1" }, new B { Property1 = "Str2" } } }; var settings = new ComparisonSettings(); + settings.ConfigureListComparison(listOptions => listOptions .CompareUnequalLists(true) .CompareElementsByKey(keyOptions => keyOptions.ThrowKeyNotFound(false))); @@ -397,7 +399,10 @@ public void ClassArrayInequalityProperty_CompareByKey_FormatKey() var a2 = new A { ArrayOfB = new[] { new B { Property1 = "Str1", Id = 1 }, new B { Property1 = "Str3", Id = 2 } } }; var settings = new ComparisonSettings(); - settings.ConfigureListComparison(listOptions => listOptions.CompareElementsByKey(keyOptions => keyOptions.FormatElementKey(args => $"Id={args.ElementKey}"))); + + settings.ConfigureListComparison(listOptions => + listOptions + .CompareElementsByKey(keyOptions => keyOptions.FormatElementKey(args => $"Id={args.ElementKey}"))); var comparer = new Comparer(settings); @@ -1943,7 +1948,7 @@ public TestClassB ClassBProperty } [Test] - public void CompareObjectListByContext() + public void BuildDifferenceTree() { var student1 = new Student { @@ -1969,26 +1974,69 @@ public void CompareObjectListByContext() } }; - var customer = new Customer - { - Person = new Person - { - ListOfAddress1 = new List
- { - new Address { City = "Olomouc", Country = "Czech republic 2" } - } - } - }; + var comparer = new Comparer(); - var comparer = new ComparersFactory().GetObjectsComparer(); var rootNode = comparer.CalculateDifferenceTree(student1, student2); - var diffs = rootNode.GetDifferences(true).ToArray(); var stringBuilder = new StringBuilder(); WalkDifferenceTree(rootNode, 0, stringBuilder); var differenceTreeStr = stringBuilder.ToString(); var differenceTreeJson = (rootNode as DifferenceTreeNode).ToJson(); + /* + * differenceTreeStr: + ? + Person + FirstName + LastName + Birthdate + PhoneNumber + ListOfAddress1 + [0] + Id + City + Difference: DifferenceType=ValueMismatch, MemberPath='Person.ListOfAddress1[0].City', Value1='Prag', Value2='Olomouc'. + Country + Difference: DifferenceType=ValueMismatch, MemberPath='Person.ListOfAddress1[0].Country', Value1='Czech republic', Value2='Czech republic 2'. + State + PostalCode + Street + [1] + Id + City + Country + State + PostalCode + Street + ListOfAddress2 + */ + + using (var sr = new System.IO.StringReader(differenceTreeStr)) + { + var expectedLine = sr.ReadLine(); + Assert.AreEqual(expectedLine.Trim(), "?"); + expectedLine = sr.ReadLine(); + Assert.AreEqual(expectedLine.Trim(), "Person"); + expectedLine = sr.ReadLine(); + Assert.AreEqual(expectedLine.Trim(), "FirstName"); + expectedLine = sr.ReadLine(); + Assert.AreEqual(expectedLine.Trim(), "LastName"); + expectedLine = sr.ReadLine(); + Assert.AreEqual(expectedLine.Trim(), "Birthdate"); + expectedLine = sr.ReadLine(); + Assert.AreEqual(expectedLine.Trim(), "PhoneNumber"); + expectedLine = sr.ReadLine(); + Assert.AreEqual(expectedLine.Trim(), "ListOfAddress1"); + expectedLine = sr.ReadLine(); + Assert.AreEqual(expectedLine.Trim(), "[0]"); + expectedLine = sr.ReadLine(); + Assert.AreEqual(expectedLine.Trim(), "Id"); + expectedLine = sr.ReadLine(); + Assert.AreEqual(expectedLine.Trim(), "City"); + expectedLine = sr.ReadLine(); + Assert.AreEqual(expectedLine.Trim(), "Difference: DifferenceType=ValueMismatch, MemberPath='Person.ListOfAddress1[0].City', Value1='Prag', Value2='Olomouc'."); + } + rootNode.Shrink(); Debug.WriteLine(""); @@ -1997,6 +2045,35 @@ public void CompareObjectListByContext() WalkDifferenceTree(rootNode, 0, stringBuilder); differenceTreeStr = stringBuilder.ToString(); differenceTreeJson = (rootNode as DifferenceTreeNode).ToJson(); + + /* differenceTreeStr (shrinked): + ? + Person + ListOfAddress1 + [0] + City + Difference: DifferenceType=ValueMismatch, MemberPath='Person.ListOfAddress1[0].City', Value1='Prag', Value2='Olomouc'. + Country + Difference: DifferenceType=ValueMismatch, MemberPath='Person.ListOfAddress1[0].Country', Value1='Czech republic', Value2='Czech republic 2'. + */ + + using (var sr = new System.IO.StringReader(differenceTreeStr)) + { + var expectedLine = sr.ReadLine(); + Assert.AreEqual(expectedLine.Trim(), "?"); + expectedLine = sr.ReadLine(); + Assert.AreEqual(expectedLine.Trim(), "Person"); + expectedLine = sr.ReadLine(); + Assert.AreEqual(expectedLine.Trim(), "ListOfAddress1"); + expectedLine = sr.ReadLine(); + Assert.AreEqual(expectedLine.Trim(), "[0]"); + expectedLine = sr.ReadLine(); + Assert.AreEqual(expectedLine.Trim(), "Id"); + expectedLine = sr.ReadLine(); + Assert.AreEqual(expectedLine.Trim(), "City"); + expectedLine = sr.ReadLine(); + Assert.AreEqual(expectedLine.Trim(), "Difference: DifferenceType=ValueMismatch, MemberPath='Person.ListOfAddress1[0].City', Value1='Prag', Value2='Olomouc'."); + } } void WalkDifferenceTree(IDifferenceTreeNode node, int level, StringBuilder stringBuilder) @@ -2093,11 +2170,12 @@ public void CompareObjectListsByComplexKey() var differences = comparer.CalculateDifferences(a1, a2).ToArray(); Assert.IsTrue(differences.Count() == 1); + Assert.IsTrue(differences.Any(d => d.DifferenceType == DifferenceTypes.ValueMismatch && d.MemberPath == "ListOfC[{ Property1 = Key2a, Property2 = Key2b }].Property3" - && d.Value1 == "Value 2" && - d.Value2 == "Value two")); + && d.Value1 == "Value 2" + && d.Value2 == "Value two")); } } } diff --git a/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs b/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs index 791b15a..3d8ed70 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/Comparer_NonGenericEnumerableTests.cs @@ -52,7 +52,7 @@ public void ShortcutConfigureListComparison(bool compareElementsByKey, int expec var a2 = new int?[] { null, 3, 2, 1 }; var settings = new ComparisonSettings(); - settings.ConfigureListComparison(compareElementsByKey, false); + settings.ConfigureListComparison(compareElementsByKey); var comparer = new Comparer(settings); @@ -277,10 +277,7 @@ public void NullAndNotNullElementsInequality_CompareByKey() var a2 = new A { NonGenericEnumerable = new ArrayList { "Str2", null } }; var settings = new ComparisonSettings(); - settings.ConfigureListComparison(listOptions => - { - listOptions.CompareElementsByKey(); - }); + settings.ConfigureListComparison(compareElementsByKey: true); var comparer = new Comparer(settings); diff --git a/ObjectsComparer/ObjectsComparer.Tests/DifferenceConfigurationTests.cs b/ObjectsComparer/ObjectsComparer.Tests/DifferenceConfigurationTests.cs index f40bd47..99f9188 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/DifferenceConfigurationTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/DifferenceConfigurationTests.cs @@ -90,8 +90,8 @@ public void PreserveRawValuesConditionaly() [Test] public void CustomizeMemberPath() { - var a1 = new A() { IntProperty = 10, TestProperty2 = "value1", ListOfC = new List { new C { Property1 = "property1" } } }; - var a2 = new A() { IntProperty = 11, TestProperty2 = "value2", ListOfC = new List { new C { Property1 = "property2" } } }; + var a1 = new A() { ClassB = new B { Property1 = "value1 " }, IntProperty = 10, TestProperty2 = "value1", ListOfC = new List { new C { Property1 = "property1" } } }; + var a2 = new A() { ClassB = new B { Property1 = "value2 " }, IntProperty = 11, TestProperty2 = "value2", ListOfC = new List { new C { Property1 = "property2" } } }; var settings = new ComparisonSettings(); @@ -104,7 +104,14 @@ public void CustomizeMemberPath() } else if (currentProperty.Member.Name == nameof(C.Property1)) { - options.UseDifferenceFactory(args => new Difference("First property", args.DefaultDifference.Value1, args.DefaultDifference.Value2)); + if (currentProperty.Ancestor.Member.Name == "ClassB") + { + options.UseDifferenceFactory(args => new Difference("First property of Class B", args.DefaultDifference.Value1, args.DefaultDifference.Value2)); + } + else + { + options.UseDifferenceFactory(args => new Difference("First property of class A", args.DefaultDifference.Value1, args.DefaultDifference.Value2)); + } } }) .ConfigureDifferencePath((parentProperty, options) => @@ -121,80 +128,9 @@ public void CustomizeMemberPath() Assert.IsTrue(differences.Any(diff => diff.MemberPath == "Integer property")); Assert.IsTrue(differences.Any(diff => diff.MemberPath == "TestProperty2")); - Assert.IsTrue(differences.Any(diff => diff.MemberPath == "Collection of C objects[0].First property")); + Assert.IsTrue(differences.Any(diff => diff.MemberPath == "Collection of C objects[0].First property of class A")); + Assert.IsTrue(differences.Any(diff => diff.MemberPath == "ClassB.First property of Class B")); } - - //[Test] - //public void CreateDifferenceIncludeRawValues() - //{ - // var sourceDifference = new Difference( - // memberPath: "PathXY", - // value1: "VALUE1", - // value2: "VALUE2", - // rawValue1: new { Value = "VALUE1" }, - // rawValue2: new { Value = "VALUE2" }, - // differenceType: DifferenceTypes.TypeMismatch); - - // var differenceTreeNode = new DifferenceTreeNode(new DifferenceTreeNodeMember()); - // var settings = new ComparisonSettings(); - - // settings.ConfigureDifference(includeRawValues: true); - - // var targetDifference = DifferenceProvider.CreateDifference(settings, differenceTreeNode, sourceDifference,null, null); - - // Assert.IsTrue(targetDifference == sourceDifference); - //} - - //[Test] - //public void CreateDifferenceNotIncludeRawValues() - //{ - // var sourceDifference = new Difference( - // memberPath: "PathXY", - // value1: "VALUE1", - // value2: "VALUE2", - // rawValue1: new { Value = "VALUE1" }, - // rawValue2: new { Value = "VALUE2" }, - // differenceType: DifferenceTypes.TypeMismatch); - - // var differenceTreeNode = new DifferenceTreeNode(new DifferenceTreeNodeMember()); - // var settings = new ComparisonSettings(); - - // settings.ConfigureDifference(includeRawValues: false); - - // var targetDifference = DifferenceProvider.CreateDifference(settings, differenceTreeNode, sourceDifference, null, null); - - // Assert.IsTrue(targetDifference.MemberPath == targetDifference.MemberPath); - // Assert.IsTrue(targetDifference.Value1 == targetDifference.Value1); - // Assert.IsTrue(targetDifference.Value2 == targetDifference.Value2); - // Assert.IsTrue(targetDifference.RawValue2 == null); - // Assert.IsTrue(targetDifference.RawValue1 == null); - // Assert.IsFalse(targetDifference == sourceDifference); - // } - - //[Test] - //[TestCase(true)] - //[TestCase(false)] - //public void NoDifferenceFactorySourceTargetDifferenceEquality(bool includeRawValues) - //{ - // var differenceTreeNode = new DifferenceTreeNode(new DifferenceTreeNodeMember()); - // var settings = new ComparisonSettings(); - - // settings.ConfigureDifference(includeRawValues); - - // var sourceDifference = new Difference( - // memberPath: "PathXY", - // value1: "VALUE1", - // value2: "VALUE2", - // rawValue1: new { Value = "VALUE1" }, - // rawValue2: new { Value = "VALUE2" }, - // differenceType: DifferenceTypes.TypeMismatch); - - // var targetDifference = DifferenceProvider.CreateDifference(settings, differenceTreeNode, sourceDifference, null, null); - - // Assert.AreEqual(includeRawValues, sourceDifference == targetDifference); - // Assert.AreEqual(includeRawValues, targetDifference.RawValue1 != null); - // Assert.AreEqual(includeRawValues, targetDifference.RawValue2 != null); - //} } } diff --git a/ObjectsComparer/ObjectsComparer/ComparisonSettings.cs b/ObjectsComparer/ObjectsComparer/ComparisonSettings.cs index d70502c..2b5cfb0 100644 --- a/ObjectsComparer/ObjectsComparer/ComparisonSettings.cs +++ b/ObjectsComparer/ObjectsComparer/ComparisonSettings.cs @@ -127,10 +127,8 @@ public ComparisonSettings ConfigureListComparison(bool compareElementsByKey = fa public Action DifferenceTreeOptionsAction { get; private set; } /// - /// Configures the difference tree behavior, see . + /// Configures creation of the instance, see . /// - /// - /// public ComparisonSettings ConfigureDifferenceTree(Action options) { DifferenceTreeOptionsAction = options ?? throw new ArgumentNullException(nameof(options)); @@ -140,6 +138,9 @@ public ComparisonSettings ConfigureDifferenceTree(Action DifferenceOptionsAction; + /// + /// Configures creation of the instance, see . + /// public ComparisonSettings ConfigureDifference(Action differenceOptions) { DifferenceOptionsAction = differenceOptions ?? throw new ArgumentNullException(nameof(differenceOptions)); @@ -147,6 +148,9 @@ public ComparisonSettings ConfigureDifference(Action + /// Configures creation of the instance. + ///
public ComparisonSettings ConfigureDifference(bool includeRawValues) { ConfigureDifference((_, options) => options.IncludeRawValues(includeRawValues)); @@ -157,7 +161,7 @@ public ComparisonSettings ConfigureDifference(bool includeRawValues) public Action DifferencePathOptionsAction; /// - /// Behavior of the insertion into the difference path. + /// Configures the insertion into the difference path, see . /// /// /// First parameter: The parent of the property to which the path is inserted. diff --git a/ObjectsComparer/ObjectsComparer/DifferenceTree/DifferenceTreeNodeProvider.cs b/ObjectsComparer/ObjectsComparer/DifferenceTree/DifferenceTreeNodeProvider.cs index dc330b8..d25664f 100644 --- a/ObjectsComparer/ObjectsComparer/DifferenceTree/DifferenceTreeNodeProvider.cs +++ b/ObjectsComparer/ObjectsComparer/DifferenceTree/DifferenceTreeNodeProvider.cs @@ -11,7 +11,7 @@ public static IDifferenceTreeNode CreateRootNode() } /// - /// Returns the root of the difference tree for cases where the consumer does not explicitly, directly or indirectly request the difference tree, ie the difference tree is created only as an auxiliary. + /// Returns the root of the difference tree for cases where the consumer does not explicitly, directly or indirectly request the difference tree, i.e the difference tree is created only as an auxiliary. /// public static IDifferenceTreeNode CreateImplicitRootNode(ComparisonSettings comparisonSettings) { diff --git a/ObjectsComparer/ObjectsComparer/DifferenceTree/ImplicitDifferenceTreeNode.cs b/ObjectsComparer/ObjectsComparer/DifferenceTree/ImplicitDifferenceTreeNode.cs index ae6d9c0..8e05256 100644 --- a/ObjectsComparer/ObjectsComparer/DifferenceTree/ImplicitDifferenceTreeNode.cs +++ b/ObjectsComparer/ObjectsComparer/DifferenceTree/ImplicitDifferenceTreeNode.cs @@ -4,7 +4,7 @@ namespace ObjectsComparer { /// - /// The root of the difference tree for cases where the consumer does not explicitly, directly or indirectly request the difference tree, ie the difference tree is created only as an auxiliary. + /// The root of the difference tree for cases where the consumer does not explicitly, directly or indirectly request the difference tree, i.e the difference tree is created only as an auxiliary. /// internal class ImplicitDifferenceTreeNode : DifferenceTreeNodeBase { From 49f1ccec52bd8dba1ed8d36fdc1f4f0c059135f8 Mon Sep 17 00:00:00 2001 From: nemec Date: Fri, 8 Jul 2022 13:52:31 +0200 Subject: [PATCH 175/181] Add BuildDifferenceTree_CustomizeMemberNames. --- .../Comparer_GenericEnumerableTests.cs | 152 ++++++++++++++++++ 1 file changed, 152 insertions(+) diff --git a/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs b/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs index f4ead2d..6c75d5d 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs @@ -2076,6 +2076,158 @@ public void BuildDifferenceTree() } } + [Test] + public void BuildDifferenceTree_CustomizeMemberNames() + { + var student1 = new Student + { + Person = new Person + { + ListOfAddress1 = new List
+ { + new Address { City = "Prag", Country = "Czech republic" }, + new Address { City = "Prag", Country = "Czech republic" } + } + } + }; + + var student2 = new Student + { + Person = new Person + { + ListOfAddress1 = new List
+ { + new Address { City = "Olomouc", Country = "Czech republic 2" }, + new Address { City = "Prag", Country = "Czech republic" } + } + } + }; + + var settings = new ComparisonSettings(); + + settings.ConfigureDifferenceTree((ancestor, options) => + { + options.UseDifferenceTreeNodeMemberFactory(defaultMember => new DifferenceTreeNodeMember(defaultMember.Info, TranslateToCzech(defaultMember?.Name))); + }); + + var comparer = new Comparer(settings); + + var rootNode = comparer.CalculateDifferenceTree(student1, student2); + + var stringBuilder = new StringBuilder(); + WalkDifferenceTree(rootNode, 0, stringBuilder); + var differenceTreeStr = stringBuilder.ToString(); + var differenceTreeJson = (rootNode as DifferenceTreeNode).ToJson(); + + /* + * differenceTreeStr: + ? + Person + FirstName + LastName + Birthdate + PhoneNumber + ListOfAddress1 + [0] + Id + City + Difference: DifferenceType=ValueMismatch, MemberPath='Person.ListOfAddress1[0].City', Value1='Prag', Value2='Olomouc'. + Country + Difference: DifferenceType=ValueMismatch, MemberPath='Person.ListOfAddress1[0].Country', Value1='Czech republic', Value2='Czech republic 2'. + State + PostalCode + Street + [1] + Id + City + Country + State + PostalCode + Street + ListOfAddress2 + */ + + using (var sr = new System.IO.StringReader(differenceTreeStr)) + { + var expectedLine = sr.ReadLine(); + Assert.AreEqual(expectedLine.Trim(), "?"); + expectedLine = sr.ReadLine(); + Assert.AreEqual(expectedLine.Trim(), "Person"); + expectedLine = sr.ReadLine(); + Assert.AreEqual(expectedLine.Trim(), "FirstName"); + expectedLine = sr.ReadLine(); + Assert.AreEqual(expectedLine.Trim(), "LastName"); + expectedLine = sr.ReadLine(); + Assert.AreEqual(expectedLine.Trim(), "Birthdate"); + expectedLine = sr.ReadLine(); + Assert.AreEqual(expectedLine.Trim(), "PhoneNumber"); + expectedLine = sr.ReadLine(); + Assert.AreEqual(expectedLine.Trim(), "ListOfAddress1"); + expectedLine = sr.ReadLine(); + Assert.AreEqual(expectedLine.Trim(), "[0]"); + expectedLine = sr.ReadLine(); + Assert.AreEqual(expectedLine.Trim(), "Id"); + expectedLine = sr.ReadLine(); + Assert.AreEqual(expectedLine.Trim(), "City"); + expectedLine = sr.ReadLine(); + Assert.AreEqual(expectedLine.Trim(), "Difference: DifferenceType=ValueMismatch, MemberPath='Person.ListOfAddress1[0].City', Value1='Prag', Value2='Olomouc'."); + } + + rootNode.Shrink(); + + Debug.WriteLine(""); + + stringBuilder = new StringBuilder(); + WalkDifferenceTree(rootNode, 0, stringBuilder); + differenceTreeStr = stringBuilder.ToString(); + differenceTreeJson = (rootNode as DifferenceTreeNode).ToJson(); + + /* differenceTreeStr (shrinked): + ? + Person + ListOfAddress1 + [0] + City + Difference: DifferenceType=ValueMismatch, MemberPath='Person.ListOfAddress1[0].City', Value1='Prag', Value2='Olomouc'. + Country + Difference: DifferenceType=ValueMismatch, MemberPath='Person.ListOfAddress1[0].Country', Value1='Czech republic', Value2='Czech republic 2'. + */ + + using (var sr = new System.IO.StringReader(differenceTreeStr)) + { + var expectedLine = sr.ReadLine(); + Assert.AreEqual(expectedLine.Trim(), "?"); + expectedLine = sr.ReadLine(); + Assert.AreEqual(expectedLine.Trim(), "Person"); + expectedLine = sr.ReadLine(); + Assert.AreEqual(expectedLine.Trim(), "ListOfAddress1"); + expectedLine = sr.ReadLine(); + Assert.AreEqual(expectedLine.Trim(), "[0]"); + expectedLine = sr.ReadLine(); + Assert.AreEqual(expectedLine.Trim(), "Id"); + expectedLine = sr.ReadLine(); + Assert.AreEqual(expectedLine.Trim(), "City"); + expectedLine = sr.ReadLine(); + Assert.AreEqual(expectedLine.Trim(), "Difference: DifferenceType=ValueMismatch, MemberPath='Person.ListOfAddress1[0].City', Value1='Prag', Value2='Olomouc'."); + } + } + + string TranslateToCzech(string original) + { + var translated = original; + + switch (original) + { + case "Person": + translated = "Osoba"; + break; + default: + break; + } + + return translated; + } + void WalkDifferenceTree(IDifferenceTreeNode node, int level, StringBuilder stringBuilder) { var blankMemberName = "?"; From 76984edb8d78f5a4dc5636c04b06b6a8e1e4d3ab Mon Sep 17 00:00:00 2001 From: Daniel Nemec Date: Sun, 10 Jul 2022 15:57:37 +0200 Subject: [PATCH 176/181] Add new ConfigureDifference method. Edit test methods. --- .../Comparer_GenericEnumerableTests.cs | 222 +++++++++++------- .../ObjectsComparer/ComparisonSettings.cs | 24 ++ 2 files changed, 167 insertions(+), 79 deletions(-) diff --git a/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs b/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs index 6c75d5d..301db5a 100644 --- a/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs +++ b/ObjectsComparer/ObjectsComparer.Tests/Comparer_GenericEnumerableTests.cs @@ -1948,7 +1948,7 @@ public TestClassB ClassBProperty } [Test] - public void BuildDifferenceTree() + public void CalculateCompletedDifferenceTree() { var student1 = new Student { @@ -1956,8 +1956,8 @@ public void BuildDifferenceTree() { ListOfAddress1 = new List
{ - new Address { City = "Prag", Country = "Czech republic" }, - new Address { City = "Prag", Country = "Czech republic" } + new Address { City = "Prague", Country = "Czech republic" }, + new Address { City = "Pilsen", Country = "Czech republic" } } } }; @@ -1968,8 +1968,8 @@ public void BuildDifferenceTree() { ListOfAddress1 = new List
{ - new Address { City = "Olomouc", Country = "Czech republic 2" }, - new Address { City = "Prag", Country = "Czech republic" } + new Address { City = "Olomouc", Country = "Czechia" }, + new Address { City = "Pilsen", Country = "Czech republic" } } } }; @@ -1978,10 +1978,11 @@ public void BuildDifferenceTree() var rootNode = comparer.CalculateDifferenceTree(student1, student2); + Assert.AreEqual(2, rootNode.GetDifferences(recursive: true).Count()); + var stringBuilder = new StringBuilder(); WalkDifferenceTree(rootNode, 0, stringBuilder); var differenceTreeStr = stringBuilder.ToString(); - var differenceTreeJson = (rootNode as DifferenceTreeNode).ToJson(); /* * differenceTreeStr: @@ -1995,9 +1996,9 @@ public void BuildDifferenceTree() [0] Id City - Difference: DifferenceType=ValueMismatch, MemberPath='Person.ListOfAddress1[0].City', Value1='Prag', Value2='Olomouc'. + Difference: DifferenceType=ValueMismatch, MemberPath='Person.ListOfAddress1[0].City', Value1='Prague', Value2='Olomouc'. Country - Difference: DifferenceType=ValueMismatch, MemberPath='Person.ListOfAddress1[0].Country', Value1='Czech republic', Value2='Czech republic 2'. + Difference: DifferenceType=ValueMismatch, MemberPath='Person.ListOfAddress1[0].Country', Value1='Czech republic', Value2='Czechia'. State PostalCode Street @@ -2034,17 +2035,18 @@ public void BuildDifferenceTree() expectedLine = sr.ReadLine(); Assert.AreEqual(expectedLine.Trim(), "City"); expectedLine = sr.ReadLine(); - Assert.AreEqual(expectedLine.Trim(), "Difference: DifferenceType=ValueMismatch, MemberPath='Person.ListOfAddress1[0].City', Value1='Prag', Value2='Olomouc'."); + Assert.AreEqual(expectedLine.Trim(), "Difference: DifferenceType=ValueMismatch, MemberPath='Person.ListOfAddress1[0].City', Value1='Prague', Value2='Olomouc'."); + expectedLine = sr.ReadLine(); + Assert.AreEqual(expectedLine.Trim(), "Country"); + expectedLine = sr.ReadLine(); + Assert.AreEqual(expectedLine.Trim(), "Difference: DifferenceType=ValueMismatch, MemberPath='Person.ListOfAddress1[0].Country', Value1='Czech republic', Value2='Czechia'."); } rootNode.Shrink(); - Debug.WriteLine(""); - stringBuilder = new StringBuilder(); WalkDifferenceTree(rootNode, 0, stringBuilder); differenceTreeStr = stringBuilder.ToString(); - differenceTreeJson = (rootNode as DifferenceTreeNode).ToJson(); /* differenceTreeStr (shrinked): ? @@ -2052,9 +2054,9 @@ public void BuildDifferenceTree() ListOfAddress1 [0] City - Difference: DifferenceType=ValueMismatch, MemberPath='Person.ListOfAddress1[0].City', Value1='Prag', Value2='Olomouc'. + Difference: DifferenceType=ValueMismatch, MemberPath='Person.ListOfAddress1[0].City', Value1='Prague', Value2='Olomouc'. Country - Difference: DifferenceType=ValueMismatch, MemberPath='Person.ListOfAddress1[0].Country', Value1='Czech republic', Value2='Czech republic 2'. + Difference: DifferenceType=ValueMismatch, MemberPath='Person.ListOfAddress1[0].Country', Value1='Czech republic', Value2='Czechia'. */ using (var sr = new System.IO.StringReader(differenceTreeStr)) @@ -2068,16 +2070,18 @@ public void BuildDifferenceTree() expectedLine = sr.ReadLine(); Assert.AreEqual(expectedLine.Trim(), "[0]"); expectedLine = sr.ReadLine(); - Assert.AreEqual(expectedLine.Trim(), "Id"); - expectedLine = sr.ReadLine(); Assert.AreEqual(expectedLine.Trim(), "City"); expectedLine = sr.ReadLine(); - Assert.AreEqual(expectedLine.Trim(), "Difference: DifferenceType=ValueMismatch, MemberPath='Person.ListOfAddress1[0].City', Value1='Prag', Value2='Olomouc'."); + Assert.AreEqual(expectedLine.Trim(), "Difference: DifferenceType=ValueMismatch, MemberPath='Person.ListOfAddress1[0].City', Value1='Prague', Value2='Olomouc'."); + expectedLine = sr.ReadLine(); + Assert.AreEqual(expectedLine.Trim(), "Country"); + expectedLine = sr.ReadLine(); + Assert.AreEqual(expectedLine.Trim(), "Difference: DifferenceType=ValueMismatch, MemberPath='Person.ListOfAddress1[0].Country', Value1='Czech republic', Value2='Czechia'."); } } [Test] - public void BuildDifferenceTree_CustomizeMemberNames() + public void CalculateUncompletedDifferenceTree() { var student1 = new Student { @@ -2085,8 +2089,8 @@ public void BuildDifferenceTree_CustomizeMemberNames() { ListOfAddress1 = new List
{ - new Address { City = "Prag", Country = "Czech republic" }, - new Address { City = "Prag", Country = "Czech republic" } + new Address { City = "Prague", Country = "Czech republic" }, + new Address { City = "Pilsen", Country = "Czech republic" } } } }; @@ -2097,54 +2101,31 @@ public void BuildDifferenceTree_CustomizeMemberNames() { ListOfAddress1 = new List
{ - new Address { City = "Olomouc", Country = "Czech republic 2" }, - new Address { City = "Prag", Country = "Czech republic" } + new Address { City = "Olomouc", Country = "Czechia" }, + new Address { City = "Pilsen", Country = "Czech republic" } } } }; - var settings = new ComparisonSettings(); + var comparer = new Comparer(); - settings.ConfigureDifferenceTree((ancestor, options) => - { - options.UseDifferenceTreeNodeMemberFactory(defaultMember => new DifferenceTreeNodeMember(defaultMember.Info, TranslateToCzech(defaultMember?.Name))); - }); + var rootNode = comparer.CalculateDifferenceTree(student1, student2, ctx => false); - var comparer = new Comparer(settings); + Assert.AreEqual(1, rootNode.GetDifferences(recursive: true).Count()); - var rootNode = comparer.CalculateDifferenceTree(student1, student2); + rootNode.Shrink(); var stringBuilder = new StringBuilder(); WalkDifferenceTree(rootNode, 0, stringBuilder); var differenceTreeStr = stringBuilder.ToString(); - var differenceTreeJson = (rootNode as DifferenceTreeNode).ToJson(); - /* - * differenceTreeStr: - ? + /* differenceTreeStr (shrinked): + ? Person - FirstName - LastName - Birthdate - PhoneNumber ListOfAddress1 [0] - Id City - Difference: DifferenceType=ValueMismatch, MemberPath='Person.ListOfAddress1[0].City', Value1='Prag', Value2='Olomouc'. - Country - Difference: DifferenceType=ValueMismatch, MemberPath='Person.ListOfAddress1[0].Country', Value1='Czech republic', Value2='Czech republic 2'. - State - PostalCode - Street - [1] - Id - City - Country - State - PostalCode - Street - ListOfAddress2 + Difference: DifferenceType=ValueMismatch, MemberPath='Person.ListOfAddress1[0].City', Value1='Prague', Value2='Olomouc'. */ using (var sr = new System.IO.StringReader(differenceTreeStr)) @@ -2154,61 +2135,123 @@ public void BuildDifferenceTree_CustomizeMemberNames() expectedLine = sr.ReadLine(); Assert.AreEqual(expectedLine.Trim(), "Person"); expectedLine = sr.ReadLine(); - Assert.AreEqual(expectedLine.Trim(), "FirstName"); - expectedLine = sr.ReadLine(); - Assert.AreEqual(expectedLine.Trim(), "LastName"); - expectedLine = sr.ReadLine(); - Assert.AreEqual(expectedLine.Trim(), "Birthdate"); - expectedLine = sr.ReadLine(); - Assert.AreEqual(expectedLine.Trim(), "PhoneNumber"); - expectedLine = sr.ReadLine(); Assert.AreEqual(expectedLine.Trim(), "ListOfAddress1"); expectedLine = sr.ReadLine(); Assert.AreEqual(expectedLine.Trim(), "[0]"); expectedLine = sr.ReadLine(); - Assert.AreEqual(expectedLine.Trim(), "Id"); - expectedLine = sr.ReadLine(); Assert.AreEqual(expectedLine.Trim(), "City"); expectedLine = sr.ReadLine(); - Assert.AreEqual(expectedLine.Trim(), "Difference: DifferenceType=ValueMismatch, MemberPath='Person.ListOfAddress1[0].City', Value1='Prag', Value2='Olomouc'."); + Assert.AreEqual(expectedLine.Trim(), "Difference: DifferenceType=ValueMismatch, MemberPath='Person.ListOfAddress1[0].City', Value1='Prague', Value2='Olomouc'."); + expectedLine = sr.ReadLine(); + Assert.AreEqual(expectedLine, null); } + } + + [Test] + public void CalculateDifferencesTranslateMembers() + { + var student1 = new Student + { + Person = new Person + { + ListOfAddress1 = new List
+ { + new Address { City = "Prague", Country = "Czech republic" }, + new Address { City = "Pilsen", Country = "Czech republic" } + } + } + }; + var student2 = new Student + { + Person = new Person + { + ListOfAddress1 = new List
+ { + new Address { City = "Olomouc", Country = "Czechia" }, + new Address { City = "Pilsen", Country = "Czech republic" } + } + } + }; + + var settings = new ComparisonSettings(); + settings.ConfigureDifference(defaultMemberName => TranslateToCzech(defaultMemberName)); + var comparer = new Comparer(settings); + var differences = comparer.CalculateDifferences(student1, student2).ToArray(); + + Assert.AreEqual(2, differences.Count()); + Assert.IsTrue(differences.Any(d => d.DifferenceType == DifferenceTypes.ValueMismatch && d.MemberPath == "Osoba.Seznam adres 1[0].Město" && d.Value1 == "Prague" && d.Value2 == "Olomouc")); + Assert.IsTrue(differences.Any(d => d.DifferenceType == DifferenceTypes.ValueMismatch && d.MemberPath == "Osoba.Seznam adres 1[0].Stát" && d.Value1 == "Czech republic" && d.Value2 == "Czechia")); + } + + [Test] + public void CalculateDifferenceTreeTranslateMembers() + { + var student1 = new Student + { + Person = new Person + { + ListOfAddress1 = new List
+ { + new Address { City = "Prague", Country = "Czech republic" }, + new Address { City = "Pilsen", Country = "Czech republic" } + } + } + }; + + var student2 = new Student + { + Person = new Person + { + ListOfAddress1 = new List
+ { + new Address { City = "Olomouc", Country = "Czechia" }, + new Address { City = "Pilsen", Country = "Czech republic" } + } + } + }; + + var settings = new ComparisonSettings(); + settings.ConfigureDifference(defaultMemberName => TranslateToCzech(defaultMemberName)); + var comparer = new Comparer(settings); + var rootNode = comparer.CalculateDifferenceTree(student1, student2); rootNode.Shrink(); - Debug.WriteLine(""); + Assert.AreEqual(2, rootNode.GetDifferences(recursive: true).Count()); - stringBuilder = new StringBuilder(); + var stringBuilder = new StringBuilder(); WalkDifferenceTree(rootNode, 0, stringBuilder); - differenceTreeStr = stringBuilder.ToString(); - differenceTreeJson = (rootNode as DifferenceTreeNode).ToJson(); + var differenceTreeStr = stringBuilder.ToString(); /* differenceTreeStr (shrinked): ? - Person - ListOfAddress1 + Osoba + Seznam adres 1 [0] - City - Difference: DifferenceType=ValueMismatch, MemberPath='Person.ListOfAddress1[0].City', Value1='Prag', Value2='Olomouc'. - Country - Difference: DifferenceType=ValueMismatch, MemberPath='Person.ListOfAddress1[0].Country', Value1='Czech republic', Value2='Czech republic 2'. + Město + Difference: DifferenceType=ValueMismatch, MemberPath='Osoba.Seznam adres 1[0].Město', Value1='Prague', Value2='Olomouc'. + Stát + Difference: DifferenceType=ValueMismatch, MemberPath='Osoba.Seznam adres 1[0].Stát', Value1='Czech republic', Value2='Czechia'. */ - using (var sr = new System.IO.StringReader(differenceTreeStr)) + using (var sr = new StringReader(differenceTreeStr)) { var expectedLine = sr.ReadLine(); Assert.AreEqual(expectedLine.Trim(), "?"); expectedLine = sr.ReadLine(); - Assert.AreEqual(expectedLine.Trim(), "Person"); + Assert.AreEqual(expectedLine.Trim(), "Osoba"); expectedLine = sr.ReadLine(); - Assert.AreEqual(expectedLine.Trim(), "ListOfAddress1"); + Assert.AreEqual(expectedLine.Trim(), "Seznam adres 1"); expectedLine = sr.ReadLine(); Assert.AreEqual(expectedLine.Trim(), "[0]"); expectedLine = sr.ReadLine(); - Assert.AreEqual(expectedLine.Trim(), "Id"); + Assert.AreEqual(expectedLine.Trim(), "Město"); expectedLine = sr.ReadLine(); - Assert.AreEqual(expectedLine.Trim(), "City"); + Assert.AreEqual(expectedLine.Trim(), "Difference: DifferenceType=ValueMismatch, MemberPath='Osoba.Seznam adres 1[0].Město', Value1='Prague', Value2='Olomouc'."); + expectedLine = sr.ReadLine(); + Assert.AreEqual(expectedLine.Trim(), "Stát"); expectedLine = sr.ReadLine(); - Assert.AreEqual(expectedLine.Trim(), "Difference: DifferenceType=ValueMismatch, MemberPath='Person.ListOfAddress1[0].City', Value1='Prag', Value2='Olomouc'."); + Assert.AreEqual(expectedLine.Trim(), "Difference: DifferenceType=ValueMismatch, MemberPath='Osoba.Seznam adres 1[0].Stát', Value1='Czech republic', Value2='Czechia'."); } } @@ -2221,6 +2264,27 @@ string TranslateToCzech(string original) case "Person": translated = "Osoba"; break; + case "FirstName": + translated = "Křestní jméno"; + break; + case "LastName": + translated = "Příjmení"; + break; + case "Birthdate": + translated = "Datum narození"; + break; + case "PhoneNumber": + translated = "Číslo telefonu"; + break; + case "ListOfAddress1": + translated = "Seznam adres 1"; + break; + case "City": + translated = "Město"; + break; + case "Country": + translated = "Stát"; + break; default: break; } diff --git a/ObjectsComparer/ObjectsComparer/ComparisonSettings.cs b/ObjectsComparer/ObjectsComparer/ComparisonSettings.cs index 2b5cfb0..4274c79 100644 --- a/ObjectsComparer/ObjectsComparer/ComparisonSettings.cs +++ b/ObjectsComparer/ObjectsComparer/ComparisonSettings.cs @@ -158,6 +158,30 @@ public ComparisonSettings ConfigureDifference(bool includeRawValues) return this; } + public ComparisonSettings ConfigureDifference(Func memberNameProvider, bool includeRawValues = false) + { + ConfigureDifferenceTree((_, options) => + options.UseDifferenceTreeNodeMemberFactory(defaultMember => + new DifferenceTreeNodeMember( + defaultMember.Info, + memberNameProvider(defaultMember.Name)))); + + ConfigureDifference((_, options) => + options.UseDifferenceFactory(args => + new Difference( + memberPath: memberNameProvider(args.DefaultDifference.MemberPath), + args.DefaultDifference.Value1, + args.DefaultDifference.Value2, + args.DefaultDifference.DifferenceType, + rawValue1: includeRawValues ? args.RawValue1 : null, + rawValue2: includeRawValues ? args.RawValue2 : null))); + + ConfigureDifferencePath((_, options) => + options.UseInsertPathFactory(args => memberNameProvider(args.DefaultRootElementPath))); + + return this; + } + public Action DifferencePathOptionsAction; /// From ef01a37c2271ce11f1350566e3e1eb4a01443aa1 Mon Sep 17 00:00:00 2001 From: Daniel Nemec Date: Tue, 12 Jul 2022 09:44:20 +0200 Subject: [PATCH 177/181] Edit comments. --- .../ObjectsComparer/ComparisonSettings.cs | 12 +++++-- .../ObjectsComparer/DifferenceOptions.cs | 2 +- .../ObjectsComparer/DifferencePathOptions.cs | 7 ++-- .../DifferenceTree/ComparerExtensions.cs | 32 ++++++++++++------- .../DifferenceTree/ComparisonContext.cs | 10 +++--- .../DifferenceTree/DifferenceTreeOptions.cs | 9 ++++-- .../ObjectsComparer/InsertPathFactoryArgs.cs | 3 ++ .../ListElementComparisonByKeyOptions.cs | 8 +++-- 8 files changed, 57 insertions(+), 26 deletions(-) diff --git a/ObjectsComparer/ObjectsComparer/ComparisonSettings.cs b/ObjectsComparer/ObjectsComparer/ComparisonSettings.cs index 4274c79..f7beb03 100644 --- a/ObjectsComparer/ObjectsComparer/ComparisonSettings.cs +++ b/ObjectsComparer/ObjectsComparer/ComparisonSettings.cs @@ -73,7 +73,9 @@ public T GetCustomSetting(string key = null) /// Configures list comparison behavior, especially the type of the comparison. For more info, see . /// The term list has a general meaning here and includes almost all Enumerable objects. /// - /// First parameter: Current list node. + /// + /// First parameter type: Current list node. + /// public ComparisonSettings ConfigureListComparison(Action comparisonOptions) { if (comparisonOptions is null) @@ -129,6 +131,9 @@ public ComparisonSettings ConfigureListComparison(bool compareElementsByKey = fa /// /// Configures creation of the instance, see . /// + /// + /// First parameter type: The ancestor member the tree node is configured for. + /// public ComparisonSettings ConfigureDifferenceTree(Action options) { DifferenceTreeOptionsAction = options ?? throw new ArgumentNullException(nameof(options)); @@ -141,6 +146,9 @@ public ComparisonSettings ConfigureDifferenceTree(Action /// Configures creation of the instance, see . ///
+ /// + /// First parameter type: The member the difference is configured for. + /// public ComparisonSettings ConfigureDifference(Action differenceOptions) { DifferenceOptionsAction = differenceOptions ?? throw new ArgumentNullException(nameof(differenceOptions)); @@ -188,7 +196,7 @@ public ComparisonSettings ConfigureDifference(Func memberNamePro /// Configures the insertion into the difference path, see . ///