public void Existing_Parent_With_Added_Children_Should_Have_Children_Marked_As_Added()
        {
            // Arrange
            var database = new MockNorthwind();
            var order = database.Orders[0];
            var changeTracker = new ChangeTrackingCollection<Order>(order);
            var orderDetails = (IList<OrderDetail>)changeTracker[0].OrderDetails;
            var addedDetail1 = new OrderDetail
            {
                ProductId = 1,
                Product = database.Products[0],
                Quantity = 10,
                UnitPrice = 20M
            };
            var addedDetail2 = new OrderDetail
            {
                ProductId = 2,
                Product = database.Products[1],
                Quantity = 20,
                UnitPrice = 30M
            };

            // Act
            orderDetails.Add(addedDetail1);
            orderDetails.Add(addedDetail2);

            // Assert
            Assert.Equal(TrackingState.Added, addedDetail1.TrackingState);
            Assert.Equal(TrackingState.Added, addedDetail2.TrackingState);
        }
        public void Existing_Parent_With_Children_Should_Have_Children_Marked()
        {
            // Arrange
            var database = new MockNorthwind();
            var order = database.Orders[0];
            var changeTracker = new ChangeTrackingCollection<Order>(order);
            var orderDetails = (IList<OrderDetail>)changeTracker[0].OrderDetails;
            var addedDetail = new OrderDetail
                {
                    ProductId = 1,
                    Product = database.Products[0],
                    Quantity = 10,
                    UnitPrice = 20M
                };
            var modifiedDetail = orderDetails[0];
            var deletedDetail = orderDetails[1];
            addedDetail.Order = order;
            modifiedDetail.Order = order;
            deletedDetail.Order = order;

            // Act
            modifiedDetail.UnitPrice++;
            orderDetails.Remove(deletedDetail);
            orderDetails.Add(addedDetail);

            // Assert
            Assert.Equal(TrackingState.Added, addedDetail.TrackingState);
            Assert.Equal(TrackingState.Modified, modifiedDetail.TrackingState);
            Assert.Equal(TrackingState.Deleted, deletedDetail.TrackingState);
        }
        public void Items_Should_Be_Added_As_Unchanged_With_Array_Ctor()
        {
            // Arrange
            var database = new MockNorthwind();
            var product = database.Products[0];

            // Act
            var changeTracker = new ChangeTrackingCollection<Product>(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);
        }
        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 Added_Parent_With_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);

            // Assert
            Assert.Equal(TrackingState.Added, order.TrackingState);
            Assert.Equal(TrackingState.Added, orderDetails[0].TrackingState);
        }
        public void MergeChanges_Should_Set_ModifiedProperties_To_Null_For_Modified_Order_With_Updated_Customer()
        {
            // Arrange
            var database = new MockNorthwind();
            var origOrder = database.Orders[0];
            var changeTracker = new ChangeTrackingCollection<Order>(origOrder);
            origOrder.CustomerId = "ALFKI";
            var origModifiedProps = origOrder.ModifiedProperties;
            var updatedOrder = UpdateOrders(database, origOrder)[0];

            // Act
            changeTracker.MergeChanges(updatedOrder);

            // Assert
            Assert.Contains("CustomerId", origModifiedProps);
            Assert.Null(origOrder.ModifiedProperties);
        }
        public void MergeChanges_Should_Set_TrackingState_To_Unchanged_For_Modified_Order_With_Updated_Customer()
        {
            // Arrange
            var database = new MockNorthwind();
            var origOrder = database.Orders[0];
            var changeTracker = new ChangeTrackingCollection<Order>(origOrder);
            origOrder.CustomerId = "ALFKI";
            TrackingState origTrackingState = origOrder.TrackingState;
            var updatedOrder = UpdateOrders(database, origOrder)[0];

            // Act
            changeTracker.MergeChanges(updatedOrder);

            // Assert
            Assert.Equal(TrackingState.Modified, origTrackingState);
            Assert.Equal(TrackingState.Unchanged, origOrder.TrackingState);
        }
        public void MergeChanges_Should_Set_Properties_For_Modified_Order_With_Updated_Customer()
        {
            // Arrange
            var database = new MockNorthwind();
            var origOrder = database.Orders[0];
            var changeTracker = new ChangeTrackingCollection<Order>(origOrder);
            origOrder.CustomerId = "ALFKI";
            var updatedOrder = UpdateOrders(database, origOrder)[0];

            // Act
            changeTracker.MergeChanges(updatedOrder);

            // Assert
            Assert.AreEqual(updatedOrder.CustomerId, origOrder.CustomerId);
            Assert.AreEqual(updatedOrder.Customer.CustomerId, origOrder.Customer.CustomerId);
            Assert.AreEqual(updatedOrder.OrderDate, origOrder.OrderDate);
        }
        public void MergeChanges_Should_Set_ChangeTracker_For_Modified_Order_With_Updated_Customer()
        {
            // Arrange
            var database = new MockNorthwind();
            var origOrder = database.Orders[0];
            var changeTracker = new ChangeTrackingCollection<Order>(origOrder);
            origOrder.CustomerId = "ALFKI";
            var updatedOrder = UpdateOrders(database, origOrder)[0];

            // Act
            changeTracker.MergeChanges(updatedOrder);
            TrackingState origTrackingState = origOrder.Customer.TrackingState;
            origOrder.Customer.CustomerName = "xxx";

            // Assert
            Assert.AreEqual(TrackingState.Unchanged, origTrackingState);
            Assert.AreEqual(TrackingState.Modified, origOrder.Customer.TrackingState);
            Assert.Contains("CustomerName", (ICollection)origOrder.Customer.ModifiedProperties);
        }
        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 Removed_Items_Should_NOT_Disable_Change_Tracking_On_Related_Entities_OneToMany_ToOne()
        {
            // Arrange
            var database = new MockNorthwind();
            var order = database.Orders[0];
            var product = order.OrderDetails[0].Product;

            var changeTracker = new ChangeTrackingCollection<Order>(order);
            changeTracker.Remove(order);

            // Act
            product.ProductName = "XXX";

            // Assert
            Assert.AreEqual(TrackingState.Modified, product.TrackingState);
        }
        public void Removed_Items_Should_NOT_Disable_Change_Tracking_On_Related_Entities_OneToOne()
        {
            // Arrange
            var database = new MockNorthwind();
            var customer = database.Orders[0].Customer;
            var setting = customer.CustomerSetting = new CustomerSetting
            {
                CustomerId = customer.CustomerId,
                Customer = customer,
                Setting = "Setting1"
            };

            var changeTracker = new ChangeTrackingCollection<Customer>(customer);
            changeTracker.Remove(customer);

            // Act
            setting.Setting = "XXX";

            // Assert
            Assert.AreEqual(TrackingState.Modified, setting.TrackingState);
        }
        public void Removed_Items_Should_Disable_Change_Tracking_On_Entity()
        {
            // Arrange
            var database = new MockNorthwind();
            var order = database.Orders[0];

            var changeTracker = new ChangeTrackingCollection<Order>(order);
            changeTracker.Remove(order);
            order.TrackingState = TrackingState.Unchanged;

            // Act
            order.OrderDate = order.OrderDate.AddDays(1);

            // Assert
            Assert.AreEqual(TrackingState.Unchanged, order.TrackingState);
        }
        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 Removed_Existing_Modified_Items_Should_Be_Marked_As_Deleted()
        {
            // Arrange
            var database = new MockNorthwind();
            var changeTracker = new ChangeTrackingCollection<Product>(database.Products[0]);
            var product = changeTracker[0];
            product.UnitPrice++;

            // Act
            changeTracker.Remove(product);

            // Assert
            Assert.AreEqual(TrackingState.Deleted, product.TrackingState);
        }
        public void Removed_Existing_Modified_Items_Should_Not_Have_ModifiedProperties()
        {
            // Arrange
            var database = new MockNorthwind();
            var changeTracker = new ChangeTrackingCollection<Product>(database.Products[0]);
            var product = changeTracker[0];
            product.UnitPrice++;

            // Act
            changeTracker.Remove(product);

            // Assert
            Assert.IsTrue(product.ModifiedProperties == null
                || product.ModifiedProperties.Count == 0);
        }
        public void Modified_Existing_Items_Should_Add_ModifiedProperty()
        {
            // Arrange
            var database = new MockNorthwind();
            var changeTracker = new ChangeTrackingCollection<Product>(database.Products[0]);
            var product = changeTracker[0];

            // Act
            product.UnitPrice++;

            // Assert
            Assert.Contains("UnitPrice", (ICollection)product.ModifiedProperties);
        }
        public void Removed_Items_Should_Disable_Change_Tracking_On_Related_Entities_OneToMany()
        {
            // Arrange
            var database = new MockNorthwind();
            var order = database.Orders[0];
            var detail = order.OrderDetails[0];

            var changeTracker = new ChangeTrackingCollection<Order>(order);
            changeTracker.Remove(order);
            detail.TrackingState = TrackingState.Unchanged;

            // Act
            detail.Quantity++;

            // Assert
            Assert.AreEqual(TrackingState.Unchanged, detail.TrackingState);
        }
        public void Modified_Existing_Excluded_Items_Should_Not_Be_Marked_As_Modified()
        {
            // Arrange
            var database = new MockNorthwind();
            var changeTracker = new ChangeTrackingCollection<Product>(database.Products[0]);
            changeTracker.ExcludedProperties.Add("UnitPrice");
            var product = changeTracker[0];

            // Act
            product.UnitPrice++;

            // Assert
            Assert.AreEqual(TrackingState.Unchanged, product.TrackingState);
        }
        public void Removed_Items_Should_NOT_Disable_Change_Tracking_On_Related_Entities_ManyToOne()
        {
            // Arrange
            var database = new MockNorthwind();
            var order = database.Orders[0];
            var customer = order.Customer;

            var changeTracker = new ChangeTrackingCollection<Order>(order);
            changeTracker.Remove(order);

            // Act
            customer.CustomerName = "XXX";

            // Assert
            Assert.AreEqual(TrackingState.Modified, customer.TrackingState);
        }
        public void Modified_Existing_Excluded_Items_Should_Not_Add_ModifiedProperty()
        {
            // Arrange
            var database = new MockNorthwind();
            var changeTracker = new ChangeTrackingCollection<Product>(database.Products[0]);
            changeTracker.ExcludedProperties.Add("UnitPrice");
            var product = changeTracker[0];

            // Act
            product.UnitPrice++;

            // Assert
            Assert.IsTrue(product.ModifiedProperties == null
                || product.ModifiedProperties.Count == 0);
        }
        public void Removed_Items_Should_NOT_Disable_Change_Tracking_On_Related_Entities_ManyToMany()
        {
            // Arrange
            var database = new MockNorthwind();
            var employee = database.Employees[0];
            var territory = employee.Territories[0];

            var changeTracker = new ChangeTrackingCollection<Employee>(employee);
            changeTracker.Remove(employee);

            // Act
            territory.TerritoryDescription = "XXX";

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

            // Act
            product.UnitPrice++;
            product.Discontinued = true;
            product.ProductName = "xxxxxxxx";

            // Assert
            Assert.Contains("UnitPrice", (ICollection)product.ModifiedProperties);
            Assert.Contains("Discontinued", (ICollection)product.ModifiedProperties);
            Assert.Contains("ProductName", (ICollection)product.ModifiedProperties);
        }
        public void GetChanges_Should_Return_Deleted_Items()
        {
            // Arrange
            var database = new MockNorthwind();
            var product = database.Products[0];
            var changeTracker = new ChangeTrackingCollection<Product>(product);
            changeTracker.Remove(product);

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

            // Assert
            Assert.AreEqual(TrackingState.Deleted, changes.First().TrackingState);
        }
        public void Modified_Existing_Mixed_Items_Should_Not_Be_Marked_As_Modified()
        {
            // Arrange
            var database = new MockNorthwind();
            var changeTracker = new ChangeTrackingCollection<Product>(database.Products[0]);
            changeTracker.ExcludedProperties.Add("UnitPrice");
            var product = changeTracker[0];

            // Act
            product.UnitPrice++;
            product.ProductName = "xxxxxxxx";

            // Assert
            Assert.AreEqual(TrackingState.Modified, product.TrackingState);
            Assert.Contains("ProductName", (ICollection)product.ModifiedProperties);
            Assert.That(product.ModifiedProperties, Has.No.Member("UnitPrice"));
        }
        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 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);
        }
        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 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);
        }