public void OtherPropertyChanged()
 {
     var propertyChanged = new MyNotifyPropertyChanged();
     Assert.PropertyChanged(propertyChanged, "Property1", () => propertyChanged.Property2 = 42);
 }
 public void ActualPropertyChanged()
 {
     var propertyChanged = new MyNotifyPropertyChanged();
     Assert.PropertyChanged(propertyChanged, "Property1", () => propertyChanged.Property1 = "NewValue");
 }
        public void ShouldNotifySubscribersAboutValueChangesWhileItemsAreInDictionary()
        {
            // given
            var scheduler = new TestScheduler();

            int key = 1;
            var testInpcImplementationInstance = new MyNotifyPropertyChanged<int, string>(key);

            var observer = scheduler.CreateObserver<IObservableDictionaryChange<int, MyNotifyPropertyChanged<int, string>>>();
            var itemChangesObserver = scheduler.CreateObserver<IObservableDictionaryChange<int, MyNotifyPropertyChanged<int, string>>>();
            var collectionItemChangesObserver = scheduler.CreateObserver<IObservableCollectionChange<KeyValuePair<int, MyNotifyPropertyChanged<int, string>>>>();

            using (var observableDictionary = new ObservableDictionary<int, MyNotifyPropertyChanged<int, string>>(scheduler: scheduler))
            {
                observableDictionary.ThresholdAmountWhenChangesAreNotifiedAsReset = int.MaxValue;

                IDisposable dictionaryChangesSubscription = null;
                IDisposable dictionaryItemChangesSubscription = null;
                IDisposable observableCollectionItemChangesSubscription = null;

                try
                {
                    dictionaryChangesSubscription = observableDictionary.DictionaryChanges.Subscribe(observer);
                    dictionaryItemChangesSubscription = observableDictionary.ValueChanges.Subscribe(itemChangesObserver);
                    observableCollectionItemChangesSubscription = ((INotifyObservableCollectionItemChanges<KeyValuePair<int, MyNotifyPropertyChanged<int, string>>>)observableDictionary)
                        .CollectionItemChanges
                        .Subscribe(collectionItemChangesObserver);

                    // when
                    observableDictionary.Add(key, testInpcImplementationInstance);

                    testInpcImplementationInstance.FirstProperty = Guid.NewGuid().ToString();
                    scheduler.AdvanceBy(100);

                    // then
                    observer.Messages.Count.Should().Be(2);
                    itemChangesObserver.Messages.Count.Should().Be(1);
                    collectionItemChangesObserver.Messages.Count.Should().Be(1);

                    observer.Messages.First().Value.Value.ChangeType.Should().Be(ObservableDictionaryChangeType.ItemAdded);
                    observer.Messages.First().Value.Value.Key.Should().Be(key);
                    observer.Messages.First().Value.Value.Value.Should().Be(testInpcImplementationInstance);

                    observer.Messages.Last().Value.Value.ChangeType.Should().Be(ObservableDictionaryChangeType.ItemValueChanged);
                    observer.Messages.Last().Value.Value.Key.Should().Be(default(int));
                    observer.Messages.Last().Value.Value.Value.Should().Be(testInpcImplementationInstance);
                    observer.Messages.Last().Value.Value.OldValue.Should().BeNull();
                    observer.Messages.Last().Value.Value.ChangedPropertyName.Should().Be(nameof(MyNotifyPropertyChanged<int, string>.FirstProperty));

                    itemChangesObserver.Messages.First().Value.Value.ChangeType.Should().Be(ObservableDictionaryChangeType.ItemValueChanged);
                    itemChangesObserver.Messages.First().Value.Value.Key.Should().Be(default(int));
                    itemChangesObserver.Messages.First().Value.Value.Value.Should().Be(testInpcImplementationInstance);
                    itemChangesObserver.Messages.First().Value.Value.OldValue.Should().BeNull();
                    itemChangesObserver.Messages.Last().Value.Value.ChangedPropertyName.Should().Be(nameof(MyNotifyPropertyChanged<int, string>.FirstProperty));

                    collectionItemChangesObserver.Messages.First().Value.Value.ChangeType.Should().Be(ObservableCollectionChangeType.ItemChanged);
                    collectionItemChangesObserver.Messages.First().Value.Value.Item.Key.Should().Be(key);
                    collectionItemChangesObserver.Messages.First().Value.Value.Item.Value.Should().Be(testInpcImplementationInstance);
                }
                finally
                {
                    dictionaryChangesSubscription?.Dispose();
                    dictionaryItemChangesSubscription?.Dispose();
                    observableCollectionItemChangesSubscription?.Dispose();
                }
            }
        }
        public void ShouldNotifySubscribersAboutKeyChangesAsResetIfRequestedWhileItemsAreInDictionary()
        {
            // given
            var scheduler = new TestScheduler();

            int value = 1;
            var key = new MyNotifyPropertyChanged<int, string>(value);

            var observer = scheduler.CreateObserver<IObservableDictionaryChange<MyNotifyPropertyChanged<int, string>, int>>();
            var itemChangesObserver = scheduler.CreateObserver<IObservableDictionaryChange<MyNotifyPropertyChanged<int, string>, int>>();
            var resetsObserver = scheduler.CreateObserver<Unit>();

            using (var observableDictionary = new ObservableDictionary<MyNotifyPropertyChanged<int, string>, int>(scheduler: scheduler))
            {
                observableDictionary.ThresholdAmountWhenChangesAreNotifiedAsReset = Int32.MaxValue;

                IDisposable dictionaryChangesSubscription = null;
                IDisposable dictionaryItemChangesSubscription = null;
                IDisposable dictionaryResetsSubscription = null;

                try
                {
                    dictionaryChangesSubscription = observableDictionary.DictionaryChanges.Subscribe(observer);
                    dictionaryItemChangesSubscription = observableDictionary.KeyChanges.Subscribe(itemChangesObserver);
                    dictionaryResetsSubscription = observableDictionary.Resets.Subscribe(resetsObserver);

                    // when
                    observableDictionary.Add(key, value);

                    observableDictionary.ThresholdAmountWhenChangesAreNotifiedAsReset = 0;
                    key.FirstProperty = Guid.NewGuid().ToString();
                    scheduler.AdvanceBy(100);

                    // then
                    observer.Messages.Count.Should().Be(2);
                    itemChangesObserver.Messages.Count.Should().Be(0);
                    resetsObserver.Messages.Count.Should().Be(1);

                    observer.Messages.First().Value.Value.ChangeType.Should().Be(ObservableDictionaryChangeType.ItemAdded);
                    observer.Messages.First().Value.Value.Key.Should().Be(key);
                    observer.Messages.First().Value.Value.Value.Should().Be(value);

                    observer.Messages.Last().Value.Value.ChangeType.Should().Be(ObservableDictionaryChangeType.Reset);
                    observer.Messages.Last().Value.Value.Key.Should().Be(default(MyNotifyPropertyChanged<int, string>));
                    observer.Messages.Last().Value.Value.Value.Should().Be(default(int));
                    observer.Messages.Last().Value.Value.OldValue.Should().Be(default(int));
                    observer.Messages.Last().Value.Value.ChangedPropertyName.Should().BeEmpty();
                }
                finally
                {
                    dictionaryChangesSubscription?.Dispose();
                    dictionaryItemChangesSubscription?.Dispose();
                    dictionaryResetsSubscription?.Dispose();
                }
            }
        }
        public void ShouldNotNotifySubscribersAboutValueChangesAfterItemsAreRemovedFromDictionary()
        {
            // given
            var scheduler = new TestScheduler();

            int key = 1;
            var testInpcImplementationInstance = new MyNotifyPropertyChanged<int, string>(key);

            var observer = scheduler.CreateObserver<IObservableDictionaryChange<int, MyNotifyPropertyChanged<int, string>>>();
            var itemChangesObserver = scheduler.CreateObserver<IObservableDictionaryChange<int, MyNotifyPropertyChanged<int, string>>>();

            using (var observableDictionary = new ObservableDictionary<int, MyNotifyPropertyChanged<int, string>>(scheduler: scheduler))
            {
                observableDictionary.ThresholdAmountWhenChangesAreNotifiedAsReset = int.MaxValue;

                IDisposable dictionaryChangesSubscription = null;
                IDisposable dictionaryItemChangesSubscription = null;

                try
                {
                    dictionaryChangesSubscription = observableDictionary.DictionaryChanges.Subscribe(observer);
                    dictionaryItemChangesSubscription = observableDictionary.ValueChanges.Subscribe(itemChangesObserver);

                    // when
                    observableDictionary.Add(key, testInpcImplementationInstance); // first general message - ItemAdd
                    testInpcImplementationInstance.FirstProperty = Guid.NewGuid().ToString(); // second general / first item change message - ItemChanged
                    observableDictionary.Remove(key); // third general message - ItemRemoved
                    testInpcImplementationInstance.SecondProperty = Guid.NewGuid().ToString(); // should no longer be observable on/via dictionary

                    scheduler.AdvanceBy(100);

                    // then
                    observer.Messages.Count.Should().Be(3);
                    observer.Messages[0].Value.Value.ChangeType.Should().Be(ObservableDictionaryChangeType.ItemAdded);
                    observer.Messages[0].Value.Value.Key.Should().Be(key);
                    observer.Messages[0].Value.Value.Value.Should().Be(testInpcImplementationInstance);

                    observer.Messages[1].Value.Value.ChangeType.Should().Be(ObservableDictionaryChangeType.ItemValueChanged);
                    observer.Messages[1].Value.Value.Key.Should().Be(default(int));
                    observer.Messages[1].Value.Value.Value.Should().Be(testInpcImplementationInstance);
                    observer.Messages[1].Value.Value.OldValue.Should().BeNull();
                    observer.Messages[1].Value.Value.ChangedPropertyName.Should().Be(nameof(MyNotifyPropertyChanged<int, string>.FirstProperty));

                    observer.Messages[2].Value.Value.ChangeType.Should().Be(ObservableDictionaryChangeType.ItemRemoved);
                    observer.Messages[2].Value.Value.Key.Should().Be(key);
                    observer.Messages[2].Value.Value.Value.Should().Be(testInpcImplementationInstance);

                    itemChangesObserver.Messages.Count.Should().Be(1);
                    itemChangesObserver.Messages.First().Value.Value.ChangeType.Should().Be(ObservableDictionaryChangeType.ItemValueChanged);
                    itemChangesObserver.Messages.First().Value.Value.Key.Should().Be(default(int));
                    itemChangesObserver.Messages.First().Value.Value.Value.Should().Be(testInpcImplementationInstance);
                    itemChangesObserver.Messages.First().Value.Value.OldValue.Should().BeNull();
                    itemChangesObserver.Messages.First().Value.Value.ChangedPropertyName.Should().Be(nameof(MyNotifyPropertyChanged<int, string>.FirstProperty));
                }
                finally
                {
                    dictionaryChangesSubscription?.Dispose();
                    dictionaryItemChangesSubscription?.Dispose();
                }
            }
        }