package core import ( "finance/backend/internal/models" "testing" "time" "github.com/stretchr/testify/assert" "gorm.io/gorm" ) // Mock goal for testing func createTestGoal() *models.Goal { return &models.Goal{ Model: gorm.Model{ID: 1, CreatedAt: time.Now().Add(-30 * 24 * time.Hour)}, // created 30 days ago UserID: 1, Name: "Test Goal", TargetAmount: 10000, CurrentAmount: 3000, Status: "Active", TargetDate: time.Now().Add(60 * 24 * time.Hour), // due in 60 days } } // TestCalculateGoalProgress tests the goal progress calculation logic func TestCalculateGoalProgress(t *testing.T) { // Create a test service service := &GoalService{} // Test with a goal that's on track goal := createTestGoal() progress, err := service.calculateGoalProgress(goal) assert.NoError(t, err) assert.NotNil(t, progress) // Verify calculations assert.Equal(t, int64(7000), progress.AmountRemaining) assert.InDelta(t, 30.0, progress.PercentComplete, 0.1) // Should have around 60 days remaining (might vary slightly based on test execution time) assert.True(t, progress.DaysRemaining > 55 && progress.DaysRemaining <= 61) // Test required amounts assert.True(t, progress.RequiredPerDay > 0) assert.True(t, progress.RequiredPerMonth > 0) // Verify on track status - goal is at 30% completion, we're 1/3 through the time period // so it should be on track assert.True(t, progress.OnTrack) // Test with a goal that's behind goal.CurrentAmount = 1000 // only 10% complete after 1/3 of the time progress, err = service.calculateGoalProgress(goal) assert.NoError(t, err) assert.NotNil(t, progress) assert.False(t, progress.OnTrack) // Test with a goal that has no target date goal = createTestGoal() goal.TargetDate = time.Time{} // zero time progress, err = service.calculateGoalProgress(goal) assert.NoError(t, err) assert.NotNil(t, progress) assert.True(t, progress.OnTrack) // should be on track if any progress made assert.Equal(t, 0, progress.DaysRemaining) // Test with a goal whose target date has passed goal = createTestGoal() goal.TargetDate = time.Now().Add(-10 * 24 * time.Hour) // 10 days ago progress, err = service.calculateGoalProgress(goal) assert.NoError(t, err) assert.NotNil(t, progress) assert.Equal(t, 0, progress.DaysRemaining) // Not on track if target amount not reached assert.False(t, progress.OnTrack) // But should be on track if target amount reached despite date passed goal.CurrentAmount = goal.TargetAmount progress, err = service.calculateGoalProgress(goal) assert.NoError(t, err) assert.True(t, progress.OnTrack) } // TestUpdateGoalFromTransactions tests updating a goal based on transactions func TestUpdateGoalFromTransactions(t *testing.T) { // This test would need a mock database to be fully implemented // Here's a placeholder for when DB mocking is available /* // Setup a mock DB db, mock := setupMockDB(t) service := &GoalService{db: db} // Setup expectations goalID := uint(1) userID := uint(1) // Expect a query to fetch the goal mock.ExpectQuery(`SELECT * FROM "goals" WHERE "id" = ?`). WithArgs(goalID). WillReturnRows(sqlmock.NewRows([]string{"id", "user_id", "name", "target_amount", "current_amount", "status"}). AddRow(goalID, userID, "Test Goal", 10000, 0, "Active")) // Expect a query to fetch transactions mock.ExpectQuery(`SELECT * FROM "transactions" WHERE "user_id" = ? AND "category" = ?`). WithArgs(userID, "Goal:1"). WillReturnRows(sqlmock.NewRows([]string{"id", "user_id", "amount", "type", "category"}). AddRow(1, userID, 500, "Income", "Goal:1"). AddRow(2, userID, 300, "Income", "Goal:1"). AddRow(3, userID, 200, "Expense", "Goal:1")) // Expect an update to the goal mock.ExpectBegin() mock.ExpectExec(`UPDATE "goals" SET`). WithArgs(600, "Active", goalID). // 500 + 300 - 200 = 600 WillReturnResult(sqlmock.NewResult(1, 1)) mock.ExpectCommit() // Run the test err := service.UpdateGoalFromTransactions(goalID) assert.NoError(t, err) */ }