public void WithIllegal() { var expected = // "Track.Changes(x, y) failed for item: ObservableCollection<ComplexType>[0].Illegal.\r\n" + "Track.Changes(x, y) failed.\r\n" + "The type IllegalType does not notify changes.\r\n" + "The property WithIllegal.Illegal of type IllegalType is not supported.\r\n" + "Solve the problem by any of:\r\n" + "* Implement INotifyPropertyChanged for IllegalType or use a type that does.\r\n" + "* Make IllegalType 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 change tracking is performed:\r\n" + " - ReferenceHandling.Structural means that a the entire graph is tracked.\r\n" + " - ReferenceHandling.References means that only the root level changes are tracked.\r\n" + " - Exclude a combination of the following:\r\n" + " - The property WithIllegal.Illegal.\r\n" + " - The type IllegalType.\r\n"; var item = new WithIllegal(); var settings = PropertiesSettings.GetOrCreate(); var exception = Assert.Throws <NotSupportedException>(() => Track.Changes(item, settings)); Assert.AreEqual(expected, exception.Message); exception = Assert.Throws <NotSupportedException>(() => Track.Changes(item)); Assert.AreEqual(expected, exception.Message); }
public void IsImmutable(Type type, bool expected) { var settings = PropertiesSettings.GetOrCreate(); var isImmutable = settings.IsImmutable(type); Assert.AreEqual(expected, isImmutable); }
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 CheckReferenceHandlingWhenRootError(bool requiresRef) { var settings = PropertiesSettings.GetOrCreate(ReferenceHandling.Throw); var type = typeof(List <ComplexType>); var errors = ErrorBuilder.Start() .CheckRequiresReferenceHandling(type, settings, _ => requiresRef) .Finnish(); if (requiresRef) { var error = RequiresReferenceHandling.Enumerable; var expected = new[] { error }; CollectionAssert.AreEqual(expected, errors.Errors); var stringBuilder = new StringBuilder(); var message = stringBuilder.AppendNotSupported(errors) .ToString(); var expectedMessage = ""; Assert.AreEqual(expectedMessage, message); stringBuilder = new StringBuilder(); message = stringBuilder.AppendSuggestExclude(errors) .ToString(); expectedMessage = ""; Assert.AreEqual(expectedMessage, message); } else { Assert.AreEqual(null, errors); } }
public void CheckIndexersWhenError() { var settings = PropertiesSettings.GetOrCreate(); var type = typeof(ErrorTypes.WithIndexer); var errors = ErrorBuilder.Start() .CheckIndexers(type, settings) .Finnish(); var indexer = type.GetProperties().Single(); var error = UnsupportedIndexer.GetOrCreate(indexer); var expected = new[] { error }; CollectionAssert.AreEqual(expected, errors.Errors); var stringBuilder = new StringBuilder(); var message = stringBuilder.AppendNotSupported(errors) .ToString(); var expectedMessage = "Indexers are not supported.\r\n" + " - The property WithIndexer.Item is an indexer and not supported.\r\n"; Assert.AreEqual(expectedMessage, message); stringBuilder = new StringBuilder(); message = stringBuilder.AppendSuggestExclude(errors) .ToString(); expectedMessage = " - Exclude a combination of the following:\r\n" + " - The indexer property WithIndexer.Item.\r\n"; Assert.AreEqual(expectedMessage, message); }
public void GetRecursive() { var x = new object(); var y = new object(); var settings = PropertiesSettings.GetOrCreate(); var rec = TrackerCache.GetOrAdd(x, y, settings, p => new Recursive(p, settings)); Assert.AreSame(rec, rec.Value.Next); }
public void CheckReferenceHandlingWhenValid(Type type) { var settings = PropertiesSettings.GetOrCreate(); var errors = ErrorBuilder.Start() .CheckRequiresReferenceHandling(type, settings, _ => false) .Finnish(); Assert.IsNull(errors); }
public void CheckNotifiesWhenValid(Type type) { var settings = PropertiesSettings.GetOrCreate(); var errors = ErrorBuilder.Start() .CheckNotifies(type, settings) .Finnish(); Assert.IsNull(errors); }
public void ReturnsDifferentForDifferentSettings() { var x = new ComplexType(); var y = new ComplexType(); var t1 = DiffBuilder.GetOrCreate(x, y, PropertiesSettings.GetOrCreate(ReferenceHandling.Structural)); var t2 = DiffBuilder.GetOrCreate(x, y, PropertiesSettings.GetOrCreate(ReferenceHandling.Throw)); Assert.AreNotSame(t1, t2); }
public void Equals(string xs, string ys, bool expected) { var x = xs.Split(',').Select(int.Parse); var y = ys.Split(',').Select(int.Parse); var comparer = EnumerableEqualByComparer <int> .Default; var settings = PropertiesSettings.GetOrCreate(); Assert.AreEqual(expected, comparer.Equals(x, y, settings, null)); }
public void Caches(BindingFlags bindingFlags, ReferenceHandling referenceHandling) { var settings = PropertiesSettings.GetOrCreate(referenceHandling, bindingFlags); Assert.AreEqual(bindingFlags, settings.BindingFlags); Assert.AreEqual(referenceHandling, settings.ReferenceHandling); var second = PropertiesSettings.GetOrCreate(referenceHandling, BindingFlags.Public); Assert.AreSame(settings, second); }
public void CheckReferenceHandlingWhenPropertyError() { var settings = PropertiesSettings.GetOrCreate(ReferenceHandling.Throw); var type = typeof(With <List <int> >); var errors = ErrorBuilder.Start() .CheckRequiresReferenceHandling(type, settings, _ => true) .Finnish(); var expected = new[] { RequiresReferenceHandling.ComplexType }; CollectionAssert.AreEqual(expected, errors.Errors); }
public void ReturnsDifferentForDifferentSettings() { var x = new WithSimpleProperties { Value = 1, Time = DateTime.MinValue }; var y = new WithSimpleProperties { Value = 1, Time = DateTime.MinValue }; var t1 = DirtyTrackerNode.GetOrCreate(x, y, PropertiesSettings.GetOrCreate(ReferenceHandling.Structural), true); var t2 = DirtyTrackerNode.GetOrCreate(x, y, PropertiesSettings.GetOrCreate(ReferenceHandling.References), true); Assert.AreNotSame(t1, t2); }
public void ReturnsDifferentForDifferentPairs() { var x = new ComplexType(); var y = new ComplexType(); var structuralSettings = PropertiesSettings.GetOrCreate(ReferenceHandling.Structural); using (var t1 = DiffBuilder.GetOrCreate(x, y, structuralSettings)) { using (var t2 = DiffBuilder.GetOrCreate(y, x, structuralSettings)) { Assert.AreNotSame(t1, t2); } } }
public void IgnoresCollectionProperties(Type type) { var settings = PropertiesSettings.GetOrCreate(); var propertyInfos = type.GetProperties(Constants.DefaultFieldBindingFlags); if (type != typeof(int[])) { CollectionAssert.IsNotEmpty(propertyInfos); } foreach (var propertyInfo in propertyInfos) { Assert.AreEqual(true, settings.IsIgnoringProperty(propertyInfo)); } }
public void ReturnsSameWhileAlive() { var x = new ComplexType(); var y = new ComplexType(); var structuralSettings = PropertiesSettings.GetOrCreate(ReferenceHandling.Structural); var t1 = DiffBuilder.GetOrCreate(x, y, structuralSettings); var t2 = DiffBuilder.GetOrCreate(x, y, structuralSettings); Assert.AreSame(t1, t2); t1.Dispose(); t2.Dispose(); var t4 = DiffBuilder.GetOrCreate(x, y, structuralSettings); Assert.AreNotSame(t1, t4); }
public void ReturnsDifferentForDifferentPairs() { var x = new WithSimpleProperties { Value = 1, Time = DateTime.MinValue }; var y = new WithSimpleProperties { Value = 1, Time = DateTime.MinValue }; var settings = PropertiesSettings.GetOrCreate(ReferenceHandling.Structural); using (var t1 = DirtyTrackerNode.GetOrCreate(x, y, settings, isRoot: true)) { using (var t2 = DirtyTrackerNode.GetOrCreate(y, x, settings, isRoot: true)) { Assert.AreNotSame(t1, t2); } } }
public void ReturnsSameWhileAlive() { var x = new WithSimpleProperties(); var y = new WithSimpleProperties(); var settings = PropertiesSettings.GetOrCreate(ReferenceHandling.Structural); var t1 = DirtyTrackerNode.GetOrCreate(x, y, settings, true); var t2 = DirtyTrackerNode.GetOrCreate(x, y, settings, true); Assert.AreSame(t1, t2); t1.Dispose(); var t3 = DirtyTrackerNode.GetOrCreate(x, y, settings, true); Assert.AreSame(t1, t3); t2.Dispose(); t3.Dispose(); var t4 = DirtyTrackerNode.GetOrCreate(x, y, settings, true); Assert.AreNotSame(t1, t4); }
public void GetOrAddUsingReferencePair() { var x = new object(); var y = new object(); var pair = ReferencePair.GetOrCreate(x, y); Assert.AreEqual(pair.Count, 1); var settings = PropertiesSettings.GetOrCreate(ReferenceHandling.Structural); using (var created = TrackerCache.GetOrAdd(x, y, settings, p => p)) { Assert.AreSame(pair, created.Value); Assert.AreEqual(pair.Count, 2); } Assert.AreEqual(1, pair.Count); pair.Dispose(); Assert.AreEqual(0, pair.Count); }
public void CheckNotifiesWithInt() { var settings = PropertiesSettings.GetOrCreate(); var type = typeof(ErrorTypes.With <int>); var errors = ErrorBuilder.Start().CheckNotifies(type, settings).Finnish(); var expected = new[] { TypeMustNotifyError.GetOrCreate(type) }; CollectionAssert.AreEqual(expected, errors.Errors); var stringBuilder = new StringBuilder(); var message = stringBuilder.AppendNotSupported(errors) .ToString(); var expectedMessage = "The type With<int> does not notify changes.\r\n"; Assert.AreEqual(expectedMessage, message); stringBuilder = new StringBuilder(); message = stringBuilder.AppendSuggestExclude(errors) .ToString(); expectedMessage = string.Empty; Assert.AreEqual(expectedMessage, message); }
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 CreateAndDisposeExplicitSetting(ReferenceHandling referenceHandling) { var x = new WithSimpleProperties { Value = 1, Time = DateTime.MinValue }; var y = new WithSimpleProperties { Value = 1, Time = DateTime.MinValue }; var propertyChanges = new List <string>(); var expectedChanges = new List <string>(); using (var tracker = Track.IsDirty(x, y, PropertiesSettings.GetOrCreate(referenceHandling))) { tracker.PropertyChanged += (_, e) => propertyChanges.Add(e.PropertyName); Assert.AreEqual(false, tracker.IsDirty); Assert.AreEqual(null, tracker.Diff); CollectionAssert.IsEmpty(propertyChanges); x.Value++; Assert.AreEqual(true, tracker.IsDirty); Assert.AreEqual("WithSimpleProperties Value x: 2 y: 1", tracker.Diff.ToString("", " ")); expectedChanges.AddRange(new[] { "Diff", "IsDirty" }); CollectionAssert.AreEqual(expectedChanges, propertyChanges); } x.Value++; CollectionAssert.AreEqual(expectedChanges, propertyChanges); #if (!DEBUG) // debug build keeps instances alive longer for nicer debugging experience var wrx = new System.WeakReference(x); var wry = new System.WeakReference(y); x = null; y = null; System.GC.Collect(); Assert.AreEqual(false, wrx.IsAlive); Assert.AreEqual(false, wry.IsAlive); #endif }
public void TracksNestedWithExplicitSetting() { 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, PropertiesSettings.GetOrCreate())) { 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); } }
public void WithListOfInts() { var expected = "Track.Changes(x, y) failed.\r\n" + "The collection type List<int> does not notify changes.\r\n" + "The property With<List<int>>.Value of type List<int> is not supported.\r\n" + "Solve the problem by any of:\r\n" + "* Use a type that implements INotifyCollectionChanged instead of List<int>.\r\n" + "* Use an immutable type instead of List<int>.\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 change tracking is performed:\r\n" + " - ReferenceHandling.Structural means that a the entire graph is tracked.\r\n" + " - ReferenceHandling.References means that only the root level changes are tracked.\r\n" + " - Exclude a combination of the following:\r\n" + " - The property With<List<int>>.Value.\r\n" + " - The type List<int>.\r\n"; var item = new With <List <int> >(); var exception = Assert.Throws <NotSupportedException>(() => Track.Changes(item)); Assert.AreEqual(expected, exception.Message); exception = Assert.Throws <NotSupportedException>(() => Track.Changes(item, PropertiesSettings.GetOrCreate())); Assert.AreEqual(expected, exception.Message); }
public void IllegalEnumerable() { var expected = "Track.Changes(x, y) failed.\r\n" + "The collection type IllegalEnumerable does not notify changes.\r\n" + "Solve the problem by any of:\r\n" + "* Implement INotifyCollectionChanged for IllegalEnumerable or use a type that does.\r\n" + "* Use PropertiesSettings and specify how change tracking is performed:\r\n" + " - ReferenceHandling.Structural means that a the entire graph is tracked.\r\n" + " - ReferenceHandling.References means that only the root level changes are tracked.\r\n"; var item = new IllegalEnumerable(); var exception = Assert.Throws <NotSupportedException>(() => Track.Changes(item)); Assert.AreEqual(expected, exception.Message); exception = Assert.Throws <NotSupportedException>(() => Track.Changes(item, PropertiesSettings.GetOrCreate())); Assert.AreEqual(expected, exception.Message); }
public void IgnoresNull() { var settings = PropertiesSettings.GetOrCreate(); Assert.AreEqual(true, settings.IsIgnoringProperty(null)); }
public void WithComplexProperty() { var expected = "Track.VerifyCanTrackIsDirty(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 exception = Assert.Throws <NotSupportedException>(() => Track.VerifyCanTrackIsDirty <WithComplexProperty>(ReferenceHandling.Throw)); Assert.AreEqual(expected, exception.Message); exception = Assert.Throws <NotSupportedException>(() => Track.VerifyCanTrackIsDirty(typeof(WithComplexProperty), PropertiesSettings.GetOrCreate(ReferenceHandling.Throw))); Assert.AreEqual(expected, exception.Message); Assert.DoesNotThrow(() => Track.VerifyCanTrackIsDirty <WithComplexProperty>(ReferenceHandling.Structural)); Assert.DoesNotThrow(() => Track.VerifyCanTrackIsDirty <WithComplexProperty>(ReferenceHandling.References)); }
public void WithSimpleProperties(ReferenceHandling referenceHandling) { Synchronize.VerifyCanSynchronize <WithSimpleProperties>(referenceHandling); Synchronize.VerifyCanSynchronize <WithSimpleProperties>(PropertiesSettings.GetOrCreate(referenceHandling)); Synchronize.VerifyCanSynchronize(typeof(WithSimpleProperties), PropertiesSettings.GetOrCreate(referenceHandling)); }
public void WithSimpleProperties(ReferenceHandling referenceHandling) { Track.VerifyCanTrackChanges <WithSimpleProperties>(referenceHandling); Track.VerifyCanTrackChanges <WithSimpleProperties>(PropertiesSettings.GetOrCreate(referenceHandling)); Track.VerifyCanTrackChanges(typeof(WithSimpleProperties), PropertiesSettings.GetOrCreate(referenceHandling)); }