aboutsummaryrefslogtreecommitdiffstats
path: root/backend/internal/core/goal_service_test.go
blob: 2a4446a689afc16f34183a5e7b5837affd926ec1 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
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)
	*/
}