public void WithComplexPropertyThrows() { var expected = "Synchronize.PropertyValues(x, y) failed.\r\n" + "The property WithComplexProperty.ComplexType of type ComplexType is not supported.\r\n" + "Solve the problem by any of:\r\n" + "* Make ComplexType immutable or use an immutable type.\r\n" + " - For immutable types the following must hold:\r\n" + " - Must be a sealed class or a struct.\r\n" + " - All fields and properties must be readonly.\r\n" + " - All field and property types must be immutable.\r\n" + " - All indexers must be readonly.\r\n" + " - Event fields are ignored.\r\n" + "* Use PropertiesSettings and specify how copying is performed:\r\n" + " - ReferenceHandling.Structural means that a the entire graph is traversed and immutable property values are copied.\r\n" + " - For structural Activator.CreateInstance is used to create instances so a parameterless constructor may be needed, can be private.\r\n" + " - ReferenceHandling.References means that references are copied.\r\n" + " - Exclude a combination of the following:\r\n" + " - The property WithComplexProperty.ComplexType.\r\n" + " - The type ComplexType.\r\n"; var source = new WithComplexProperty(); var target = new WithComplexProperty(); var exception = Assert.Throws <NotSupportedException>(() => Synchronize.PropertyValues(source, target, ReferenceHandling.Throw)); Assert.AreEqual(expected, exception.Message); Assert.DoesNotThrow(() => Synchronize.PropertyValues(source, target, ReferenceHandling.Structural)); Assert.DoesNotThrow(() => Synchronize.PropertyValues(source, target, ReferenceHandling.References)); }
public void WithComplexProperty() { var x = new WithComplexProperty { ComplexType = new ComplexType("a", 1) }; var y = new WithComplexProperty { ComplexType = new ComplexType("a", 1) }; var changes = new List<string>(); var settings = PropertiesSettings.GetOrCreate(); using (var tracker = Track.IsDirty(x, y, settings)) { tracker.PropertyChanged += (_, e) => changes.Add(e.PropertyName); Assert.AreEqual(false, tracker.IsDirty); } x.ComplexType = new ComplexType("b", 2); CollectionAssert.IsEmpty(changes); var wrx = new System.WeakReference(x); var wrxc = new System.WeakReference(x.ComplexType); var wry = new System.WeakReference(y); var wryc = new System.WeakReference(y.ComplexType); x = null; y = null; System.GC.Collect(); Assert.AreEqual(false, wrx.IsAlive); Assert.AreEqual(false, wrxc.IsAlive); Assert.AreEqual(false, wry.IsAlive); Assert.AreEqual(false, wryc.IsAlive); }
public void WithComplexReferenceWhenNotSame() { var x = new WithComplexProperty { Name = "a", Value = 1, ComplexType = new ComplexType { Name = "b", Value = 2 } }; var y = new WithComplexProperty { Name = "a", Value = 1, ComplexType = new ComplexType { Name = "b", Value = 2 } }; var result = this.EqualMethod(x, y, ReferenceHandling.Structural); Assert.AreEqual(true, result); result = this.EqualMethod(x, y, ReferenceHandling.References); Assert.AreEqual(false, result); }
public void WhenRootNameChanged(ReferenceHandling referenceHandling) { var x = new WithComplexProperty { ComplexType = new ComplexType("a", 1) }; var y = new WithComplexProperty { ComplexType = new ComplexType("a", 1) }; var changes = new List <string>(); var expectedChanges = new List <string>(); using (var tracker = Track.IsDirty(x, y, referenceHandling)) { tracker.PropertyChanged += (_, e) => changes.Add(e.PropertyName); Assert.AreEqual(false, tracker.IsDirty); Assert.AreEqual(null, tracker.Diff); CollectionAssert.IsEmpty(changes); x.Name = "changed"; Assert.AreEqual(true, tracker.IsDirty); expectedChanges.AddRange(new[] { "Diff", "IsDirty" }); CollectionAssert.AreEqual(expectedChanges, changes); Assert.AreEqual("WithComplexProperty Name x: changed y: null", tracker.Diff.ToString(string.Empty, " ")); y.Name = x.Name; Assert.AreEqual(false, tracker.IsDirty); expectedChanges.AddRange(new[] { "Diff", "IsDirty" }); CollectionAssert.AreEqual(expectedChanges, changes); Assert.AreEqual(null, tracker.Diff); } }
public void WithComplexStructural(string xn, string yn, string expected) { expected = this is FieldValues.Classes ? expected.Replace("<member1>", "complexType") .Replace("<member2>", "name") : expected.Replace("<member1>", "ComplexType") .Replace("<member2>", "Name"); var x = new WithComplexProperty("a", 1) { ComplexType = new ComplexType { Name = xn, Value = 2 } }; var y = new WithComplexProperty("a", 1) { ComplexType = new ComplexType { Name = yn, Value = 2 } }; var result = this.DiffMethod(x, y, ReferenceHandling.Structural); Assert.AreEqual(expected, result.ToString(string.Empty, " ")); }
public void WithComplexReferenceWhenNotSame(ReferenceHandling referenceHandling, string expected) { expected = expected?.Replace( "<member>", this is FieldValues.Classes ? "complexType" : "ComplexType"); var x = new WithComplexProperty { Name = "a", Value = 1, ComplexType = new ComplexType { Name = "b", Value = 2 } }; var y = new WithComplexProperty { Name = "a", Value = 1, ComplexType = new ComplexType { Name = "b", Value = 2 } }; var result = this.DiffMethod(x, y, referenceHandling); Assert.AreEqual(expected == "Empty", result.IsEmpty); Assert.AreEqual(expected, result.ToString(string.Empty, " ")); }
public void WithComplexPropertyThrows() { var expected = "Synchronize.PropertyValues(x, y) failed.\r\n" + "The property WithComplexProperty.ComplexType of type ComplexType is not supported.\r\n" + "Solve the problem by any of:\r\n" + "* Make ComplexType immutable or use an immutable type.\r\n" + " - For immutable types the following must hold:\r\n" + " - Must be a sealed class or a struct.\r\n" + " - All fields and properties must be readonly.\r\n" + " - All field and property types must be immutable.\r\n" + " - All indexers must be readonly.\r\n" + " - Event fields are ignored.\r\n" + "* Use PropertiesSettings and specify how copying is performed:\r\n" + " - ReferenceHandling.Structural means that a the entire graph is traversed and immutable property values are copied.\r\n" + " - For structural Activator.CreateInstance is used to create instances so a parameterless constructor may be needed, can be private.\r\n" + " - ReferenceHandling.References means that references are copied.\r\n" + " - Exclude a combination of the following:\r\n" + " - The property WithComplexProperty.ComplexType.\r\n" + " - The type ComplexType.\r\n"; var source = new WithComplexProperty(); var target = new WithComplexProperty(); var exception = Assert.Throws<NotSupportedException>(() => Synchronize.PropertyValues(source, target, ReferenceHandling.Throw)); Assert.AreEqual(expected, exception.Message); Assert.DoesNotThrow(() => Synchronize.PropertyValues(source, target, ReferenceHandling.Structural)); Assert.DoesNotThrow(() => Synchronize.PropertyValues(source, target, ReferenceHandling.References)); }
public void HandlesPropertyChangedEmptyAndNull(string prop) { var source = new WithComplexProperty("a", 1) { ComplexType = new ComplexType("b", 2) }; var target = new WithComplexProperty("c", 3) { ComplexType = new ComplexType("d", 4) }; using (Synchronize.PropertyValues(source, target, ReferenceHandling.Structural)) { source.SetFields("e", 5, new ComplexType("f", 6)); source.OnPropertyChanged(prop); Assert.AreEqual("e", source.Name); Assert.AreEqual("e", target.Name); Assert.AreEqual(5, source.Value); Assert.AreEqual(5, target.Value); Assert.AreNotSame(source.ComplexType, target.ComplexType); Assert.AreEqual("f", source.ComplexType.Name); Assert.AreEqual("f", target.ComplexType.Name); Assert.AreEqual(6, source.ComplexType.Value); Assert.AreEqual(6, target.ComplexType.Value); } }
public void DoesNotLeakTrackedProperty() { var x = new WithComplexProperty { ComplexType = new ComplexType("a", 1) }; var y = new WithComplexProperty { ComplexType = new ComplexType("a", 1) }; using (var tracker = Track.IsDirty(x, y)) { Assert.AreEqual(false, tracker.IsDirty); var weakReference = new System.WeakReference(x.ComplexType); Assert.AreEqual(true, weakReference.IsAlive); x.ComplexType = null; System.GC.Collect(); Assert.AreEqual(false, weakReference.IsAlive); weakReference.Target = y.ComplexType; y.ComplexType = null; System.GC.Collect(); Assert.AreEqual(false, weakReference.IsAlive); } }
public void WithComplexProperty() { var x = new WithComplexProperty { ComplexType = new ComplexType("a", 1) }; var y = new WithComplexProperty { ComplexType = new ComplexType("a", 1) }; var changes = new List <string>(); var settings = PropertiesSettings.GetOrCreate(); using (var tracker = Track.IsDirty(x, y, settings)) { tracker.PropertyChanged += (_, e) => changes.Add(e.PropertyName); Assert.AreEqual(false, tracker.IsDirty); } x.ComplexType = new ComplexType("b", 2); CollectionAssert.IsEmpty(changes); var wrx = new System.WeakReference(x); var wrxc = new System.WeakReference(x.ComplexType); var wry = new System.WeakReference(y); var wryc = new System.WeakReference(y.ComplexType); x = null; y = null; System.GC.Collect(); Assert.AreEqual(false, wrx.IsAlive); Assert.AreEqual(false, wrxc.IsAlive); Assert.AreEqual(false, wry.IsAlive); Assert.AreEqual(false, wryc.IsAlive); }
public void IgnoresType(string xv, bool expected) { var x = new WithComplexProperty(xv, 1, new ComplexType("b", 2)); var y = new WithComplexProperty("a", 1, new ComplexType("c", 2)); var result = this.EqualMethod(x, y, ReferenceHandling.Structural, ignoredType: typeof(ComplexType)); Assert.AreEqual(expected, result); }
public void WithComplexStructuralHappyPathWhenTargetMemberIsNull() { var source = new WithComplexProperty { Name = "a", Value = 1 }; var target = new WithComplexProperty(); this.CopyMethod(source, target, ReferenceHandling.Structural); Assert.AreEqual(source.Name, target.Name); Assert.AreEqual(source.Value, target.Value); Assert.IsNull(source.ComplexType); Assert.IsNull(target.ComplexType); }
public void WithComplexReferenceHappyPathTargetMemberIsNull() { var source = new WithComplexProperty { Name = "a", Value = 1 }; var target = new WithComplexProperty { ComplexType = new ComplexType("b", 1) }; this.CopyMethod(source, target, ReferenceHandling.References); Assert.AreEqual(source.Name, target.Name); Assert.AreEqual(source.Value, target.Value); Assert.IsNull(source.ComplexType); Assert.IsNull(target.ComplexType); }
public void CreateAndDisposeStopsListeningToSubProperties() { var x = new WithComplexProperty { ComplexType = new ComplexType("a", 1) }; var y = new WithComplexProperty { ComplexType = new ComplexType("a", 1) }; var changes = new List<string>(); var settings = PropertiesSettings.GetOrCreate(); using (var tracker = Track.IsDirty(x, y, settings)) { tracker.PropertyChanged += (_, e) => changes.Add(e.PropertyName); Assert.AreEqual(false, tracker.IsDirty); Assert.AreEqual(null, tracker.Diff); } x.ComplexType.Value++; CollectionAssert.IsEmpty(changes); }
public void WithComplexReferenceHappyPath() { var source = new WithComplexProperty { Name = "a", Value = 1, ComplexType = new ComplexType { Name = "b", Value = 2 } }; var target = new WithComplexProperty(); this.CopyMethod(source, target, ReferenceHandling.References); Assert.AreEqual(source.Name, target.Name); Assert.AreEqual(source.Value, target.Value); Assert.AreSame(source.ComplexType, target.ComplexType); }
public void WithExplitImmutable() { var source = new WithComplexProperty { Name = "a", Value = 1, ComplexType = new ComplexType { Name = "b", Value = 2 } }; var target = new WithComplexProperty(); this.CopyMethod(source, target, ReferenceHandling.Structural, immutableType: typeof(ComplexType)); Assert.AreEqual(source.Name, target.Name); Assert.AreEqual(source.Value, target.Value); Assert.AreSame(source.ComplexType, target.ComplexType); }
public void CreateAndDisposeReference() { var source = new WithComplexProperty("a", 1) { ComplexType = new ComplexType("b", 2) }; var target = new WithComplexProperty("c", 3) { ComplexType = new ComplexType("d", 4) }; using (Synchronize.PropertyValues(source, target, ReferenceHandling.References)) { Assert.AreEqual("a", source.Name); Assert.AreEqual("a", target.Name); Assert.AreEqual(1, source.Value); Assert.AreEqual(1, target.Value); Assert.AreSame(source.ComplexType, target.ComplexType); source.Value++; Assert.AreEqual("a", source.Name); Assert.AreEqual("a", target.Name); Assert.AreEqual(2, source.Value); Assert.AreEqual(2, target.Value); Assert.AreSame(source.ComplexType, target.ComplexType); source.ComplexType = null; Assert.AreEqual("a", source.Name); Assert.AreEqual("a", target.Name); Assert.AreEqual(2, source.Value); Assert.AreEqual(2, target.Value); Assert.AreEqual(null, source.ComplexType); Assert.AreEqual(null, target.ComplexType); source.ComplexType = new ComplexType("c", 5); Assert.AreEqual("a", source.Name); Assert.AreEqual("a", target.Name); Assert.AreEqual(2, source.Value); Assert.AreEqual(2, target.Value); Assert.AreSame(source.ComplexType, target.ComplexType); } }
public void WithComplexStructuralWhenYIsNull() { var x = new WithComplexProperty { Name = "a", Value = 1 }; var y = new WithComplexProperty { Name = "a", Value = 1, ComplexType = new ComplexType("b", 1) }; this.EqualMethod(x, y, ReferenceHandling.Structural); var result = this.EqualMethod(x, y, ReferenceHandling.Structural); Assert.AreEqual(false, result); result = this.EqualMethod(x, y, ReferenceHandling.References); Assert.AreEqual(false, result); }
public void IgnoresType(string xv, string expected) { expected = expected?.Replace( "<member>", this is FieldValues.Classes ? "name" : "Name"); var x = new WithComplexProperty(xv, 1, new ComplexType("b", 2)); var y = new WithComplexProperty("a", 1, new ComplexType("c", 2)); var result = this.DiffMethod( x, y, ReferenceHandling.Structural, ignoredType: typeof(ComplexType)); Assert.AreEqual(expected, result.ToString(string.Empty, " ")); }
public void WithComplexReferenceWhenSame(ReferenceHandling referenceHandling) { var x = new WithComplexProperty { Name = "a", Value = 1, ComplexType = new ComplexType { Name = "b", Value = 2 } }; var y = new WithComplexProperty { Name = "a", Value = 1, ComplexType = x.ComplexType }; var result = this.DiffMethod(x, y, referenceHandling); Assert.AreEqual(true, result.IsEmpty); Assert.AreEqual("Empty", result.ToString()); }
public void WithComplexStructuralWhenNull() { var x = new WithComplexProperty { Name = "a", Value = 1 }; var y = new WithComplexProperty { Name = "a", Value = 1 }; this.DiffMethod(x, y, ReferenceHandling.Structural); var result = this.DiffMethod(x, y, ReferenceHandling.Structural); Assert.AreEqual(true, result.IsEmpty); Assert.AreEqual("Empty", result.ToString()); result = this.DiffMethod(x, y, ReferenceHandling.References); Assert.AreEqual(true, result.IsEmpty); Assert.AreEqual("Empty", result.ToString()); }
public void WithComplexStructural(string xn, string yn, bool expected) { var x = new WithComplexProperty("a", 1) { ComplexType = new ComplexType { Name = xn, Value = 2 } }; var y = new WithComplexProperty("a", 1) { ComplexType = new ComplexType { Name = yn, Value = 2 } }; var result = this.EqualMethod(x, y, ReferenceHandling.Structural); Assert.AreEqual(expected, result); }
public void HandlesNull(ReferenceHandling referenceHandling) { var x = new WithComplexProperty(); var y = new WithComplexProperty(); var changes = new List <string>(); var expectedChanges = new List <string>(); using (var tracker = Track.IsDirty(x, y, referenceHandling)) { tracker.PropertyChanged += (_, e) => changes.Add(e.PropertyName); Assert.AreEqual(false, tracker.IsDirty); Assert.AreEqual(null, tracker.Diff); CollectionAssert.IsEmpty(changes); x.ComplexType = new ComplexType("a", 1); Assert.AreEqual(true, tracker.IsDirty); expectedChanges.AddRange(new[] { "Diff", "IsDirty" }); CollectionAssert.AreEqual(expectedChanges, changes); var expected = "WithComplexProperty ComplexType x: Gu.State.Tests.DirtyTrackerTypes+ComplexType y: null"; var actual = tracker.Diff.ToString(string.Empty, " "); Assert.AreEqual(expected, actual); y.ComplexType = new ComplexType("a", 1); Assert.AreEqual(false, tracker.IsDirty); expectedChanges.AddRange(new[] { "Diff", "IsDirty" }); CollectionAssert.AreEqual(expectedChanges, changes); Assert.AreEqual(null, tracker.Diff); x.ComplexType = null; Assert.AreEqual(true, tracker.IsDirty); expectedChanges.AddRange(new[] { "Diff", "IsDirty" }); CollectionAssert.AreEqual(expectedChanges, changes); expected = "WithComplexProperty ComplexType x: null y: Gu.State.Tests.DirtyTrackerTypes+ComplexType"; actual = tracker.Diff.ToString(string.Empty, " "); Assert.AreEqual(expected, actual); y.ComplexType = null; Assert.AreEqual(false, tracker.IsDirty); expectedChanges.AddRange(new[] { "Diff", "IsDirty" }); CollectionAssert.AreEqual(expectedChanges, changes); Assert.AreEqual(null, tracker.Diff); } }
public void HandlesNull(ReferenceHandling referenceHandling) { var x = new WithComplexProperty(); var y = new WithComplexProperty(); var changes = new List<string>(); var expectedChanges = new List<string>(); using (var tracker = Track.IsDirty(x, y, referenceHandling)) { tracker.PropertyChanged += (_, e) => changes.Add(e.PropertyName); Assert.AreEqual(false, tracker.IsDirty); Assert.AreEqual(null, tracker.Diff); CollectionAssert.IsEmpty(changes); x.ComplexType = new ComplexType("a", 1); Assert.AreEqual(true, tracker.IsDirty); expectedChanges.AddRange(new[] { "Diff", "IsDirty" }); CollectionAssert.AreEqual(expectedChanges, changes); var expected = "WithComplexProperty ComplexType x: Gu.State.Tests.DirtyTrackerTypes+ComplexType y: null"; var actual = tracker.Diff.ToString("", " "); Assert.AreEqual(expected, actual); y.ComplexType = new ComplexType("a", 1); Assert.AreEqual(false, tracker.IsDirty); expectedChanges.AddRange(new[] { "Diff", "IsDirty" }); CollectionAssert.AreEqual(expectedChanges, changes); Assert.AreEqual(null, tracker.Diff); x.ComplexType = null; Assert.AreEqual(true, tracker.IsDirty); expectedChanges.AddRange(new[] { "Diff", "IsDirty" }); CollectionAssert.AreEqual(expectedChanges, changes); expected = "WithComplexProperty ComplexType x: null y: Gu.State.Tests.DirtyTrackerTypes+ComplexType"; actual = tracker.Diff.ToString("", " "); Assert.AreEqual(expected, actual); y.ComplexType = null; Assert.AreEqual(false, tracker.IsDirty); expectedChanges.AddRange(new[] { "Diff", "IsDirty" }); CollectionAssert.AreEqual(expectedChanges, changes); Assert.AreEqual(null, tracker.Diff); } }
public void HandlesMissingProperty() { var source = new WithComplexProperty("a", 1) { ComplexType = new ComplexType("b", 2) }; var target = new WithComplexProperty("c", 3) { ComplexType = new ComplexType("d", 4) }; using (Synchronize.PropertyValues(source, target, ReferenceHandling.Structural)) { #pragma warning disable INPC009 // Don't raise PropertyChanged for missing property. source.OnPropertyChanged("Missing"); #pragma warning restore INPC009 // Don't raise PropertyChanged for missing property. Assert.AreEqual("a", source.Name); Assert.AreEqual("a", target.Name); Assert.AreEqual(1, source.Value); Assert.AreEqual(1, target.Value); Assert.AreNotSame(source.ComplexType, target.ComplexType); Assert.AreEqual("b", source.ComplexType.Name); Assert.AreEqual("b", target.ComplexType.Name); Assert.AreEqual(2, source.ComplexType.Value); Assert.AreEqual(2, target.ComplexType.Value); source.Value = 5; source.ComplexType.Value = 6; Assert.AreEqual("a", source.Name); Assert.AreEqual("a", target.Name); Assert.AreEqual(5, source.Value); Assert.AreEqual(5, target.Value); Assert.AreNotSame(source.ComplexType, target.ComplexType); Assert.AreEqual("b", source.ComplexType.Name); Assert.AreEqual("b", target.ComplexType.Name); Assert.AreEqual(6, source.ComplexType.Value); Assert.AreEqual(6, target.ComplexType.Value); } }
public void CreateAndDisposeStopsListeningToSubProperties() { var x = new WithComplexProperty { ComplexType = new ComplexType("a", 1) }; var y = new WithComplexProperty { ComplexType = new ComplexType("a", 1) }; var changes = new List <string>(); var settings = PropertiesSettings.GetOrCreate(); using (var tracker = Track.IsDirty(x, y, settings)) { tracker.PropertyChanged += (_, e) => changes.Add(e.PropertyName); Assert.AreEqual(false, tracker.IsDirty); Assert.AreEqual(null, tracker.Diff); } x.ComplexType.Value++; CollectionAssert.IsEmpty(changes); }
public void WithComplexProperty() { var expected = "Track.IsDirty(x, y) failed.\r\n" + "The property WithComplexProperty.ComplexType of type ComplexType is not supported.\r\n" + "Solve the problem by any of:\r\n" + "* Implement IEquatable<WithComplexProperty> for WithComplexProperty or use a type that does.\r\n" + "* Implement IEquatable<ComplexType> for ComplexType or use a type that does.\r\n" + "* Use PropertiesSettings and specify how comparing is performed:\r\n" + " - ReferenceHandling.Structural means that a deep equals is performed.\r\n" + " - ReferenceHandling.References means that reference equality is used.\r\n" + " - Exclude a combination of the following:\r\n" + " - The property WithComplexProperty.ComplexType.\r\n" + " - The type ComplexType.\r\n"; var x = new WithComplexProperty(); var y = new WithComplexProperty(); var exception = Assert.Throws<NotSupportedException>(() => Track.IsDirty(x, y, ReferenceHandling.Throw)); Assert.AreEqual(expected, exception.Message); Assert.DoesNotThrow(() => Track.IsDirty(x, y, ReferenceHandling.Structural)); Assert.DoesNotThrow(() => Track.IsDirty(x, y, ReferenceHandling.References)); }
public void WithComplexStructuralWhenXIsNull() { var expected = this is FieldValues.Classes ? "WithComplexProperty complexType x: Gu.State.Tests.DiffTests.DiffTypes+ComplexType y: null" : "WithComplexProperty ComplexType x: Gu.State.Tests.DiffTests.DiffTypes+ComplexType y: null"; var x = new WithComplexProperty { Name = "a", Value = 1, ComplexType = new ComplexType("b", 1) }; var y = new WithComplexProperty { Name = "a", Value = 1 }; this.DiffMethod(x, y, ReferenceHandling.Structural); var result = this.DiffMethod(x, y, ReferenceHandling.Structural); Assert.AreEqual(false, result.IsEmpty); Assert.AreEqual(expected, result.ToString(string.Empty, " ")); result = this.DiffMethod(x, y, ReferenceHandling.References); Assert.AreEqual(false, result.IsEmpty); Assert.AreEqual(expected, result.ToString(string.Empty, " ")); }
public void HandlesMissingProperty() { var source = new WithComplexProperty("a", 1) { ComplexType = new ComplexType("b", 2) }; var target = new WithComplexProperty("c", 3) { ComplexType = new ComplexType("d", 4) }; using (Synchronize.PropertyValues(source, target, ReferenceHandling.Structural)) { source.OnPropertyChanged("Missing"); Assert.AreEqual("a", source.Name); Assert.AreEqual("a", target.Name); Assert.AreEqual(1, source.Value); Assert.AreEqual(1, target.Value); Assert.AreNotSame(source.ComplexType, target.ComplexType); Assert.AreEqual("b", source.ComplexType.Name); Assert.AreEqual("b", target.ComplexType.Name); Assert.AreEqual(2, source.ComplexType.Value); Assert.AreEqual(2, target.ComplexType.Value); source.Value = 5; source.ComplexType.Value = 6; Assert.AreEqual("a", source.Name); Assert.AreEqual("a", target.Name); Assert.AreEqual(5, source.Value); Assert.AreEqual(5, target.Value); Assert.AreNotSame(source.ComplexType, target.ComplexType); Assert.AreEqual("b", source.ComplexType.Name); Assert.AreEqual("b", target.ComplexType.Name); Assert.AreEqual(6, source.ComplexType.Value); Assert.AreEqual(6, target.ComplexType.Value); } }
public void WithComplexProperty() { var expected = "Track.IsDirty(x, y) failed.\r\n" + "The property WithComplexProperty.ComplexType of type ComplexType is not supported.\r\n" + "Solve the problem by any of:\r\n" + "* Implement IEquatable<WithComplexProperty> for WithComplexProperty or use a type that does.\r\n" + "* Implement IEquatable<ComplexType> for ComplexType or use a type that does.\r\n" + "* Use PropertiesSettings and specify how comparing is performed:\r\n" + " - ReferenceHandling.Structural means that a deep equals is performed.\r\n" + " - ReferenceHandling.References means that reference equality is used.\r\n" + " - Exclude a combination of the following:\r\n" + " - The property WithComplexProperty.ComplexType.\r\n" + " - The type ComplexType.\r\n"; var x = new WithComplexProperty(); var y = new WithComplexProperty(); var exception = Assert.Throws <NotSupportedException>(() => Track.IsDirty(x, y, ReferenceHandling.Throw)); Assert.AreEqual(expected, exception.Message); Assert.DoesNotThrow(() => Track.IsDirty(x, y, ReferenceHandling.Structural)); Assert.DoesNotThrow(() => Track.IsDirty(x, y, ReferenceHandling.References)); }
public void ComplexValueThrowsWithoutReferenceHandling() { var expected = this is FieldValues.Throws ? "EqualBy.FieldValues(x, y) failed.\r\n" + "The field WithComplexProperty.<ComplexType>k__BackingField of type ComplexType is not supported.\r\n" + "Solve the problem by any of:\r\n" + "* Implement IEquatable<WithComplexProperty> for WithComplexProperty or use a type that does.\r\n" + "* Implement IEquatable<ComplexType> for ComplexType or use a type that does.\r\n" + "* Use FieldsSettings and specify how comparing is performed:\r\n" + " - ReferenceHandling.Structural means that a deep equals is performed.\r\n" + " - ReferenceHandling.References means that reference equality is used.\r\n" + " - Exclude a combination of the following:\r\n" + " - The field WithComplexProperty.<ComplexType>k__BackingField.\r\n" + " - The type ComplexType.\r\n" : "EqualBy.PropertyValues(x, y) failed.\r\n" + "The property WithComplexProperty.ComplexType of type ComplexType is not supported.\r\n" + "Solve the problem by any of:\r\n" + "* Implement IEquatable<WithComplexProperty> for WithComplexProperty or use a type that does.\r\n" + "* Implement IEquatable<ComplexType> for ComplexType or use a type that does.\r\n" + "* Use PropertiesSettings and specify how comparing is performed:\r\n" + " - ReferenceHandling.Structural means that a deep equals is performed.\r\n" + " - ReferenceHandling.References means that reference equality is used.\r\n" + " - Exclude a combination of the following:\r\n" + " - The property WithComplexProperty.ComplexType.\r\n" + " - The type ComplexType.\r\n"; var x = new WithComplexProperty(); var y = new WithComplexProperty(); var exception = Assert.Throws <NotSupportedException>(() => this.EqualByMethod(x, y, ReferenceHandling.Throw)); Assert.AreEqual(expected, exception.Message); Assert.DoesNotThrow(() => this.EqualByMethod(new ComplexType(), new ComplexType())); Assert.DoesNotThrow(() => this.EqualByMethod(x, y)); Assert.DoesNotThrow(() => this.EqualByMethod(x, y, ReferenceHandling.Structural)); Assert.DoesNotThrow(() => this.EqualByMethod(x, y, ReferenceHandling.References)); }
public void WhenRootNameChanged(ReferenceHandling referenceHandling) { var x = new WithComplexProperty { ComplexType = new ComplexType("a", 1) }; var y = new WithComplexProperty { ComplexType = new ComplexType("a", 1) }; var changes = new List<string>(); var expectedChanges = new List<string>(); using (var tracker = Track.IsDirty(x, y, referenceHandling)) { tracker.PropertyChanged += (_, e) => changes.Add(e.PropertyName); Assert.AreEqual(false, tracker.IsDirty); Assert.AreEqual(null, tracker.Diff); CollectionAssert.IsEmpty(changes); x.Name = "changed"; Assert.AreEqual(true, tracker.IsDirty); expectedChanges.AddRange(new[] { "Diff", "IsDirty" }); CollectionAssert.AreEqual(expectedChanges, changes); Assert.AreEqual("WithComplexProperty Name x: changed y: null", tracker.Diff.ToString("", " ")); y.Name = x.Name; Assert.AreEqual(false, tracker.IsDirty); expectedChanges.AddRange(new[] { "Diff", "IsDirty" }); CollectionAssert.AreEqual(expectedChanges, changes); Assert.AreEqual(null, tracker.Diff); } }
public void Excludes() { var source = new WithComplexProperty("a", 1) { ComplexType = new ComplexType("b", 2) }; var target = new WithComplexProperty("c", 3) { ComplexType = new ComplexType("d", 4) }; var settings = PropertiesSettings.Build() .IgnoreProperty <WithComplexProperty>(nameof(WithComplexProperty.Name)) .CreateSettings(ReferenceHandling.Structural); using (Synchronize.PropertyValues(source, target, settings)) { Assert.AreEqual("a", source.Name); Assert.AreEqual("c", target.Name); Assert.AreEqual(1, source.Value); Assert.AreEqual(1, target.Value); Assert.AreNotSame(source.ComplexType, target.ComplexType); Assert.AreEqual("b", source.ComplexType.Name); Assert.AreEqual("b", target.ComplexType.Name); Assert.AreEqual(2, source.ComplexType.Value); Assert.AreEqual(2, target.ComplexType.Value); source.Value = 5; Assert.AreEqual("a", source.Name); Assert.AreEqual("c", target.Name); Assert.AreEqual(5, source.Value); Assert.AreEqual(5, target.Value); Assert.AreEqual("b", source.ComplexType.Name); Assert.AreEqual("b", target.ComplexType.Name); Assert.AreEqual(2, source.ComplexType.Value); Assert.AreEqual(2, target.ComplexType.Value); source.Name = "ignored"; Assert.AreEqual("ignored", source.Name); Assert.AreEqual("c", target.Name); Assert.AreEqual(5, source.Value); Assert.AreEqual(5, target.Value); Assert.AreEqual("b", source.ComplexType.Name); Assert.AreEqual("b", target.ComplexType.Name); Assert.AreEqual(2, source.ComplexType.Value); Assert.AreEqual(2, target.ComplexType.Value); source.ComplexType.Value = 6; Assert.AreEqual("ignored", source.Name); Assert.AreEqual("c", target.Name); Assert.AreEqual(5, source.Value); Assert.AreEqual(5, target.Value); Assert.AreNotSame(source.ComplexType, target.ComplexType); Assert.AreEqual("b", source.ComplexType.Name); Assert.AreEqual("b", target.ComplexType.Name); Assert.AreEqual(6, source.ComplexType.Value); Assert.AreEqual(6, target.ComplexType.Value); source.ComplexType = null; Assert.AreEqual("ignored", source.Name); Assert.AreEqual("c", target.Name); Assert.AreEqual(5, source.Value); Assert.AreEqual(5, target.Value); Assert.AreEqual(null, source.ComplexType); Assert.AreEqual(null, target.ComplexType); source.ComplexType = new ComplexType("f", 7); Assert.AreEqual("ignored", source.Name); Assert.AreEqual("c", target.Name); Assert.AreEqual(5, source.Value); Assert.AreEqual(5, target.Value); Assert.AreEqual("f", source.ComplexType.Name); Assert.AreEqual("f", target.ComplexType.Name); Assert.AreEqual(7, source.ComplexType.Value); Assert.AreEqual(7, target.ComplexType.Value); source.ComplexType.Value = 8; Assert.AreEqual("ignored", source.Name); Assert.AreEqual("c", target.Name); Assert.AreEqual(5, source.Value); Assert.AreEqual(5, target.Value); Assert.AreNotSame(source.ComplexType, target.ComplexType); Assert.AreEqual("f", source.ComplexType.Name); Assert.AreEqual("f", target.ComplexType.Name); Assert.AreEqual(8, source.ComplexType.Value); Assert.AreEqual(8, target.ComplexType.Value); } source.Value = 6; Assert.AreEqual("ignored", source.Name); Assert.AreEqual("c", target.Name); Assert.AreEqual(6, source.Value); Assert.AreEqual(5, target.Value); Assert.AreEqual("f", source.ComplexType.Name); Assert.AreEqual("f", target.ComplexType.Name); Assert.AreEqual(8, source.ComplexType.Value); Assert.AreEqual(8, target.ComplexType.Value); }
public void HappyPath() { var source = new WithComplexProperty("a", 1) { ComplexType = new ComplexType("b", 2) }; var target = new WithComplexProperty("c", 3) { ComplexType = new ComplexType("d", 4) }; using (Synchronize.PropertyValues(source, target, ReferenceHandling.Structural)) { Assert.AreEqual("a", source.Name); Assert.AreEqual("a", target.Name); Assert.AreEqual(1, source.Value); Assert.AreEqual(1, target.Value); Assert.AreNotSame(source.ComplexType, target.ComplexType); Assert.AreEqual("b", source.ComplexType.Name); Assert.AreEqual("b", target.ComplexType.Name); Assert.AreEqual(2, source.ComplexType.Value); Assert.AreEqual(2, target.ComplexType.Value); source.Value = 5; Assert.AreEqual("a", source.Name); Assert.AreEqual("a", target.Name); Assert.AreEqual(5, source.Value); Assert.AreEqual(5, target.Value); Assert.AreEqual("b", source.ComplexType.Name); Assert.AreEqual("b", target.ComplexType.Name); Assert.AreEqual(2, source.ComplexType.Value); Assert.AreEqual(2, target.ComplexType.Value); source.ComplexType.Value = 6; Assert.AreEqual("a", source.Name); Assert.AreEqual("a", target.Name); Assert.AreEqual(5, source.Value); Assert.AreEqual(5, target.Value); Assert.AreNotSame(source.ComplexType, target.ComplexType); Assert.AreEqual("b", source.ComplexType.Name); Assert.AreEqual("b", target.ComplexType.Name); Assert.AreEqual(6, source.ComplexType.Value); Assert.AreEqual(6, target.ComplexType.Value); source.ComplexType = null; Assert.AreEqual("a", source.Name); Assert.AreEqual("a", target.Name); Assert.AreEqual(5, source.Value); Assert.AreEqual(5, target.Value); Assert.AreEqual(null, source.ComplexType); Assert.AreEqual(null, target.ComplexType); source.ComplexType = new ComplexType("f", 7); Assert.AreEqual("a", source.Name); Assert.AreEqual("a", target.Name); Assert.AreEqual(5, source.Value); Assert.AreEqual(5, target.Value); Assert.AreEqual("f", source.ComplexType.Name); Assert.AreEqual("f", target.ComplexType.Name); Assert.AreEqual(7, source.ComplexType.Value); Assert.AreEqual(7, target.ComplexType.Value); source.ComplexType.Value = 8; Assert.AreEqual("a", source.Name); Assert.AreEqual("a", target.Name); Assert.AreEqual(5, source.Value); Assert.AreEqual(5, target.Value); Assert.AreNotSame(source.ComplexType, target.ComplexType); Assert.AreEqual("f", source.ComplexType.Name); Assert.AreEqual("f", target.ComplexType.Name); Assert.AreEqual(8, source.ComplexType.Value); Assert.AreEqual(8, target.ComplexType.Value); } source.Value = 6; Assert.AreEqual("a", source.Name); Assert.AreEqual("a", target.Name); Assert.AreEqual(6, source.Value); Assert.AreEqual(5, target.Value); Assert.AreEqual("f", source.ComplexType.Name); Assert.AreEqual("f", target.ComplexType.Name); Assert.AreEqual(8, source.ComplexType.Value); Assert.AreEqual(8, target.ComplexType.Value); }
public void TracksNested(ReferenceHandling referenceHandling) { var x = new WithComplexProperty(); var y = new WithComplexProperty(); var changes = new List<string>(); var expectedChanges = new List<string>(); using (var tracker = Track.IsDirty(x, y, referenceHandling)) { tracker.PropertyChanged += (_, e) => changes.Add(e.PropertyName); Assert.AreEqual(false, tracker.IsDirty); Assert.AreEqual(null, tracker.Diff); CollectionAssert.IsEmpty(changes); x.Name = "newName1"; Assert.AreEqual(true, tracker.IsDirty); expectedChanges.AddRange(new[] { "Diff", "IsDirty" }); CollectionAssert.AreEqual(expectedChanges, changes); Assert.AreEqual("WithComplexProperty Name x: newName1 y: null", tracker.Diff.ToString("", " ")); y.Name = "newName1"; Assert.AreEqual(false, tracker.IsDirty); expectedChanges.AddRange(new[] { "Diff", "IsDirty" }); CollectionAssert.AreEqual(expectedChanges, changes); Assert.AreEqual(null, tracker.Diff); x.ComplexType = new ComplexType("a", 1); Assert.AreEqual(true, tracker.IsDirty); expectedChanges.AddRange(new[] { "Diff", "IsDirty" }); CollectionAssert.AreEqual(expectedChanges, changes); Assert.AreEqual("WithComplexProperty ComplexType x: Gu.State.Tests.DirtyTrackerTypes+ComplexType y: null", tracker.Diff.ToString("", " ")); y.ComplexType = new ComplexType("a", 1); Assert.AreEqual(false, tracker.IsDirty); expectedChanges.AddRange(new[] { "Diff", "IsDirty" }); CollectionAssert.AreEqual(expectedChanges, changes); Assert.AreEqual(null, tracker.Diff); x.ComplexType.Name = "newName2"; Assert.AreEqual(true, tracker.IsDirty); expectedChanges.AddRange(new[] { "Diff", "IsDirty" }); CollectionAssert.AreEqual(expectedChanges, changes); Assert.AreEqual("WithComplexProperty ComplexType Name x: newName2 y: a", tracker.Diff.ToString("", " ")); x.ComplexType.Value++; Assert.AreEqual(true, tracker.IsDirty); expectedChanges.Add("Diff"); CollectionAssert.AreEqual(expectedChanges, changes); Assert.AreEqual("WithComplexProperty ComplexType Name x: newName2 y: a Value x: 2 y: 1", tracker.Diff.ToString("", " ")); y.ComplexType.Name = "newName2"; Assert.AreEqual(true, tracker.IsDirty); expectedChanges.Add("Diff"); CollectionAssert.AreEqual(expectedChanges, changes); Assert.AreEqual("WithComplexProperty ComplexType Value x: 2 y: 1", tracker.Diff.ToString("", " ")); y.ComplexType.Value++; Assert.AreEqual(false, tracker.IsDirty); expectedChanges.AddRange(new[] { "Diff", "IsDirty" }); CollectionAssert.AreEqual(expectedChanges, changes); Assert.AreEqual(null, tracker.Diff); } }
public void CreateAndDisposeStructural() { var source = new WithComplexProperty("a", 1) { ComplexType = new ComplexType("b", 2) }; var target = new WithComplexProperty("c", 3) { ComplexType = new ComplexType("d", 4) }; using (Synchronize.PropertyValues(source, target, ReferenceHandling.Structural)) { Assert.AreEqual("a", source.Name); Assert.AreEqual("a", target.Name); Assert.AreEqual(1, source.Value); Assert.AreEqual(1, target.Value); Assert.AreNotSame(source.ComplexType, target.ComplexType); Assert.AreEqual("b", source.ComplexType.Name); Assert.AreEqual("b", target.ComplexType.Name); Assert.AreEqual(2, source.ComplexType.Value); Assert.AreEqual(2, target.ComplexType.Value); source.Value++; Assert.AreEqual("a", source.Name); Assert.AreEqual("a", target.Name); Assert.AreEqual(2, source.Value); Assert.AreEqual(2, target.Value); Assert.AreNotSame(source.ComplexType, target.ComplexType); Assert.AreEqual("b", source.ComplexType.Name); Assert.AreEqual("b", target.ComplexType.Name); Assert.AreEqual(2, source.ComplexType.Value); Assert.AreEqual(2, target.ComplexType.Value); source.ComplexType.Value++; Assert.AreEqual("a", source.Name); Assert.AreEqual("a", target.Name); Assert.AreEqual(2, source.Value); Assert.AreEqual(2, target.Value); Assert.AreNotSame(source.ComplexType, target.ComplexType); Assert.AreEqual("b", source.ComplexType.Name); Assert.AreEqual("b", target.ComplexType.Name); Assert.AreEqual(3, source.ComplexType.Value); Assert.AreEqual(3, target.ComplexType.Value); var sourceComplexType = source.ComplexType; var targetComplexType = target.ComplexType; source.ComplexType = null; Assert.AreEqual("a", source.Name); Assert.AreEqual("a", target.Name); Assert.AreEqual(2, source.Value); Assert.AreEqual(2, target.Value); Assert.AreEqual(null, source.ComplexType); Assert.AreEqual(null, target.ComplexType); sourceComplexType.Value++; Assert.AreNotEqual(sourceComplexType.Value, targetComplexType.Value); source.ComplexType = new ComplexType("c", 5); Assert.AreEqual("a", source.Name); Assert.AreEqual("a", target.Name); Assert.AreEqual(2, source.Value); Assert.AreEqual(2, target.Value); Assert.AreNotSame(source.ComplexType, target.ComplexType); Assert.AreEqual("c", source.ComplexType.Name); Assert.AreEqual("c", target.ComplexType.Name); Assert.AreEqual(5, source.ComplexType.Value); Assert.AreEqual(5, target.ComplexType.Value); } source.Value++; Assert.AreEqual("a", source.Name); Assert.AreEqual("a", target.Name); Assert.AreEqual(3, source.Value); Assert.AreEqual(2, target.Value); Assert.AreNotSame(source.ComplexType, target.ComplexType); Assert.AreEqual("c", source.ComplexType.Name); Assert.AreEqual("c", target.ComplexType.Name); Assert.AreEqual(5, source.ComplexType.Value); Assert.AreEqual(5, target.ComplexType.Value); source.ComplexType.Value++; Assert.AreEqual("a", source.Name); Assert.AreEqual("a", target.Name); Assert.AreEqual(3, source.Value); Assert.AreEqual(2, target.Value); Assert.AreNotSame(source.ComplexType, target.ComplexType); Assert.AreEqual("c", source.ComplexType.Name); Assert.AreEqual("c", target.ComplexType.Name); Assert.AreEqual(6, source.ComplexType.Value); Assert.AreEqual(5, target.ComplexType.Value); }
public void Excludes() { var source = new WithComplexProperty("a", 1) { ComplexType = new ComplexType("b", 2) }; var target = new WithComplexProperty("c", 3) { ComplexType = new ComplexType("d", 4) }; var settings = PropertiesSettings.Build() .IgnoreProperty<WithComplexProperty>(nameof(WithComplexProperty.Name)) .CreateSettings(ReferenceHandling.Structural); using (Synchronize.PropertyValues(source, target, settings)) { Assert.AreEqual("a", source.Name); Assert.AreEqual("c", target.Name); Assert.AreEqual(1, source.Value); Assert.AreEqual(1, target.Value); Assert.AreNotSame(source.ComplexType, target.ComplexType); Assert.AreEqual("b", source.ComplexType.Name); Assert.AreEqual("b", target.ComplexType.Name); Assert.AreEqual(2, source.ComplexType.Value); Assert.AreEqual(2, target.ComplexType.Value); source.Value = 5; Assert.AreEqual("a", source.Name); Assert.AreEqual("c", target.Name); Assert.AreEqual(5, source.Value); Assert.AreEqual(5, target.Value); Assert.AreEqual("b", source.ComplexType.Name); Assert.AreEqual("b", target.ComplexType.Name); Assert.AreEqual(2, source.ComplexType.Value); Assert.AreEqual(2, target.ComplexType.Value); source.Name = "ignored"; Assert.AreEqual("ignored", source.Name); Assert.AreEqual("c", target.Name); Assert.AreEqual(5, source.Value); Assert.AreEqual(5, target.Value); Assert.AreEqual("b", source.ComplexType.Name); Assert.AreEqual("b", target.ComplexType.Name); Assert.AreEqual(2, source.ComplexType.Value); Assert.AreEqual(2, target.ComplexType.Value); source.ComplexType.Value = 6; Assert.AreEqual("ignored", source.Name); Assert.AreEqual("c", target.Name); Assert.AreEqual(5, source.Value); Assert.AreEqual(5, target.Value); Assert.AreNotSame(source.ComplexType, target.ComplexType); Assert.AreEqual("b", source.ComplexType.Name); Assert.AreEqual("b", target.ComplexType.Name); Assert.AreEqual(6, source.ComplexType.Value); Assert.AreEqual(6, target.ComplexType.Value); source.ComplexType = null; Assert.AreEqual("ignored", source.Name); Assert.AreEqual("c", target.Name); Assert.AreEqual(5, source.Value); Assert.AreEqual(5, target.Value); Assert.AreEqual(null, source.ComplexType); Assert.AreEqual(null, target.ComplexType); source.ComplexType = new ComplexType("f", 7); Assert.AreEqual("ignored", source.Name); Assert.AreEqual("c", target.Name); Assert.AreEqual(5, source.Value); Assert.AreEqual(5, target.Value); Assert.AreEqual("f", source.ComplexType.Name); Assert.AreEqual("f", target.ComplexType.Name); Assert.AreEqual(7, source.ComplexType.Value); Assert.AreEqual(7, target.ComplexType.Value); source.ComplexType.Value = 8; Assert.AreEqual("ignored", source.Name); Assert.AreEqual("c", target.Name); Assert.AreEqual(5, source.Value); Assert.AreEqual(5, target.Value); Assert.AreNotSame(source.ComplexType, target.ComplexType); Assert.AreEqual("f", source.ComplexType.Name); Assert.AreEqual("f", target.ComplexType.Name); Assert.AreEqual(8, source.ComplexType.Value); Assert.AreEqual(8, target.ComplexType.Value); } source.Value = 6; Assert.AreEqual("ignored", source.Name); Assert.AreEqual("c", target.Name); Assert.AreEqual(6, source.Value); Assert.AreEqual(5, target.Value); Assert.AreEqual("f", source.ComplexType.Name); Assert.AreEqual("f", target.ComplexType.Name); Assert.AreEqual(8, source.ComplexType.Value); Assert.AreEqual(8, target.ComplexType.Value); }
public void TracksNested(ReferenceHandling referenceHandling) { var x = new WithComplexProperty(); var y = new WithComplexProperty(); var changes = new List <string>(); var expectedChanges = new List <string>(); using (var tracker = Track.IsDirty(x, y, referenceHandling)) { tracker.PropertyChanged += (_, e) => changes.Add(e.PropertyName); Assert.AreEqual(false, tracker.IsDirty); Assert.AreEqual(null, tracker.Diff); CollectionAssert.IsEmpty(changes); x.Name = "newName1"; Assert.AreEqual(true, tracker.IsDirty); expectedChanges.AddRange(new[] { "Diff", "IsDirty" }); CollectionAssert.AreEqual(expectedChanges, changes); Assert.AreEqual("WithComplexProperty Name x: newName1 y: null", tracker.Diff.ToString(string.Empty, " ")); y.Name = "newName1"; Assert.AreEqual(false, tracker.IsDirty); expectedChanges.AddRange(new[] { "Diff", "IsDirty" }); CollectionAssert.AreEqual(expectedChanges, changes); Assert.AreEqual(null, tracker.Diff); x.ComplexType = new ComplexType("a", 1); Assert.AreEqual(true, tracker.IsDirty); expectedChanges.AddRange(new[] { "Diff", "IsDirty" }); CollectionAssert.AreEqual(expectedChanges, changes); Assert.AreEqual("WithComplexProperty ComplexType x: Gu.State.Tests.DirtyTrackerTypes+ComplexType y: null", tracker.Diff.ToString(string.Empty, " ")); y.ComplexType = new ComplexType("a", 1); Assert.AreEqual(false, tracker.IsDirty); expectedChanges.AddRange(new[] { "Diff", "IsDirty" }); CollectionAssert.AreEqual(expectedChanges, changes); Assert.AreEqual(null, tracker.Diff); x.ComplexType.Name = "newName2"; Assert.AreEqual(true, tracker.IsDirty); expectedChanges.AddRange(new[] { "Diff", "IsDirty" }); CollectionAssert.AreEqual(expectedChanges, changes); Assert.AreEqual("WithComplexProperty ComplexType Name x: newName2 y: a", tracker.Diff.ToString(string.Empty, " ")); x.ComplexType.Value++; Assert.AreEqual(true, tracker.IsDirty); expectedChanges.Add("Diff"); CollectionAssert.AreEqual(expectedChanges, changes); Assert.AreEqual("WithComplexProperty ComplexType Name x: newName2 y: a Value x: 2 y: 1", tracker.Diff.ToString(string.Empty, " ")); y.ComplexType.Name = "newName2"; Assert.AreEqual(true, tracker.IsDirty); expectedChanges.Add("Diff"); CollectionAssert.AreEqual(expectedChanges, changes); Assert.AreEqual("WithComplexProperty ComplexType Value x: 2 y: 1", tracker.Diff.ToString(string.Empty, " ")); y.ComplexType.Value++; Assert.AreEqual(false, tracker.IsDirty); expectedChanges.AddRange(new[] { "Diff", "IsDirty" }); CollectionAssert.AreEqual(expectedChanges, changes); Assert.AreEqual(null, tracker.Diff); } }