public void ShouldTrackAddedItems()
        {
            Initialize();

            var listItemToAdd = new PocoListItemAdapter(new PocoListItem());

            var c = new ChangeTrackingCollection <PocoListItemAdapter>(_listItems);

            Assert.Equal(2, c.Count);
            Assert.False(c.IsChanged);

            c.Add(listItemToAdd);
            Assert.Equal(3, c.Count);
            Assert.Equal(1, c.AddedItems.Count);
            Assert.Equal(0, c.RemovedItems.Count);
            Assert.Equal(0, c.ModifiedItems.Count);
            Assert.Equal(listItemToAdd, c.AddedItems.First());
            Assert.True(c.IsChanged);

            c.Remove(listItemToAdd);
            Assert.Equal(2, c.Count);
            Assert.Equal(0, c.AddedItems.Count);
            Assert.Equal(0, c.RemovedItems.Count);
            Assert.Equal(0, c.ModifiedItems.Count);
            Assert.False(c.IsChanged);
        }
Пример #2
0
        public void Reset_HasChangesTrue_ResetsAllchanges()
        {
            var removeMe         = new TestItem();
            var expectedOldValue = "My old value";
            var expectedNewValue = "The new value";
            var expectedUpdate   = new TestItem
            {
                StringValue = expectedOldValue
            };
            var expectedItems = new List <TestItem>
            {
                removeMe,
                expectedUpdate
            };
            var subject = new ChangeTrackingCollection <TestItem>(expectedItems);

            expectedUpdate.StringValue = expectedNewValue;
            subject.Add(new TestItem());
            subject.Remove(removeMe);

            subject.Reset();

            Assert.False(subject.HasChanges);
            var changes = subject.GetChangeSet(ChangePath.Empty);

            Assert.Null(changes);
            Assert.False(expectedUpdate.HasChanges);
        }
Пример #3
0
        public void GetChangeSet_CommitTrue_MakesChangesPermanent()
        {
            var removeMe       = ChangeTrackingObject.CreateTrackable <TestItem>();
            var expectedUpdate = ChangeTrackingObject.CreateTrackable <TestItem>();
            var expectedItems  = new List <TestItem>
            {
                removeMe,
                expectedUpdate
            };
            var subject = new ChangeTrackingCollection <TestItem>(expectedItems);

            subject.Add(new TestItem());
            subject.Remove(removeMe);
            var expectedNewValue = "New Value";

            expectedUpdate.StringValue = expectedNewValue;

            var result = subject.GetChangeSet(ChangePath.Empty, commit: true);

            Assert.Equal(3, result.Count);
            Assert.False(subject.HasChanges);
            Assert.False(expectedUpdate.HasChanges);
            Assert.Equal(expectedNewValue, expectedUpdate.StringValue);
            Assert.DoesNotContain(removeMe, subject);
            Assert.Equal(2, subject.Count);
        }
        public void ShouldTrackRemovedItems()
        {
            var emailToRemove = _emails.First();
            var c             = new ChangeTrackingCollection <FriendEmailWrapper>(_emails);

            Assert.Equal(2, c.Count);
            Assert.False(c.IsChanged);

            c.Remove(emailToRemove);

            Assert.Equal(1, c.Count);
            Assert.Equal(0, c.AddedItems.Count);
            Assert.Equal(1, c.RemovedItems.Count);
            Assert.Equal(0, c.ModifiedItems.Count);
            Assert.Equal(emailToRemove, c.RemovedItems.First());
            Assert.True(c.IsChanged);

            c.Add(emailToRemove);

            Assert.Equal(2, c.Count);
            Assert.Equal(0, c.AddedItems.Count);
            Assert.Equal(0, c.RemovedItems.Count);
            Assert.Equal(0, c.ModifiedItems.Count);
            Assert.False(c.IsChanged);
        }
Пример #5
0
        public void HasChanges_TrueWhenAdd()
        {
            var subject = new ChangeTrackingCollection <TestItem>();

            subject.Add(ChangeTrackingObject.CreateTrackable <TestItem>());
            Assert.True(subject.HasChanges);
        }
        public void ShoudNotTrackRemovedItemAsModified()
        {
            var wordToAdd = new WordWrapper(new Word());
            var collection = new ChangeTrackingCollection<WordWrapper>(words);

            Assert.AreEqual(2, collection.Count);
            Assert.IsFalse(collection.IsChanged);

            collection.Add(wordToAdd);

            Assert.AreEqual(3, collection.Count);
            Assert.AreEqual(1, collection.AddedItems.Count);
            Assert.AreEqual(0, collection.RemovedItems.Count);
            Assert.AreEqual(0, collection.ModifiedItems.Count);
            Assert.AreEqual(wordToAdd, collection.AddedItems.First());
            Assert.IsTrue(collection.IsChanged);

            collection.Remove(wordToAdd);

            Assert.AreEqual(2, collection.Count);
            Assert.AreEqual(0, collection.AddedItems.Count);
            Assert.AreEqual(0, collection.RemovedItems.Count);
            Assert.AreEqual(0, collection.ModifiedItems.Count);
            Assert.IsFalse(collection.IsChanged);
        }
        public void Tracking_Should_Be_Disabled_With_Default_Ctor()
        {
            // Arrange
            var database = new MockNorthwind();
            var product = database.Products[0];
            var changeTracker = new ChangeTrackingCollection<Product>();

            // Act
            changeTracker.Add(product);

            // Assert
            Assert.AreEqual(TrackingState.Unchanged, changeTracker[0].TrackingState);
        }
        public void Tracking_Should_Be_Enabled_With_Array_Ctor()
        {
            // Arrange
            var database = new MockNorthwind();
            var product = database.Products[1];

            // Act
            var changeTracker = new ChangeTrackingCollection<Product>(database.Products[0]);
            changeTracker.Add(product);

            // Assert
            Assert.AreEqual(TrackingState.Added, changeTracker[1].TrackingState);
        }
Пример #9
0
        public void Added_Items_After_Tracking_Enabled_Should_Be_Marked_As_Added()
        {
            // Arrange
            var database      = new MockNorthwind();
            var product       = database.Products[0];
            var changeTracker = new ChangeTrackingCollection <Product>(true);

            // Act
            changeTracker.Add(product);

            // Assert
            Assert.Equal(TrackingState.Added, product.TrackingState);
        }
Пример #10
0
        public void Tracking_Should_Be_Disabled_With_Default_Ctor()
        {
            // Arrange
            var database      = new MockNorthwind();
            var product       = database.Products[0];
            var changeTracker = new ChangeTrackingCollection <Product>();

            // Act
            changeTracker.Add(product);

            // Assert
            Assert.Equal(TrackingState.Unchanged, changeTracker[0].TrackingState);
        }
        public void HasChanges_Added_Parent_Should_Return_True()
        {
            // Arrange
            var parent        = new Parent("Parent");
            var changeTracker = new ChangeTrackingCollection <Parent>(true);

            changeTracker.Add(parent);

            // Act
            bool hasChanges = parent.HasChanges();

            // Assert
            Assert.True(hasChanges);
        }
Пример #12
0
        public void Tracking_Should_Be_Enabled_With_Array_Ctor()
        {
            // Arrange
            var database = new MockNorthwind();
            var product  = database.Products[1];

            // Act
            var changeTracker = new ChangeTrackingCollection <Product>(database.Products[0]);

            changeTracker.Add(product);

            // Assert
            Assert.Equal(TrackingState.Added, changeTracker[1].TrackingState);
        }
        public void ShouldTrackAddedAsModified()
        {
            var emailToAdd = new EmailWrapper(new Email());

            var c = new ChangeTrackingCollection <EmailWrapper>(_emails);

            c.Add(emailToAdd);
            emailToAdd.EmailAddress = "*****@*****.**";
            Assert.IsTrue(emailToAdd.IsChanged);
            Assert.AreEqual(3, c.Count);
            Assert.AreEqual(1, c.AddedItems.Count);
            Assert.AreEqual(0, c.RemovedItems.Count);
            Assert.AreEqual(0, c.ModifiedItems.Count);
            Assert.IsTrue(c.IsChanged);
        }
Пример #14
0
        public void ShouldNotTrackAddedItemsAsModified()
        {
            var emailToAdd = new FriendEmailWrapper(new FriendEmail());

            var c = new ChangeTrackingCollection <FriendEmailWrapper>(_emails);

            c.Add(emailToAdd);
            emailToAdd.Email = "*****@*****.**";
            Assert.IsTrue(emailToAdd.IsChanged);
            Assert.AreEqual(3, c.Count);
            Assert.AreEqual(1, c.AddedItems.Count);
            Assert.AreEqual(0, c.RemovedItems.Count);
            Assert.AreEqual(0, c.ModifiedItems.Count);
            Assert.IsTrue(c.IsChanged);
        }
Пример #15
0
        public void GetChanges_Should_Return_Added_Items()
        {
            // Arrange
            var database      = new MockNorthwind();
            var changeTracker = new ChangeTrackingCollection <Product>(true);
            var product       = database.Products[0];

            changeTracker.Add(product);

            // Act
            var changes = changeTracker.GetChanges();

            // Assert
            Assert.Equal(TrackingState.Added, changes.First().TrackingState);
        }
Пример #16
0
        public void Should_Not_Track_Added_Item_As_Modified()
        {
            var listItemToAdd = new PocoListItemAdapter(new PocoListItem());

            var c = new ChangeTrackingCollection <PocoListItemAdapter>(_listItems);

            c.Add(listItemToAdd);
            listItemToAdd.Description = "modified entry";
            Assert.IsTrue(listItemToAdd.IsChanged);
            Assert.AreEqual(3, c.Count);
            Assert.AreEqual(1, c.AddedItems.Count);
            Assert.AreEqual(0, c.RemovedItems.Count);
            Assert.AreEqual(0, c.ModifiedItems.Count);
            Assert.IsTrue(c.IsChanged);
        }
Пример #17
0
        public void Added_Employee_After_Tracking_Enabled_Should_Not_Mark_Manually_Added_Territories_As_Unchanged()
        {
            // Arrange
            var database = new MockNorthwind();
            var employee = database.Employees[0];

            employee.Territories.ToList().ForEach(t => t.TrackingState = TrackingState.Added);
            var changeTracker = new ChangeTrackingCollection <Employee>(true);

            // Act
            changeTracker.Add(employee);

            // Assert
            Assert.Equal(TrackingState.Added, employee.TrackingState);
            Assert.True(employee.Territories.All(t => t.TrackingState == TrackingState.Added));
        }
        public void ShouldNotTrackAddedItemAsModified()
        {
            Initialize();
            var listItemToAdd = new PocoListItemAdapter(new PocoListItem());

            var c = new ChangeTrackingCollection <PocoListItemAdapter>(_listItems);

            c.Add(listItemToAdd);
            listItemToAdd.Description = "modified entry";
            Assert.True(listItemToAdd.IsChanged);
            Assert.Equal(3, c.Count);
            Assert.Equal(1, c.AddedItems.Count);
            Assert.Equal(0, c.RemovedItems.Count);
            Assert.Equal(0, c.ModifiedItems.Count);
            Assert.True(c.IsChanged);
        }
        public void Collection_Set_Tracking_Should_Enable_Tracking_For_Children()
        {
            // Arrange
            var parent        = _family.Parent;
            var changeTracker = new ChangeTrackingCollection <Parent>();

            changeTracker.Add(parent);

            // Act
            changeTracker.Tracking = true;

            // Assert
            Assert.IsTrue(changeTracker.Tracking);
            IEnumerable <bool> trackings = GetTrackings(parent);

            Assert.IsTrue(trackings.All(t => t));
        }
        public void Collection_Added_Set_State_As_Deleted_Should_Mark_Children_As_Unchanged()
        {
            // Arrange
            var parent        = _family.Parent;
            var changeTracker = new ChangeTrackingCollection <Parent>(true);

            changeTracker.Add(parent);

            // Act
            changeTracker.Remove(parent);

            // Assert
            Assert.AreEqual(TrackingState.Unchanged, parent.TrackingState);
            IEnumerable <TrackingState> trackings = GetStates(parent);

            Assert.IsTrue(trackings.All(t => t == TrackingState.Unchanged));
        }
Пример #21
0
        public void Add_ItemAlreadyRemovedGetsRestored()
        {
            var expectedItems = new List <TestItem>
            {
                new TestItem(),
                new TestItem(),
                new TestItem()
            };
            var subject = new ChangeTrackingCollection <TestItem>(expectedItems);

            subject.Remove(expectedItems[0]);
            Assert.True(subject.HasChanges);
            Assert.Equal(2, subject.Count);

            subject.Add(expectedItems[0]);
            Assert.False(subject.HasChanges);
            Assert.Contains(expectedItems[0], subject);
        }
Пример #22
0
        public void EntityChanged_Event_Should_Fire_When_Items_Added_Modified_Deleted()
        {
            // Arrange
            int changesCount = 0;

            var database       = new MockNorthwind();
            var addedProduct   = database.Products[0];
            var updatedProduct = database.Products[1];
            var deletedProduct = database.Products[2];
            var changeTracker  = new ChangeTrackingCollection <Product>(updatedProduct, deletedProduct);

            changeTracker.EntityChanged += (s, e) => changesCount++;

            // Act
            changeTracker.Add(addedProduct);
            updatedProduct.UnitPrice++;
            changeTracker.Remove(deletedProduct);

            // Assert
            Assert.Equal(3, changesCount);
        }
Пример #23
0
        public void GetChanges_Should_Return_Added_Modified_Deleted_Items()
        {
            // Arrange
            var database       = new MockNorthwind();
            var addedProduct   = database.Products[0];
            var updatedProduct = database.Products[1];
            var deletedProduct = database.Products[2];

            var changeTracker = new ChangeTrackingCollection <Product>(updatedProduct, deletedProduct);

            changeTracker.Add(addedProduct);
            updatedProduct.UnitPrice++;
            changeTracker.Remove(deletedProduct);

            // Act
            var changes = changeTracker.GetChanges();

            // Assert
            Assert.Equal(TrackingState.Added, changes.ElementAt(1).TrackingState);
            Assert.Equal(TrackingState.Modified, changes.ElementAt(0).TrackingState);
            Assert.Equal(TrackingState.Deleted, changes.ElementAt(2).TrackingState);
        }
        public void ShouldRejectChanges()
        {
            Initialize();
            var listItemToAdd = new PocoListItemAdapter(new PocoListItem {
                Id = 3, Title = "TestItem03", Description = "Description03"
            });
            var listItemToModify = _listItems.First();
            var listItemToRemove = _listItems.Skip(1).First();


            var c = new ChangeTrackingCollection <PocoListItemAdapter>(_listItems);

            c.Add(listItemToAdd);
            c.Remove(listItemToRemove);
            listItemToModify.Description = "modified item";
            Assert.Equal("Description01", listItemToModify.DescriptionOriginal);

            Assert.Equal(2, c.Count);
            Assert.Equal(1, c.AddedItems.Count);
            Assert.Equal(1, c.ModifiedItems.Count);
            Assert.Equal(1, c.RemovedItems.Count);

            c.RejectChanges();

            Assert.Equal(2, c.Count);
            Assert.True(c.Contains(listItemToModify));
            Assert.True(c.Contains(listItemToRemove));

            Assert.Equal(0, c.AddedItems.Count);
            Assert.Equal(0, c.ModifiedItems.Count);
            Assert.Equal(0, c.RemovedItems.Count);

            Assert.False(listItemToModify.IsChanged);
            Assert.Equal("Description01", listItemToModify.Description);
            Assert.Equal("Description01", listItemToModify.DescriptionOriginal);

            Assert.False(c.IsChanged);
        }
Пример #25
0
        public void Should_Track_Removed_Items()
        {
            var listItemToRemove = _listItems.First();
            var c = new ChangeTrackingCollection <PocoListItemAdapter>(_listItems);

            Assert.AreEqual(2, c.Count);
            Assert.IsFalse(c.IsChanged);

            c.Remove(listItemToRemove);
            Assert.AreEqual(1, c.Count);
            Assert.AreEqual(0, c.AddedItems.Count);
            Assert.AreEqual(1, c.RemovedItems.Count);
            Assert.AreEqual(0, c.ModifiedItems.Count);
            Assert.AreEqual(listItemToRemove, c.RemovedItems.First());
            Assert.IsTrue(c.IsChanged);

            c.Add(listItemToRemove);
            Assert.AreEqual(2, c.Count);
            Assert.AreEqual(0, c.AddedItems.Count);
            Assert.AreEqual(0, c.RemovedItems.Count);
            Assert.AreEqual(0, c.ModifiedItems.Count);
            Assert.IsFalse(c.IsChanged);
        }
Пример #26
0
        public void Removed_Added_Modified_Items_Should_Not_Have_ModifiedProperties()
        {
            // Arrange
            var database      = new MockNorthwind();
            var changeTracker = new ChangeTrackingCollection <Product>(true);
            var product       = new Product
            {
                ProductId   = 100,
                ProductName = "Test Beverage",
                CategoryId  = 1,
                Category    = database.Categories[0],
                UnitPrice   = 10M
            };

            // Act
            changeTracker.Add(product);
            product.UnitPrice++;
            changeTracker.Remove(product);

            // Assert
            Assert.True(product.ModifiedProperties == null ||
                        product.ModifiedProperties.Count == 0);
        }
Пример #27
0
        public void GetChangeSet_CommitFalse_ContainsAdds()
        {
            var subject      = new ChangeTrackingCollection <TestItem>();
            var expectedItem = new TestItem();

            subject.Add(expectedItem);
            var basePath     = ChangePath.Create("path");
            var result       = subject.GetChangeSet(basePath);
            var expectedPath = basePath.AppendIndex(0);

            Assert.True(subject.HasChanges);
            Assert.NotNull(result);
            var kvp = Assert.Single(result);

            Assert.Equal(ChangeTarget.Collection, kvp.Key.Target);
            Assert.Contains(expectedPath, result as IDictionary <ChangePath, List <ChangeValue> >);
            var values = result[expectedPath];
            var value  = Assert.Single(values);

            Assert.Equal(ChangeAction.Add, value.Action);
            Assert.Null(value.OldValue);
            Assert.Same(expectedItem, value.NewValue);
        }
Пример #28
0
        public void Modified_Added_Items_Should_Be_Marked_As_Added()
        {
            // Arrange
            var database      = new MockNorthwind();
            var changeTracker = new ChangeTrackingCollection <Product>();

            changeTracker.Tracking = true;
            var product = new Product
            {
                ProductId   = 100,
                ProductName = "Test Beverage",
                CategoryId  = 1,
                Category    = database.Categories[0],
                UnitPrice   = 10M
            };

            // Act
            changeTracker.Add(product);
            product.UnitPrice++;

            // Assert
            Assert.Equal(TrackingState.Added, product.TrackingState);
        }
        public void ShouldTrackModifiedItems()
        {
            var emailToRemove      = _emails.First();
            var trackingCollection = new ChangeTrackingCollection <EmailWrapper>(_emails);

            Assert.AreEqual(2, trackingCollection.Count);
            Assert.IsFalse(trackingCollection.IsChanged);

            trackingCollection.Remove(emailToRemove);
            Assert.AreEqual(1, trackingCollection.Count);
            Assert.AreEqual(0, trackingCollection.AddedItems.Count);
            Assert.AreEqual(1, trackingCollection.RemovedItems.Count);
            Assert.AreEqual(0, trackingCollection.ModifiedItems.Count);
            Assert.AreEqual(emailToRemove, trackingCollection.RemovedItems.First());
            Assert.IsTrue(trackingCollection.IsChanged);

            trackingCollection.Add(emailToRemove);
            Assert.AreEqual(2, trackingCollection.Count);
            Assert.AreEqual(0, trackingCollection.AddedItems.Count);
            Assert.AreEqual(0, trackingCollection.RemovedItems.Count);
            Assert.AreEqual(0, trackingCollection.ModifiedItems.Count);
            Assert.IsFalse(trackingCollection.IsChanged);
        }
Пример #30
0
        public void Added_Items_With_Enumerable_Ctor_Should_Be_Marked_As_Added()
        {
            // Arrange
            var database = new MockNorthwind();
            var products = new List <Product> {
                database.Products[0]
            };
            var changeTracker = new ChangeTrackingCollection <Product>(products);
            var product       = new Product
            {
                ProductId   = 100,
                ProductName = "Test Beverage",
                CategoryId  = 1,
                Category    = database.Categories[0],
                UnitPrice   = 10M
            };

            // Act
            changeTracker.Add(product);

            // Assert
            Assert.Equal(TrackingState.Added, product.TrackingState);
        }
Пример #31
0
        public void ShouldTrackAddedItems()
        {
            var emailToAdd = new FriendEmailWrapper(new FriendEmail());

            var c = new ChangeTrackingCollection <FriendEmailWrapper>(_emails);

            Assert.AreEqual(2, c.Count);
            Assert.IsFalse(c.IsChanged);

            c.Add(emailToAdd);
            Assert.AreEqual(3, c.Count);
            Assert.AreEqual(1, c.AddedItems.Count);
            Assert.AreEqual(0, c.RemovedItems.Count);
            Assert.AreEqual(0, c.ModifiedItems.Count);
            Assert.AreEqual(emailToAdd, c.AddedItems.First());
            Assert.IsTrue(c.IsChanged);

            c.Remove(emailToAdd);
            Assert.AreEqual(2, c.Count);
            Assert.AreEqual(0, c.AddedItems.Count);
            Assert.AreEqual(0, c.RemovedItems.Count);
            Assert.AreEqual(0, c.ModifiedItems.Count);
            Assert.IsFalse(c.IsChanged);
        }
Пример #32
0
        public void ShouldRejectChanges()
        {
            var emailToModify = _emails.First();
            var emailToRemove = _emails.Skip(1).First();
            var emailToAdd    = new FriendEmailWrapper(new FriendEmail {
                Email = "*****@*****.**"
            });

            var c = new ChangeTrackingCollection <FriendEmailWrapper>(_emails);

            c.Add(emailToAdd);
            c.Remove(emailToRemove);
            emailToModify.Email = "*****@*****.**";
            Assert.AreEqual("*****@*****.**", emailToModify.EmailOriginalValue);

            Assert.AreEqual(2, c.Count);
            Assert.AreEqual(1, c.AddedItems.Count);
            Assert.AreEqual(1, c.ModifiedItems.Count);
            Assert.AreEqual(1, c.RemovedItems.Count);

            c.RejectChanges();

            Assert.AreEqual(2, c.Count);
            Assert.IsTrue(c.Contains(emailToModify));
            Assert.IsTrue(c.Contains(emailToRemove));

            Assert.AreEqual(0, c.AddedItems.Count);
            Assert.AreEqual(0, c.ModifiedItems.Count);
            Assert.AreEqual(0, c.RemovedItems.Count);

            Assert.IsFalse(emailToModify.IsChanged);
            Assert.AreEqual("*****@*****.**", emailToModify.Email);
            Assert.AreEqual("*****@*****.**", emailToModify.EmailOriginalValue);

            Assert.IsFalse(c.IsChanged);
        }
        public void ShouldAcceptChanges()
        {
            var emailToModify = _emails.First();
            var emailToRemove = _emails.Skip(1).First();
            var emailToAdd    = new EmailWrapper(new Email {
                EmailAddress = "*****@*****.**"
            });

            var c = new ChangeTrackingCollection <EmailWrapper>(_emails);

            c.Add(emailToAdd);
            c.Remove(emailToRemove);
            emailToModify.EmailAddress = "*****@*****.**";
            Assert.AreEqual("*****@*****.**", emailToModify.EmailAddressOriginalValue);

            Assert.AreEqual(2, c.Count);
            Assert.AreEqual(1, c.AddedItems.Count);
            Assert.AreEqual(1, c.ModifiedItems.Count);
            Assert.AreEqual(1, c.RemovedItems.Count);

            c.AcceptChanges();

            Assert.AreEqual(2, c.Count);
            Assert.IsTrue(c.Contains(emailToModify));
            Assert.IsTrue(c.Contains(emailToAdd));

            Assert.AreEqual(0, c.AddedItems.Count);
            Assert.AreEqual(0, c.ModifiedItems.Count);
            Assert.AreEqual(0, c.RemovedItems.Count);

            Assert.IsFalse(emailToModify.IsChanged);
            Assert.AreEqual("*****@*****.**", emailToModify.EmailAddress);
            Assert.AreEqual("*****@*****.**", emailToModify.EmailAddressOriginalValue);

            Assert.IsFalse(c.IsChanged);
        }
        public void Added_Employee_Then_Removed_With_Territories_Should_Have_Territories_Marked_As_Unchanged()
        {
            // NOTE: Removing an added parent should mark parent and children as unchanged.
            // This is so that GetChanges will not include parent or children.

            // Arrange
            var database = new MockNorthwind();
            var changeTracker = new ChangeTrackingCollection<Employee>(true);
            var employee = database.Employees[0];
            var unchangedTerritory = employee.Territories[0];
            var modifiedTerritory = employee.Territories[1];
            var deletedTerritory = employee.Territories[2];
            var addedTerritory = database.Territories[3];
            changeTracker.Add(employee);

            // Act
            modifiedTerritory.TerritoryDescription = "xxx";
            employee.Territories.Add(addedTerritory); // stays added
            employee.Territories.Remove(deletedTerritory); // from added to unchanged
            changeTracker.Remove(employee);

            // Assert
            Assert.Equal(TrackingState.Unchanged, employee.TrackingState);
            Assert.Equal(TrackingState.Unchanged, unchangedTerritory.TrackingState);
            Assert.Equal(TrackingState.Unchanged, modifiedTerritory.TrackingState);
            Assert.Equal(TrackingState.Unchanged, addedTerritory.TrackingState);
            Assert.Equal(TrackingState.Unchanged, deletedTerritory.TrackingState);
        }
        public void Added_Order_With_Manually_Added_Customer_Should_Mark_Customer_As_Added()
        {
            // NOTE: Manually marking reference as added will create a new entity
            // when it is saved.

            // Arrange
            var database = new MockNorthwind();
            var order = database.Orders[0];
            var changeTracker = new ChangeTrackingCollection<Order>(true);
            changeTracker.Add(order);

            // Act
            order.Customer = new Customer
            {
                CustomerId = "ABCD",
                CustomerName = "Test",
                TrackingState = TrackingState.Added // required to insert new customer
            };

            // Assert
            Assert.Equal(TrackingState.Added, order.TrackingState);
            Assert.Equal(TrackingState.Added, order.Customer.TrackingState);
            Assert.True(order.HasChanges());
        }
        public void EntityChanged_Event_Should_Fire_When_Items_Added_Modified_Deleted()
        {
            // Arrange
            int changesCount = 0;

            var database = new MockNorthwind();
            var addedProduct = database.Products[0];
            var updatedProduct = database.Products[1];
            var deletedProduct = database.Products[2];
            var changeTracker = new ChangeTrackingCollection<Product>(updatedProduct, deletedProduct);
            changeTracker.EntityChanged += (s, e) => changesCount++;

            // Act
            changeTracker.Add(addedProduct);
            updatedProduct.UnitPrice++;
            changeTracker.Remove(deletedProduct);

            // Assert
            Assert.AreEqual(3, changesCount);
        }
        public void Added_Items_After_Tracking_Enabled_Should_Be_Marked_As_Added()
        {
            // Arrange
            var database = new MockNorthwind();
            var product = database.Products[0];
            var changeTracker = new ChangeTrackingCollection<Product>(true);

            // Act
            changeTracker.Add(product);

            // Assert
            Assert.AreEqual(TrackingState.Added, product.TrackingState);
        }
        public void GetChanges_Should_Return_Added_Items()
        {
            // Arrange
            var database = new MockNorthwind();
            var changeTracker = new ChangeTrackingCollection<Product>(true);
            var product = database.Products[0];
            changeTracker.Add(product);

            // Act
            var changes = changeTracker.GetChanges();

            // Assert
            Assert.AreEqual(TrackingState.Added, changes.First().TrackingState);
        }
        public void GetChanges_Should_Return_Added_Modified_Deleted_Items()
        {
            // Arrange
            var database = new MockNorthwind();
            var addedProduct = database.Products[0];
            var updatedProduct = database.Products[1];
            var deletedProduct = database.Products[2];

            var changeTracker = new ChangeTrackingCollection<Product>(updatedProduct, deletedProduct);
            
            changeTracker.Add(addedProduct);
            updatedProduct.UnitPrice++;
            changeTracker.Remove(deletedProduct);

            // Act
            var changes = changeTracker.GetChanges();

            // Assert
            Assert.AreEqual(TrackingState.Added, changes.ElementAt(1).TrackingState);
            Assert.AreEqual(TrackingState.Modified, changes.ElementAt(0).TrackingState);
            Assert.AreEqual(TrackingState.Deleted, changes.ElementAt(2).TrackingState);
        }
        public void HasChanges_Added_Parent_Should_Return_True()
        {
            // Arrange
            var parent = new Parent("Parent");
            var changeTracker = new ChangeTrackingCollection<Parent>(true);
            changeTracker.Add(parent);

            // Act
            bool hasChanges = parent.HasChanges();

            // Assert
            Assert.True(hasChanges);
        }
        public void Added_Items_With_Enumerable_Ctor_Should_Be_Marked_As_Added()
        {
            // Arrange
            var database = new MockNorthwind();
            var products = new List<Product> { database.Products[0] };
            var changeTracker = new ChangeTrackingCollection<Product>(products);
            var product = new Product
                {
                    ProductId = 100,
                    ProductName = "Test Beverage",
                    CategoryId = 1,
                    Category = database.Categories[0],
                    UnitPrice = 10M
                };

            // Act
            changeTracker.Add(product);

            // Assert
            Assert.AreEqual(TrackingState.Added, product.TrackingState);
        }
        public void Added_Parent_Then_Removed_Should_Have_Children_Marked_As_Unchanged()
        {
            // Arrange
            var database = new MockNorthwind();
            var changeTracker = new ChangeTrackingCollection<Order>(true);
            var order = database.Orders[0];
            var orderDetails = (IList<OrderDetail>)order.OrderDetails;
            var orderDetail = orderDetails[0];

            // Act
            changeTracker.Add(order);
            changeTracker.Remove(order);

            // Assert
            Assert.Equal(TrackingState.Unchanged, order.TrackingState);
            Assert.Equal(TrackingState.Unchanged, orderDetail.TrackingState);
        }
        public void Added_Order_With_Modified_Customer_Should_Mark_Customer_As_Modified()
        {
            // NOTE: Modified reference entity will remain modified if parent is added.

            // Arrange
            var database = new MockNorthwind();
            var order = database.Orders[0];
            var changeTracker = new ChangeTrackingCollection<Order>(true);
            changeTracker.Add(order);

            // Act
            order.Customer.CustomerName = "xxx";

            // Assert
            Assert.Equal(TrackingState.Added, order.TrackingState);
            Assert.Equal(TrackingState.Modified, order.Customer.TrackingState);
            Assert.True(order.HasChanges());
        }
        public void Added_Employee_After_Tracking_Enabled_Should_Not_Mark_Manually_Added_Territories_As_Unchanged()
        {
            // Arrange
            var database = new MockNorthwind();
            var employee = database.Employees[0];
            employee.Territories.ToList().ForEach(t => t.TrackingState = TrackingState.Added);
            var changeTracker = new ChangeTrackingCollection<Employee>(true);

            // Act
            changeTracker.Add(employee);

            // Assert
            Assert.AreEqual(TrackingState.Added, employee.TrackingState);
            Assert.IsTrue(employee.Territories.All(t => t.TrackingState == TrackingState.Added));
        }
        public void Added_Order_With_Removed_Customer_Should_Mark_Customer_As_Unchanged()
        {
            // NOTE: Removed customer will not be marked as deleted. Instead to be deleted
            // it must be independently marked as deleted.

            // Arrange
            var database = new MockNorthwind();
            var order = database.Orders[0];
            var changeTracker = new ChangeTrackingCollection<Order>(true);
            changeTracker.Add(order);
            var customer = order.Customer;

            // Act
            order.Customer = null;

            // Assert
            Assert.Equal(TrackingState.Added, order.TrackingState);
            Assert.Equal(TrackingState.Unchanged, customer.TrackingState);
            Assert.True(order.HasChanges());
        }
        /// <summary>
        /// Serialize the object into JSON.
        /// </summary>
        /// <param name="writer">JSON writer.</param>
        /// <param name="value">PropertyValue to be serialized.</param>
        /// <param name="serializer">JSON serializer.</param>
        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            if (value == null)
            {
                return;
            }

            ChangeTrackingCollection<GraphObject> graphObjects = value as ChangeTrackingCollection<GraphObject>;

            if (graphObjects == null)
            {
                if (!(value is IEnumerable))
                {
                    throw new ArgumentException("parameter 'value' is not of type IEnumerable.");
                }

                graphObjects = new ChangeTrackingCollection<GraphObject>();
                IEnumerable iEnumerableValue = value as IEnumerable;

                foreach (object valueObject in iEnumerableValue)
                {
                    GraphObject graphObject = valueObject as GraphObject;
                    if (graphObject == null)
                    {
                        throw new ArgumentException(
                            "Each value in the ChangeTrackingCollection should be of type GraphObject.");
                    }

                    graphObjects.Add(graphObject);
                }
            }

            if (graphObjects.Count > 0)
            {
                throw new ArgumentException("Updating links is not supported from entity.");
            }

            writer.WriteNull();
        }
        public void Removed_Added_Items_Should_Be_Marked_As_Unchanged()
        {
            // Arrange
            var database = new MockNorthwind();
            var changeTracker = new ChangeTrackingCollection<Product>();
            changeTracker.Tracking = true;
            var product = new Product
            {
                ProductId = 100,
                ProductName = "Test Beverage",
                CategoryId = 1,
                Category = database.Categories[0],
                UnitPrice = 10M
            };

            // Act
            changeTracker.Add(product);
            product.UnitPrice++;
            changeTracker.Remove(product);

            // Assert
            Assert.AreEqual(TrackingState.Unchanged, product.TrackingState);
        }
        /// <summary>
        /// Read JSON string to the object.
        /// </summary>
        /// <param name="reader">JSON reader.</param>
        /// <param name="objectType">Object type.</param>
        /// <param name="existingValue">Existing value.</param>
        /// <param name="serializer">Json serializer</param>
        /// <returns>Deserialized object.</returns>
        /// <remarks>
        /// 1. Check if this is an array or a single element.
        ///     If Array, deserialize each element as DirectoryObject and return the list
        /// 2. Deserialize using the default property set
        /// 3. Find the non-deserialized properties and add them to the Dictionary.
        /// </remarks>
        public override object ReadJson(
            JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            if (reader.TokenType == JsonToken.StartArray)
            {
                JToken jsonToken = JArray.ReadFrom(reader);
                List<JToken> jsonTokens = jsonToken.ToList();

                // This converter can only handle an array of graph objects.
                // Not native types. When deserializing an expanded link, all linked objects will be
                // deserialized as GraphObject.
                ChangeTrackingCollection<GraphObject> resultObjects = new ChangeTrackingCollection<GraphObject>();

                AadJsonConverter jsonConverter = new AadJsonConverter();
                foreach (JToken arrayToken in jsonTokens)
                {
                    GraphObject resultElement = JsonConvert.DeserializeObject(
                        arrayToken.ToString(), typeof(GraphObject), jsonConverter) as GraphObject;

                    resultObjects.Add(resultElement);
                }

                return resultObjects;
            }

            // Load the JSON into a JsonObject so that we can inspect the odata.type property.
            Object resultObject;
            JObject jsonObject = JObject.Load(reader);
 
            List<JProperty> jsonProperties = jsonObject.Properties().ToList();
            JProperty odataTypeProperty = 
                jsonProperties.FirstOrDefault(x => x.Name == Constants.OdataTypeKey);

            // If there is odata.type value, use that to find the type to be deserialized into.
            // If not, use the type that was passed to the de-serializer.
            Type resultObjectType;

            if (odataTypeProperty != null && 
                SerializationHelper.TryGetImplementationForAadType(
                    odataTypeProperty.Value.ToString(), out resultObjectType) &&
                typeof(GraphObject).IsAssignableFrom(resultObjectType))
            {
                resultObject = Activator.CreateInstance(resultObjectType) as GraphObject;
            }
            else
            {
                resultObjectType = objectType;
                resultObject = Activator.CreateInstance(resultObjectType);
            }

            // Deserialize all known properties using the default JSON.NET serializer
            resultObject = JsonConvert.DeserializeObject(jsonObject.ToString(), resultObjectType);

            // TODO: If the odata type is null, should still try to deserialize additional values using
            // the graphObjectType.
            GraphObject graphObject = resultObject as GraphObject;
            if (graphObject != null && odataTypeProperty != null)
            {
                Dictionary<string, PropertyInfo> propertyNameToInfoMap =
                    this.GetPropertyInfosForAadType(odataTypeProperty.Value.ToString(), resultObjectType);

                foreach (JProperty jsonProperty in jsonProperties)
                {
                    PropertyInfo propertyInfo;
                    if (!propertyNameToInfoMap.TryGetValue(jsonProperty.Name, out propertyInfo))
                    {
                        graphObject.NonSerializedProperties[jsonProperty.Name] = jsonProperty.Value.ToString();
                    }
                }
            }

            return graphObject;
        }
        public void Added_Order_With_New_Customer_Should_Mark_Customer_As_Unchanged()
        {
            // NOTE: Setting Order.Customer to a new customer will not automatically
            // mark it as Added, because Order has no way to tell if customer is new
            // or already exists.  However, Customer can be marked as Added manually.

            // Arrange
            var database = new MockNorthwind();
            var order = database.Orders[0];
            var changeTracker = new ChangeTrackingCollection<Order>(true);
            changeTracker.Add(order);

            // Act
            // Because not marked as added, refers to existing customer
            order.Customer = new Customer
            {
                CustomerId = "ABCD",
                CustomerName = "Test"
            };

            // Assert
            Assert.Equal(TrackingState.Added, order.TrackingState);
            Assert.Equal(TrackingState.Unchanged, order.Customer.TrackingState);
            Assert.True(order.HasChanges());
        }
        public void Removed_Added_Modified_Items_Should_Not_Have_ModifiedProperties()
        {
            // Arrange
            var database = new MockNorthwind();
            var changeTracker = new ChangeTrackingCollection<Product>(true);
            var product = new Product
            {
                ProductId = 100,
                ProductName = "Test Beverage",
                CategoryId = 1,
                Category = database.Categories[0],
                UnitPrice = 10M
            };

            // Act
            changeTracker.Add(product);
            product.UnitPrice++;
            changeTracker.Remove(product);

            // Assert
            Assert.IsTrue(product.ModifiedProperties == null
                || product.ModifiedProperties.Count == 0);
        }
        public void Added_Order_With_Unchanged_Customer_Should_Mark_Customer_As_Unchanged()
        {
            // NOTE: Referenced customer will remain unchanged because Order has no way to  
            // tell if customer is new or already exists. However, Customer can be marked 
            // as Added manually. (If it were 1-M or M-M, marking parent as added automatically
            // marks children as added.)

            // Arrange
            var database = new MockNorthwind();
            var order = database.Orders[0];
            var changeTracker = new ChangeTrackingCollection<Order>(true);
            changeTracker.Add(order);

            // Act

            // Assert
            Assert.Equal(TrackingState.Added, order.TrackingState);
            Assert.Equal(TrackingState.Unchanged, order.Customer.TrackingState);
            Assert.True(order.HasChanges());
        }
        public void Added_Parent_With_Modified_Children_Should_Have_Children_Marked_As_Added()
        {
            // Arrange
            var database = new MockNorthwind();
            var changeTracker = new ChangeTrackingCollection<Order>(true);
            var order = database.Orders[0];
            var orderDetails = (IList<OrderDetail>)order.OrderDetails;

            // Act
            changeTracker.Add(order);
            orderDetails[0].Quantity++;

            // Assert
            Assert.Equal(TrackingState.Added, order.TrackingState);
            Assert.Equal(TrackingState.Added, orderDetails[0].TrackingState);
        }