namespace BudgetApp.Tests.Domain; using BudgetApp.Domain.Models; using Xunit; public class LedgerTests { [Fact] public void Constructor_CreatesEmptyLedger() { // Arrange & Act var ledger = new Ledger(); // Assert Assert.Empty(ledger.Entries); } [Fact] public void AddEntry_WithValidEntry_AddsToLedger() { // Arrange var ledger = new Ledger(); var budgetAllocations = new Dictionary { { Guid.NewGuid(), new Money(100m, "USD") } }; var entry = new LedgerEntry( DateTime.Now, "Grocery Shopping", new Money(100m, "USD"), EntryType.Expense, budgetAllocations); // Act ledger.AddEntry(entry); // Assert Assert.Single(ledger.Entries); Assert.Equal(entry, ledger.Entries.First()); } [Fact] public void AddEntry_WithInvalidEntry_ThrowsException() { // Arrange var ledger = new Ledger(); var budgetAllocations = new Dictionary { { Guid.NewGuid(), new Money(50m, "USD") } }; // Act & Assert - The exception is thrown during construction, not when adding Assert.Throws(() => new LedgerEntry( Guid.NewGuid(), DateTime.Now, "Grocery Shopping", new Money(100m, "USD"), EntryType.Expense, budgetAllocations)); } [Fact] public void GetEntriesByType_ReturnsOnlyMatchingType() { // Arrange var ledger = new Ledger(); var expenseAllocations = new Dictionary { { Guid.NewGuid(), new Money(100m, "USD") } }; var incomeAllocations = new Dictionary { { Guid.NewGuid(), new Money(1000m, "USD") } }; var expense = new LedgerEntry(DateTime.Now, "Expense", new Money(100m, "USD"), EntryType.Expense, expenseAllocations); var income = new LedgerEntry(DateTime.Now, "Income", new Money(1000m, "USD"), EntryType.Income, incomeAllocations); ledger.AddEntry(expense); ledger.AddEntry(income); // Act var expenses = ledger.GetEntriesByType(EntryType.Expense); var incomes = ledger.GetEntriesByType(EntryType.Income); // Assert Assert.Single(expenses); Assert.Single(incomes); Assert.Equal(EntryType.Expense, expenses.First().Type); Assert.Equal(EntryType.Income, incomes.First().Type); } [Fact] public void CalculateTotalByType_ReturnsCorrectTotal() { // Arrange var ledger = new Ledger(); var expenseAllocations1 = new Dictionary { { Guid.NewGuid(), new Money(100m, "USD") } }; var expenseAllocations2 = new Dictionary { { Guid.NewGuid(), new Money(200m, "USD") } }; var expense1 = new LedgerEntry(DateTime.Now, "Expense 1", new Money(100m, "USD"), EntryType.Expense, expenseAllocations1); var expense2 = new LedgerEntry(DateTime.Now, "Expense 2", new Money(200m, "USD"), EntryType.Expense, expenseAllocations2); ledger.AddEntry(expense1); ledger.AddEntry(expense2); // Act var total = ledger.CalculateTotalByType(EntryType.Expense, "USD"); // Assert Assert.Equal(300m, total.Amount); } [Fact] public void CalculateNetBalance_ReturnsIncomeMinusExpenses() { // Arrange var ledger = new Ledger(); var expenseAllocations = new Dictionary { { Guid.NewGuid(), new Money(100m, "USD") } }; var incomeAllocations = new Dictionary { { Guid.NewGuid(), new Money(1000m, "USD") } }; var expense = new LedgerEntry(DateTime.Now, "Expense", new Money(100m, "USD"), EntryType.Expense, expenseAllocations); var income = new LedgerEntry(DateTime.Now, "Income", new Money(1000m, "USD"), EntryType.Income, incomeAllocations); ledger.AddEntry(expense); ledger.AddEntry(income); // Act var netBalance = ledger.CalculateNetBalance("USD"); // Assert Assert.Equal(900m, netBalance.Amount); } [Fact] public void GetEntriesForBudget_ReturnsEntriesWithBudgetAllocation() { // Arrange var budgetId = Guid.NewGuid(); var ledger = new Ledger(); var allocations1 = new Dictionary { { budgetId, new Money(100m, "USD") } }; var allocations2 = new Dictionary { { Guid.NewGuid(), new Money(200m, "USD") } }; var entry1 = new LedgerEntry(DateTime.Now, "Entry 1", new Money(100m, "USD"), EntryType.Expense, allocations1); var entry2 = new LedgerEntry(DateTime.Now, "Entry 2", new Money(200m, "USD"), EntryType.Expense, allocations2); ledger.AddEntry(entry1); ledger.AddEntry(entry2); // Act var entries = ledger.GetEntriesForBudget(budgetId); // Assert Assert.Single(entries); Assert.Equal(entry1, entries.First()); } }