namespace BudgetApp.Tests.Domain; using BudgetApp.Domain.Models; using Xunit; public class GoalBudgetTests { [Fact] public void Constructor_WithValidParameters_CreatesGoalBudget() { // Arrange & Act var targetDate = DateTime.Now.AddYears(3); var budget = new GoalBudget( "Car Purchase", new Money(0m, "USD"), new Money(30000m, "USD"), targetDate, new Money(1000m, "USD"), TimeSpan.FromDays(30)); // Assert Assert.Equal("Car Purchase", budget.Name); Assert.Equal(30000m, budget.GoalAmount.Amount); Assert.Equal(targetDate, budget.TargetDate); Assert.Equal(1000m, budget.PeriodicContribution.Amount); } [Fact] public void Constructor_WithPastTargetDate_ThrowsException() { // Arrange, Act & Assert var pastDate = DateTime.Now.AddDays(-1); Assert.Throws(() => new GoalBudget( "Test", new Money(0m, "USD"), new Money(10000m, "USD"), pastDate, new Money(1000m, "USD"), TimeSpan.FromDays(30))); } [Fact] public void Constructor_WithZeroGoalAmount_ThrowsException() { // Arrange, Act & Assert var targetDate = DateTime.Now.AddYears(1); Assert.Throws(() => new GoalBudget( "Test", new Money(0m, "USD"), new Money(0m, "USD"), targetDate, new Money(1000m, "USD"), TimeSpan.FromDays(30))); } [Fact] public void IsGoalAchievable_WithSufficientContributions_ReturnsTrue() { // Arrange var targetDate = DateTime.Now.AddYears(3); var budget = new GoalBudget( "Car Purchase", new Money(0m, "USD"), new Money(36000m, "USD"), targetDate, new Money(1000m, "USD"), TimeSpan.FromDays(30)); // Act var isAchievable = budget.IsGoalAchievable(DateTime.Now); // Assert Assert.True(isAchievable); } [Fact] public void IsGoalAchievable_WithInsufficientContributions_ReturnsFalse() { // Arrange var targetDate = DateTime.Now.AddMonths(1); var budget = new GoalBudget( "Car Purchase", new Money(0m, "USD"), new Money(100000m, "USD"), targetDate, new Money(1000m, "USD"), TimeSpan.FromDays(30)); // Act var isAchievable = budget.IsGoalAchievable(DateTime.Now); // Assert Assert.False(isAchievable); } [Fact] public void CalculateRequiredContributionRate_WithSufficientTime_ReturnsCorrectRate() { // Arrange var targetDate = DateTime.Now.AddYears(3); var budget = new GoalBudget( "Car Purchase", new Money(0m, "USD"), new Money(36000m, "USD"), targetDate, new Money(1000m, "USD"), TimeSpan.FromDays(30)); // Act var requiredRate = budget.CalculateRequiredContributionRate(DateTime.Now); // Assert Assert.True(requiredRate.Amount > 0); Assert.True(requiredRate.Amount <= 1000m); // Should be achievable } [Fact] public void CalculateRequiredContributionRate_WithCurrentBalanceAtGoal_ReturnsZero() { // Arrange var targetDate = DateTime.Now.AddYears(1); var budget = new GoalBudget( "Car Purchase", new Money(10000m, "USD"), new Money(10000m, "USD"), targetDate, new Money(1000m, "USD"), TimeSpan.FromDays(30)); // Act var requiredRate = budget.CalculateRequiredContributionRate(DateTime.Now); // Assert Assert.Equal(0m, requiredRate.Amount); } [Fact] public void IsGoalAchievable_WithBalanceExceedingGoal_ReturnsTrue() { // Arrange var targetDate = DateTime.Now.AddYears(1); var budget = new GoalBudget( "Car Purchase", new Money(15000m, "USD"), new Money(10000m, "USD"), targetDate, new Money(1000m, "USD"), TimeSpan.FromDays(30)); // Act var isAchievable = budget.IsGoalAchievable(DateTime.Now); // Assert Assert.True(isAchievable); } }