public void EditBudgetCategory_calls_EFCore_Update()
        {
            // Arrange
            var mockBudgetCategorySet = new Mock <DbSet <BudgetCategory> >();

            _mockContext.SetupGet(m => m.BudgetCategories).Returns(mockBudgetCategorySet.Object);
            var testBudgetCategory = new BudgetCategory();

            // Act
            _testRepo.EditBudgetCategory(testBudgetCategory);

            // Assert
            mockBudgetCategorySet.Verify(m => m.Update(testBudgetCategory), Times.Once());
        }
        public async Task <int> UpdateCategoryAsync(int id, double amount, DateTime effectiveFrom, BudgetType type)
        {
            BudgetCategory originalCategory = _context.GetCategories()
                                              .FirstOrDefault(c => c.ID == id) ?? throw new IdNotFoundException($"No BudgetCategory found for Id = {id}");

            try {
                if (effectiveFrom > originalCategory.EffectiveFrom)
                {
                    // Add new category
                    var categoryToAdd = new BudgetCategory {
                        Name          = originalCategory.Name,
                        EffectiveFrom = effectiveFrom,
                        Amount        = amount,
                        Type          = type
                    };
                    ValidateBudgetCategory(categoryToAdd, false);
                    _context.AddBudgetCategory(categoryToAdd);

                    // Reassign payees and transactions accordingly
                    ReassignPayeesByDate(originalCategory, categoryToAdd);
                    ReassingTransactionsByDate(originalCategory, categoryToAdd);
                }
                else
                {
                    if (effectiveFrom < originalCategory.EffectiveFrom)
                    {
                        // Check if there is an older category whose transactions/payees need to be split up
                        var categoryToStealFrom = _context.GetCategories()
                                                  .Where(c => c.Name == originalCategory.Name && c.EffectiveFrom < effectiveFrom)
                                                  .OrderByDescending(c => c.EffectiveFrom)
                                                  .FirstOrDefault();

                        // Update the originalCategory's date so payees/transactions will be properly reassigned
                        originalCategory.EffectiveFrom = effectiveFrom;

                        if (categoryToStealFrom != null)
                        {
                            ReassignPayeesByDate(categoryToStealFrom, originalCategory);
                            ReassingTransactionsByDate(categoryToStealFrom, originalCategory);
                        }

                        // Reassign payees/transactions from categories with newer EffectiveFrom dates and then delete the categories
                        foreach (BudgetCategory categoryToDelete in _context.GetCategories()
                                 .Where(c => c.Name == originalCategory.Name &&
                                        c.EffectiveFrom >= effectiveFrom &&
                                        c.ID != id))
                        {
                            ReassignPayeesByDate(categoryToDelete, originalCategory);
                            ReassingTransactionsByDate(categoryToDelete, originalCategory);
                            _context.DeleteBudgetCategory(categoryToDelete);
                        }
                    }

                    // Update the original category's values
                    originalCategory.EffectiveFrom = effectiveFrom;
                    originalCategory.Amount        = amount;
                    originalCategory.Type          = type;

                    ValidateBudgetCategory(originalCategory, false);
                    _context.EditBudgetCategory(originalCategory);
                }
                return(await _context.SaveChangesAsync());
            } catch (DbUpdateConcurrencyException) {
                throw new ConcurrencyException();
            }
        }