feat: tests

This commit is contained in:
juancwu 2026-02-14 10:53:57 -05:00
commit 1346abf733
No known key found for this signature in database
32 changed files with 3772 additions and 11 deletions

View file

@ -0,0 +1,245 @@
package repository
import (
"testing"
"time"
"git.juancwu.dev/juancwu/budgit/internal/model"
"git.juancwu.dev/juancwu/budgit/internal/testutil"
"github.com/google/uuid"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestExpenseRepository_Create(t *testing.T) {
testutil.ForEachDB(t, func(t *testing.T, dbi testutil.DBInfo) {
repo := NewExpenseRepository(dbi.DB)
user := testutil.CreateTestUser(t, dbi.DB, "test@example.com", nil)
space := testutil.CreateTestSpace(t, dbi.DB, user.ID, "Test Space")
tag := testutil.CreateTestTag(t, dbi.DB, space.ID, "Food", nil)
now := time.Now()
expense := &model.Expense{
ID: uuid.NewString(),
SpaceID: space.ID,
CreatedBy: user.ID,
Description: "Lunch",
AmountCents: 1500,
Type: model.ExpenseTypeExpense,
Date: now,
CreatedAt: now,
UpdatedAt: now,
}
err := repo.Create(expense, []string{tag.ID}, nil)
require.NoError(t, err)
fetched, err := repo.GetByID(expense.ID)
require.NoError(t, err)
assert.Equal(t, expense.ID, fetched.ID)
assert.Equal(t, "Lunch", fetched.Description)
assert.Equal(t, 1500, fetched.AmountCents)
assert.Equal(t, model.ExpenseTypeExpense, fetched.Type)
})
}
func TestExpenseRepository_GetBySpaceIDPaginated(t *testing.T) {
testutil.ForEachDB(t, func(t *testing.T, dbi testutil.DBInfo) {
repo := NewExpenseRepository(dbi.DB)
user := testutil.CreateTestUser(t, dbi.DB, "test@example.com", nil)
space := testutil.CreateTestSpace(t, dbi.DB, user.ID, "Test Space")
testutil.CreateTestExpense(t, dbi.DB, space.ID, user.ID, "Expense 1", 1000, model.ExpenseTypeExpense)
testutil.CreateTestExpense(t, dbi.DB, space.ID, user.ID, "Expense 2", 2000, model.ExpenseTypeExpense)
testutil.CreateTestExpense(t, dbi.DB, space.ID, user.ID, "Expense 3", 3000, model.ExpenseTypeExpense)
expenses, err := repo.GetBySpaceIDPaginated(space.ID, 2, 0)
require.NoError(t, err)
assert.Len(t, expenses, 2)
})
}
func TestExpenseRepository_CountBySpaceID(t *testing.T) {
testutil.ForEachDB(t, func(t *testing.T, dbi testutil.DBInfo) {
repo := NewExpenseRepository(dbi.DB)
user := testutil.CreateTestUser(t, dbi.DB, "test@example.com", nil)
space := testutil.CreateTestSpace(t, dbi.DB, user.ID, "Test Space")
testutil.CreateTestExpense(t, dbi.DB, space.ID, user.ID, "Expense 1", 1000, model.ExpenseTypeExpense)
testutil.CreateTestExpense(t, dbi.DB, space.ID, user.ID, "Expense 2", 2000, model.ExpenseTypeExpense)
count, err := repo.CountBySpaceID(space.ID)
require.NoError(t, err)
assert.Equal(t, 2, count)
})
}
func TestExpenseRepository_GetTagsByExpenseIDs(t *testing.T) {
testutil.ForEachDB(t, func(t *testing.T, dbi testutil.DBInfo) {
repo := NewExpenseRepository(dbi.DB)
user := testutil.CreateTestUser(t, dbi.DB, "test@example.com", nil)
space := testutil.CreateTestSpace(t, dbi.DB, user.ID, "Test Space")
tag := testutil.CreateTestTag(t, dbi.DB, space.ID, "Groceries", nil)
now := time.Now()
expense := &model.Expense{
ID: uuid.NewString(),
SpaceID: space.ID,
CreatedBy: user.ID,
Description: "Weekly groceries",
AmountCents: 5000,
Type: model.ExpenseTypeExpense,
Date: now,
CreatedAt: now,
UpdatedAt: now,
}
err := repo.Create(expense, []string{tag.ID}, nil)
require.NoError(t, err)
tagMap, err := repo.GetTagsByExpenseIDs([]string{expense.ID})
require.NoError(t, err)
require.Contains(t, tagMap, expense.ID)
require.Len(t, tagMap[expense.ID], 1)
assert.Equal(t, tag.ID, tagMap[expense.ID][0].ID)
assert.Equal(t, "Groceries", tagMap[expense.ID][0].Name)
})
}
func TestExpenseRepository_GetPaymentMethodsByExpenseIDs(t *testing.T) {
testutil.ForEachDB(t, func(t *testing.T, dbi testutil.DBInfo) {
repo := NewExpenseRepository(dbi.DB)
user := testutil.CreateTestUser(t, dbi.DB, "test@example.com", nil)
space := testutil.CreateTestSpace(t, dbi.DB, user.ID, "Test Space")
method := testutil.CreateTestPaymentMethod(t, dbi.DB, space.ID, "Visa", model.PaymentMethodTypeCredit, user.ID)
now := time.Now()
expense := &model.Expense{
ID: uuid.NewString(),
SpaceID: space.ID,
CreatedBy: user.ID,
Description: "Online purchase",
AmountCents: 3000,
Type: model.ExpenseTypeExpense,
Date: now,
PaymentMethodID: &method.ID,
CreatedAt: now,
UpdatedAt: now,
}
err := repo.Create(expense, nil, nil)
require.NoError(t, err)
methodMap, err := repo.GetPaymentMethodsByExpenseIDs([]string{expense.ID})
require.NoError(t, err)
require.Contains(t, methodMap, expense.ID)
assert.Equal(t, method.ID, methodMap[expense.ID].ID)
assert.Equal(t, "Visa", methodMap[expense.ID].Name)
assert.Equal(t, model.PaymentMethodTypeCredit, methodMap[expense.ID].Type)
})
}
func TestExpenseRepository_GetExpensesByTag(t *testing.T) {
testutil.ForEachDB(t, func(t *testing.T, dbi testutil.DBInfo) {
repo := NewExpenseRepository(dbi.DB)
user := testutil.CreateTestUser(t, dbi.DB, "test@example.com", nil)
space := testutil.CreateTestSpace(t, dbi.DB, user.ID, "Test Space")
color := "#ff0000"
tag := testutil.CreateTestTag(t, dbi.DB, space.ID, "Food", &color)
now := time.Now()
fromDate := now.Add(-24 * time.Hour)
toDate := now.Add(24 * time.Hour)
expense1 := &model.Expense{
ID: uuid.NewString(),
SpaceID: space.ID,
CreatedBy: user.ID,
Description: "Lunch",
AmountCents: 1500,
Type: model.ExpenseTypeExpense,
Date: now,
CreatedAt: now,
UpdatedAt: now,
}
err := repo.Create(expense1, []string{tag.ID}, nil)
require.NoError(t, err)
expense2 := &model.Expense{
ID: uuid.NewString(),
SpaceID: space.ID,
CreatedBy: user.ID,
Description: "Dinner",
AmountCents: 2500,
Type: model.ExpenseTypeExpense,
Date: now,
CreatedAt: now,
UpdatedAt: now,
}
err = repo.Create(expense2, []string{tag.ID}, nil)
require.NoError(t, err)
summaries, err := repo.GetExpensesByTag(space.ID, fromDate, toDate)
require.NoError(t, err)
require.Len(t, summaries, 1)
assert.Equal(t, tag.ID, summaries[0].TagID)
assert.Equal(t, "Food", summaries[0].TagName)
assert.Equal(t, 4000, summaries[0].TotalAmount)
})
}
func TestExpenseRepository_Update(t *testing.T) {
testutil.ForEachDB(t, func(t *testing.T, dbi testutil.DBInfo) {
repo := NewExpenseRepository(dbi.DB)
user := testutil.CreateTestUser(t, dbi.DB, "test@example.com", nil)
space := testutil.CreateTestSpace(t, dbi.DB, user.ID, "Test Space")
tag1 := testutil.CreateTestTag(t, dbi.DB, space.ID, "Tag A", nil)
tag2 := testutil.CreateTestTag(t, dbi.DB, space.ID, "Tag B", nil)
now := time.Now()
expense := &model.Expense{
ID: uuid.NewString(),
SpaceID: space.ID,
CreatedBy: user.ID,
Description: "Original",
AmountCents: 1000,
Type: model.ExpenseTypeExpense,
Date: now,
CreatedAt: now,
UpdatedAt: now,
}
err := repo.Create(expense, []string{tag1.ID}, nil)
require.NoError(t, err)
expense.Description = "Updated"
expense.UpdatedAt = time.Now()
err = repo.Update(expense, []string{tag2.ID})
require.NoError(t, err)
fetched, err := repo.GetByID(expense.ID)
require.NoError(t, err)
assert.Equal(t, "Updated", fetched.Description)
tagMap, err := repo.GetTagsByExpenseIDs([]string{expense.ID})
require.NoError(t, err)
require.Len(t, tagMap[expense.ID], 1)
assert.Equal(t, tag2.ID, tagMap[expense.ID][0].ID)
})
}
func TestExpenseRepository_Delete(t *testing.T) {
testutil.ForEachDB(t, func(t *testing.T, dbi testutil.DBInfo) {
repo := NewExpenseRepository(dbi.DB)
user := testutil.CreateTestUser(t, dbi.DB, "test@example.com", nil)
space := testutil.CreateTestSpace(t, dbi.DB, user.ID, "Test Space")
expense := testutil.CreateTestExpense(t, dbi.DB, space.ID, user.ID, "To Delete", 500, model.ExpenseTypeExpense)
err := repo.Delete(expense.ID)
require.NoError(t, err)
_, err = repo.GetByID(expense.ID)
assert.ErrorIs(t, err, ErrExpenseNotFound)
})
}

View file

@ -0,0 +1,100 @@
package repository
import (
"testing"
"time"
"git.juancwu.dev/juancwu/budgit/internal/model"
"git.juancwu.dev/juancwu/budgit/internal/testutil"
"github.com/google/uuid"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestInvitationRepository_Create(t *testing.T) {
testutil.ForEachDB(t, func(t *testing.T, dbi testutil.DBInfo) {
repo := NewInvitationRepository(dbi.DB)
owner := testutil.CreateTestUser(t, dbi.DB, "inv-owner@example.com", nil)
space := testutil.CreateTestSpace(t, dbi.DB, owner.ID, "Invite Space")
now := time.Now()
invitation := &model.SpaceInvitation{
Token: uuid.NewString(),
SpaceID: space.ID,
InviterID: owner.ID,
Email: "invitee@example.com",
Status: model.InvitationStatusPending,
ExpiresAt: now.Add(48 * time.Hour),
CreatedAt: now,
UpdatedAt: now,
}
err := repo.Create(invitation)
require.NoError(t, err)
fetched, err := repo.GetByToken(invitation.Token)
require.NoError(t, err)
assert.Equal(t, invitation.Token, fetched.Token)
assert.Equal(t, space.ID, fetched.SpaceID)
assert.Equal(t, "invitee@example.com", fetched.Email)
assert.Equal(t, model.InvitationStatusPending, fetched.Status)
})
}
func TestInvitationRepository_GetBySpaceID(t *testing.T) {
testutil.ForEachDB(t, func(t *testing.T, dbi testutil.DBInfo) {
repo := NewInvitationRepository(dbi.DB)
owner := testutil.CreateTestUser(t, dbi.DB, "inv-space-owner@example.com", nil)
space := testutil.CreateTestSpace(t, dbi.DB, owner.ID, "Space Invites")
testutil.CreateTestInvitation(t, dbi.DB, space.ID, owner.ID, "one@example.com")
invitations, err := repo.GetBySpaceID(space.ID)
require.NoError(t, err)
require.Len(t, invitations, 1)
assert.Equal(t, "one@example.com", invitations[0].Email)
})
}
func TestInvitationRepository_UpdateStatus(t *testing.T) {
testutil.ForEachDB(t, func(t *testing.T, dbi testutil.DBInfo) {
repo := NewInvitationRepository(dbi.DB)
owner := testutil.CreateTestUser(t, dbi.DB, "inv-status-owner@example.com", nil)
space := testutil.CreateTestSpace(t, dbi.DB, owner.ID, "Status Space")
invitation := testutil.CreateTestInvitation(t, dbi.DB, space.ID, owner.ID, "status@example.com")
err := repo.UpdateStatus(invitation.Token, model.InvitationStatusAccepted)
require.NoError(t, err)
fetched, err := repo.GetByToken(invitation.Token)
require.NoError(t, err)
assert.Equal(t, model.InvitationStatusAccepted, fetched.Status)
})
}
func TestInvitationRepository_Delete(t *testing.T) {
testutil.ForEachDB(t, func(t *testing.T, dbi testutil.DBInfo) {
repo := NewInvitationRepository(dbi.DB)
owner := testutil.CreateTestUser(t, dbi.DB, "inv-delete-owner@example.com", nil)
space := testutil.CreateTestSpace(t, dbi.DB, owner.ID, "Delete Space")
invitation := testutil.CreateTestInvitation(t, dbi.DB, space.ID, owner.ID, "delete@example.com")
err := repo.Delete(invitation.Token)
require.NoError(t, err)
_, err = repo.GetByToken(invitation.Token)
assert.ErrorIs(t, err, ErrInvitationNotFound)
})
}
func TestInvitationRepository_NotFound(t *testing.T) {
testutil.ForEachDB(t, func(t *testing.T, dbi testutil.DBInfo) {
repo := NewInvitationRepository(dbi.DB)
_, err := repo.GetByToken("nonexistent-token")
assert.ErrorIs(t, err, ErrInvitationNotFound)
})
}

View file

@ -0,0 +1,161 @@
package repository
import (
"testing"
"time"
"git.juancwu.dev/juancwu/budgit/internal/model"
"git.juancwu.dev/juancwu/budgit/internal/testutil"
"github.com/google/uuid"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestListItemRepository_Create(t *testing.T) {
testutil.ForEachDB(t, func(t *testing.T, dbi testutil.DBInfo) {
repo := NewListItemRepository(dbi.DB)
user := testutil.CreateTestUser(t, dbi.DB, "test@example.com", nil)
space := testutil.CreateTestSpace(t, dbi.DB, user.ID, "Test Space")
list := testutil.CreateTestShoppingList(t, dbi.DB, space.ID, "Test List")
now := time.Now()
item := &model.ListItem{
ID: uuid.NewString(),
ListID: list.ID,
Name: "Apples",
IsChecked: false,
CreatedBy: user.ID,
CreatedAt: now,
UpdatedAt: now,
}
err := repo.Create(item)
require.NoError(t, err)
fetched, err := repo.GetByID(item.ID)
require.NoError(t, err)
assert.Equal(t, item.ID, fetched.ID)
assert.Equal(t, list.ID, fetched.ListID)
assert.Equal(t, "Apples", fetched.Name)
assert.False(t, fetched.IsChecked)
assert.Equal(t, user.ID, fetched.CreatedBy)
})
}
func TestListItemRepository_GetByListID(t *testing.T) {
testutil.ForEachDB(t, func(t *testing.T, dbi testutil.DBInfo) {
repo := NewListItemRepository(dbi.DB)
user := testutil.CreateTestUser(t, dbi.DB, "test@example.com", nil)
space := testutil.CreateTestSpace(t, dbi.DB, user.ID, "Test Space")
list := testutil.CreateTestShoppingList(t, dbi.DB, space.ID, "Test List")
item1 := testutil.CreateTestListItem(t, dbi.DB, list.ID, "Item A", user.ID)
time.Sleep(10 * time.Millisecond)
item2 := testutil.CreateTestListItem(t, dbi.DB, list.ID, "Item B", user.ID)
items, err := repo.GetByListID(list.ID)
require.NoError(t, err)
require.Len(t, items, 2)
// Ordered by created_at ASC, so item1 should be first.
assert.Equal(t, item1.ID, items[0].ID)
assert.Equal(t, item2.ID, items[1].ID)
})
}
func TestListItemRepository_GetByListIDPaginated(t *testing.T) {
testutil.ForEachDB(t, func(t *testing.T, dbi testutil.DBInfo) {
repo := NewListItemRepository(dbi.DB)
user := testutil.CreateTestUser(t, dbi.DB, "test@example.com", nil)
space := testutil.CreateTestSpace(t, dbi.DB, user.ID, "Test Space")
list := testutil.CreateTestShoppingList(t, dbi.DB, space.ID, "Test List")
testutil.CreateTestListItem(t, dbi.DB, list.ID, "Item A", user.ID)
time.Sleep(10 * time.Millisecond)
testutil.CreateTestListItem(t, dbi.DB, list.ID, "Item B", user.ID)
time.Sleep(10 * time.Millisecond)
testutil.CreateTestListItem(t, dbi.DB, list.ID, "Item C", user.ID)
items, err := repo.GetByListIDPaginated(list.ID, 2, 0)
require.NoError(t, err)
assert.Len(t, items, 2)
count, err := repo.CountByListID(list.ID)
require.NoError(t, err)
assert.Equal(t, 3, count)
})
}
func TestListItemRepository_CountByListID(t *testing.T) {
testutil.ForEachDB(t, func(t *testing.T, dbi testutil.DBInfo) {
repo := NewListItemRepository(dbi.DB)
user := testutil.CreateTestUser(t, dbi.DB, "test@example.com", nil)
space := testutil.CreateTestSpace(t, dbi.DB, user.ID, "Test Space")
list := testutil.CreateTestShoppingList(t, dbi.DB, space.ID, "Test List")
testutil.CreateTestListItem(t, dbi.DB, list.ID, "Item A", user.ID)
testutil.CreateTestListItem(t, dbi.DB, list.ID, "Item B", user.ID)
testutil.CreateTestListItem(t, dbi.DB, list.ID, "Item C", user.ID)
count, err := repo.CountByListID(list.ID)
require.NoError(t, err)
assert.Equal(t, 3, count)
})
}
func TestListItemRepository_Update(t *testing.T) {
testutil.ForEachDB(t, func(t *testing.T, dbi testutil.DBInfo) {
repo := NewListItemRepository(dbi.DB)
user := testutil.CreateTestUser(t, dbi.DB, "test@example.com", nil)
space := testutil.CreateTestSpace(t, dbi.DB, user.ID, "Test Space")
list := testutil.CreateTestShoppingList(t, dbi.DB, space.ID, "Test List")
item := testutil.CreateTestListItem(t, dbi.DB, list.ID, "Original", user.ID)
item.Name = "Updated"
item.IsChecked = true
err := repo.Update(item)
require.NoError(t, err)
fetched, err := repo.GetByID(item.ID)
require.NoError(t, err)
assert.Equal(t, "Updated", fetched.Name)
assert.True(t, fetched.IsChecked)
})
}
func TestListItemRepository_Delete(t *testing.T) {
testutil.ForEachDB(t, func(t *testing.T, dbi testutil.DBInfo) {
repo := NewListItemRepository(dbi.DB)
user := testutil.CreateTestUser(t, dbi.DB, "test@example.com", nil)
space := testutil.CreateTestSpace(t, dbi.DB, user.ID, "Test Space")
list := testutil.CreateTestShoppingList(t, dbi.DB, space.ID, "Test List")
item := testutil.CreateTestListItem(t, dbi.DB, list.ID, "To Delete", user.ID)
err := repo.Delete(item.ID)
require.NoError(t, err)
_, err = repo.GetByID(item.ID)
assert.ErrorIs(t, err, ErrListItemNotFound)
})
}
func TestListItemRepository_DeleteByListID(t *testing.T) {
testutil.ForEachDB(t, func(t *testing.T, dbi testutil.DBInfo) {
repo := NewListItemRepository(dbi.DB)
user := testutil.CreateTestUser(t, dbi.DB, "test@example.com", nil)
space := testutil.CreateTestSpace(t, dbi.DB, user.ID, "Test Space")
list := testutil.CreateTestShoppingList(t, dbi.DB, space.ID, "Test List")
testutil.CreateTestListItem(t, dbi.DB, list.ID, "Item A", user.ID)
testutil.CreateTestListItem(t, dbi.DB, list.ID, "Item B", user.ID)
err := repo.DeleteByListID(list.ID)
require.NoError(t, err)
items, err := repo.GetByListID(list.ID)
require.NoError(t, err)
assert.Empty(t, items)
})
}

View file

@ -0,0 +1,169 @@
package repository
import (
"testing"
"time"
"git.juancwu.dev/juancwu/budgit/internal/model"
"git.juancwu.dev/juancwu/budgit/internal/testutil"
"github.com/google/uuid"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestMoneyAccountRepository_Create(t *testing.T) {
testutil.ForEachDB(t, func(t *testing.T, dbi testutil.DBInfo) {
repo := NewMoneyAccountRepository(dbi.DB)
user := testutil.CreateTestUser(t, dbi.DB, "test@example.com", nil)
space := testutil.CreateTestSpace(t, dbi.DB, user.ID, "Test Space")
now := time.Now()
account := &model.MoneyAccount{
ID: uuid.NewString(),
SpaceID: space.ID,
Name: "Savings",
CreatedBy: user.ID,
CreatedAt: now,
UpdatedAt: now,
}
err := repo.Create(account)
require.NoError(t, err)
fetched, err := repo.GetByID(account.ID)
require.NoError(t, err)
assert.Equal(t, account.ID, fetched.ID)
assert.Equal(t, space.ID, fetched.SpaceID)
assert.Equal(t, "Savings", fetched.Name)
assert.Equal(t, user.ID, fetched.CreatedBy)
})
}
func TestMoneyAccountRepository_GetBySpaceID(t *testing.T) {
testutil.ForEachDB(t, func(t *testing.T, dbi testutil.DBInfo) {
repo := NewMoneyAccountRepository(dbi.DB)
user := testutil.CreateTestUser(t, dbi.DB, "test@example.com", nil)
space := testutil.CreateTestSpace(t, dbi.DB, user.ID, "Test Space")
testutil.CreateTestMoneyAccount(t, dbi.DB, space.ID, "Account A", user.ID)
testutil.CreateTestMoneyAccount(t, dbi.DB, space.ID, "Account B", user.ID)
accounts, err := repo.GetBySpaceID(space.ID)
require.NoError(t, err)
assert.Len(t, accounts, 2)
})
}
func TestMoneyAccountRepository_Update(t *testing.T) {
testutil.ForEachDB(t, func(t *testing.T, dbi testutil.DBInfo) {
repo := NewMoneyAccountRepository(dbi.DB)
user := testutil.CreateTestUser(t, dbi.DB, "test@example.com", nil)
space := testutil.CreateTestSpace(t, dbi.DB, user.ID, "Test Space")
account := testutil.CreateTestMoneyAccount(t, dbi.DB, space.ID, "Original", user.ID)
account.Name = "Renamed"
err := repo.Update(account)
require.NoError(t, err)
fetched, err := repo.GetByID(account.ID)
require.NoError(t, err)
assert.Equal(t, "Renamed", fetched.Name)
})
}
func TestMoneyAccountRepository_Delete(t *testing.T) {
testutil.ForEachDB(t, func(t *testing.T, dbi testutil.DBInfo) {
repo := NewMoneyAccountRepository(dbi.DB)
user := testutil.CreateTestUser(t, dbi.DB, "test@example.com", nil)
space := testutil.CreateTestSpace(t, dbi.DB, user.ID, "Test Space")
account := testutil.CreateTestMoneyAccount(t, dbi.DB, space.ID, "To Delete", user.ID)
err := repo.Delete(account.ID)
require.NoError(t, err)
_, err = repo.GetByID(account.ID)
assert.ErrorIs(t, err, ErrMoneyAccountNotFound)
})
}
func TestMoneyAccountRepository_CreateTransfer(t *testing.T) {
testutil.ForEachDB(t, func(t *testing.T, dbi testutil.DBInfo) {
repo := NewMoneyAccountRepository(dbi.DB)
user := testutil.CreateTestUser(t, dbi.DB, "test@example.com", nil)
space := testutil.CreateTestSpace(t, dbi.DB, user.ID, "Test Space")
account := testutil.CreateTestMoneyAccount(t, dbi.DB, space.ID, "Checking", user.ID)
transfer := &model.AccountTransfer{
ID: uuid.NewString(),
AccountID: account.ID,
AmountCents: 5000,
Direction: model.TransferDirectionDeposit,
Note: "Initial deposit",
CreatedBy: user.ID,
CreatedAt: time.Now(),
}
err := repo.CreateTransfer(transfer)
require.NoError(t, err)
transfers, err := repo.GetTransfersByAccountID(account.ID)
require.NoError(t, err)
require.Len(t, transfers, 1)
assert.Equal(t, transfer.ID, transfers[0].ID)
assert.Equal(t, 5000, transfers[0].AmountCents)
assert.Equal(t, model.TransferDirectionDeposit, transfers[0].Direction)
})
}
func TestMoneyAccountRepository_DeleteTransfer(t *testing.T) {
testutil.ForEachDB(t, func(t *testing.T, dbi testutil.DBInfo) {
repo := NewMoneyAccountRepository(dbi.DB)
user := testutil.CreateTestUser(t, dbi.DB, "test@example.com", nil)
space := testutil.CreateTestSpace(t, dbi.DB, user.ID, "Test Space")
account := testutil.CreateTestMoneyAccount(t, dbi.DB, space.ID, "Checking", user.ID)
transfer := testutil.CreateTestTransfer(t, dbi.DB, account.ID, 1000, model.TransferDirectionDeposit, user.ID)
err := repo.DeleteTransfer(transfer.ID)
require.NoError(t, err)
transfers, err := repo.GetTransfersByAccountID(account.ID)
require.NoError(t, err)
assert.Empty(t, transfers)
})
}
func TestMoneyAccountRepository_GetAccountBalance(t *testing.T) {
testutil.ForEachDB(t, func(t *testing.T, dbi testutil.DBInfo) {
repo := NewMoneyAccountRepository(dbi.DB)
user := testutil.CreateTestUser(t, dbi.DB, "test@example.com", nil)
space := testutil.CreateTestSpace(t, dbi.DB, user.ID, "Test Space")
account := testutil.CreateTestMoneyAccount(t, dbi.DB, space.ID, "Checking", user.ID)
testutil.CreateTestTransfer(t, dbi.DB, account.ID, 1000, model.TransferDirectionDeposit, user.ID)
testutil.CreateTestTransfer(t, dbi.DB, account.ID, 300, model.TransferDirectionWithdrawal, user.ID)
balance, err := repo.GetAccountBalance(account.ID)
require.NoError(t, err)
assert.Equal(t, 700, balance)
})
}
func TestMoneyAccountRepository_GetTotalAllocatedForSpace(t *testing.T) {
testutil.ForEachDB(t, func(t *testing.T, dbi testutil.DBInfo) {
repo := NewMoneyAccountRepository(dbi.DB)
user := testutil.CreateTestUser(t, dbi.DB, "test@example.com", nil)
space := testutil.CreateTestSpace(t, dbi.DB, user.ID, "Test Space")
account1 := testutil.CreateTestMoneyAccount(t, dbi.DB, space.ID, "Account A", user.ID)
account2 := testutil.CreateTestMoneyAccount(t, dbi.DB, space.ID, "Account B", user.ID)
testutil.CreateTestTransfer(t, dbi.DB, account1.ID, 2000, model.TransferDirectionDeposit, user.ID)
testutil.CreateTestTransfer(t, dbi.DB, account2.ID, 3000, model.TransferDirectionDeposit, user.ID)
total, err := repo.GetTotalAllocatedForSpace(space.ID)
require.NoError(t, err)
assert.Equal(t, 5000, total)
})
}

View file

@ -0,0 +1,97 @@
package repository
import (
"testing"
"time"
"git.juancwu.dev/juancwu/budgit/internal/model"
"git.juancwu.dev/juancwu/budgit/internal/testutil"
"github.com/google/uuid"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestPaymentMethodRepository_Create(t *testing.T) {
testutil.ForEachDB(t, func(t *testing.T, dbi testutil.DBInfo) {
repo := NewPaymentMethodRepository(dbi.DB)
user := testutil.CreateTestUser(t, dbi.DB, "test@example.com", nil)
space := testutil.CreateTestSpace(t, dbi.DB, user.ID, "Test Space")
lastFour := "4242"
now := time.Now()
method := &model.PaymentMethod{
ID: uuid.NewString(),
SpaceID: space.ID,
Name: "Visa Gold",
Type: model.PaymentMethodTypeCredit,
LastFour: &lastFour,
CreatedBy: user.ID,
CreatedAt: now,
UpdatedAt: now,
}
err := repo.Create(method)
require.NoError(t, err)
fetched, err := repo.GetByID(method.ID)
require.NoError(t, err)
assert.Equal(t, method.ID, fetched.ID)
assert.Equal(t, space.ID, fetched.SpaceID)
assert.Equal(t, "Visa Gold", fetched.Name)
assert.Equal(t, model.PaymentMethodTypeCredit, fetched.Type)
require.NotNil(t, fetched.LastFour)
assert.Equal(t, "4242", *fetched.LastFour)
assert.Equal(t, user.ID, fetched.CreatedBy)
})
}
func TestPaymentMethodRepository_GetBySpaceID(t *testing.T) {
testutil.ForEachDB(t, func(t *testing.T, dbi testutil.DBInfo) {
repo := NewPaymentMethodRepository(dbi.DB)
user := testutil.CreateTestUser(t, dbi.DB, "test@example.com", nil)
space := testutil.CreateTestSpace(t, dbi.DB, user.ID, "Test Space")
testutil.CreateTestPaymentMethod(t, dbi.DB, space.ID, "Visa", model.PaymentMethodTypeCredit, user.ID)
testutil.CreateTestPaymentMethod(t, dbi.DB, space.ID, "Debit Card", model.PaymentMethodTypeDebit, user.ID)
methods, err := repo.GetBySpaceID(space.ID)
require.NoError(t, err)
assert.Len(t, methods, 2)
})
}
func TestPaymentMethodRepository_Update(t *testing.T) {
testutil.ForEachDB(t, func(t *testing.T, dbi testutil.DBInfo) {
repo := NewPaymentMethodRepository(dbi.DB)
user := testutil.CreateTestUser(t, dbi.DB, "test@example.com", nil)
space := testutil.CreateTestSpace(t, dbi.DB, user.ID, "Test Space")
method := testutil.CreateTestPaymentMethod(t, dbi.DB, space.ID, "Old Card", model.PaymentMethodTypeCredit, user.ID)
method.Name = "New Card"
method.Type = model.PaymentMethodTypeDebit
err := repo.Update(method)
require.NoError(t, err)
fetched, err := repo.GetByID(method.ID)
require.NoError(t, err)
assert.Equal(t, "New Card", fetched.Name)
assert.Equal(t, model.PaymentMethodTypeDebit, fetched.Type)
})
}
func TestPaymentMethodRepository_Delete(t *testing.T) {
testutil.ForEachDB(t, func(t *testing.T, dbi testutil.DBInfo) {
repo := NewPaymentMethodRepository(dbi.DB)
user := testutil.CreateTestUser(t, dbi.DB, "test@example.com", nil)
space := testutil.CreateTestSpace(t, dbi.DB, user.ID, "Test Space")
method := testutil.CreateTestPaymentMethod(t, dbi.DB, space.ID, "To Delete", model.PaymentMethodTypeCredit, user.ID)
err := repo.Delete(method.ID)
require.NoError(t, err)
_, err = repo.GetByID(method.ID)
assert.ErrorIs(t, err, ErrPaymentMethodNotFound)
})
}

View file

@ -0,0 +1,63 @@
package repository
import (
"testing"
"time"
"git.juancwu.dev/juancwu/budgit/internal/model"
"git.juancwu.dev/juancwu/budgit/internal/testutil"
"github.com/google/uuid"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestProfileRepository_Create(t *testing.T) {
testutil.ForEachDB(t, func(t *testing.T, dbi testutil.DBInfo) {
repo := NewProfileRepository(dbi.DB)
user := testutil.CreateTestUser(t, dbi.DB, "profile-create@example.com", nil)
now := time.Now()
profile := &model.Profile{
ID: uuid.NewString(),
UserID: user.ID,
Name: "Test User",
CreatedAt: now,
UpdatedAt: now,
}
id, err := repo.Create(profile)
require.NoError(t, err)
assert.Equal(t, profile.ID, id)
fetched, err := repo.ByUserID(user.ID)
require.NoError(t, err)
assert.Equal(t, "Test User", fetched.Name)
assert.Equal(t, user.ID, fetched.UserID)
})
}
func TestProfileRepository_UpdateName(t *testing.T) {
testutil.ForEachDB(t, func(t *testing.T, dbi testutil.DBInfo) {
repo := NewProfileRepository(dbi.DB)
user := testutil.CreateTestUser(t, dbi.DB, "profile-update@example.com", nil)
testutil.CreateTestProfile(t, dbi.DB, user.ID, "Old Name")
err := repo.UpdateName(user.ID, "New Name")
require.NoError(t, err)
fetched, err := repo.ByUserID(user.ID)
require.NoError(t, err)
assert.Equal(t, "New Name", fetched.Name)
})
}
func TestProfileRepository_NotFound(t *testing.T) {
testutil.ForEachDB(t, func(t *testing.T, dbi testutil.DBInfo) {
repo := NewProfileRepository(dbi.DB)
_, err := repo.ByUserID("nonexistent-id")
assert.ErrorIs(t, err, ErrProfileNotFound)
})
}

View file

@ -0,0 +1,93 @@
package repository
import (
"testing"
"time"
"git.juancwu.dev/juancwu/budgit/internal/model"
"git.juancwu.dev/juancwu/budgit/internal/testutil"
"github.com/google/uuid"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestShoppingListRepository_Create(t *testing.T) {
testutil.ForEachDB(t, func(t *testing.T, dbi testutil.DBInfo) {
repo := NewShoppingListRepository(dbi.DB)
user := testutil.CreateTestUser(t, dbi.DB, "test@example.com", nil)
space := testutil.CreateTestSpace(t, dbi.DB, user.ID, "Test Space")
now := time.Now()
list := &model.ShoppingList{
ID: uuid.NewString(),
SpaceID: space.ID,
Name: "Groceries",
CreatedAt: now,
UpdatedAt: now,
}
err := repo.Create(list)
require.NoError(t, err)
fetched, err := repo.GetByID(list.ID)
require.NoError(t, err)
assert.Equal(t, list.ID, fetched.ID)
assert.Equal(t, space.ID, fetched.SpaceID)
assert.Equal(t, "Groceries", fetched.Name)
})
}
func TestShoppingListRepository_GetBySpaceID(t *testing.T) {
testutil.ForEachDB(t, func(t *testing.T, dbi testutil.DBInfo) {
repo := NewShoppingListRepository(dbi.DB)
user := testutil.CreateTestUser(t, dbi.DB, "test@example.com", nil)
space := testutil.CreateTestSpace(t, dbi.DB, user.ID, "Test Space")
list1 := testutil.CreateTestShoppingList(t, dbi.DB, space.ID, "List A")
// Small delay to ensure distinct created_at timestamps for ordering.
time.Sleep(10 * time.Millisecond)
list2 := testutil.CreateTestShoppingList(t, dbi.DB, space.ID, "List B")
lists, err := repo.GetBySpaceID(space.ID)
require.NoError(t, err)
require.Len(t, lists, 2)
// Ordered by created_at DESC, so list2 should be first.
assert.Equal(t, list2.ID, lists[0].ID)
assert.Equal(t, list1.ID, lists[1].ID)
})
}
func TestShoppingListRepository_Update(t *testing.T) {
testutil.ForEachDB(t, func(t *testing.T, dbi testutil.DBInfo) {
repo := NewShoppingListRepository(dbi.DB)
user := testutil.CreateTestUser(t, dbi.DB, "test@example.com", nil)
space := testutil.CreateTestSpace(t, dbi.DB, user.ID, "Test Space")
list := testutil.CreateTestShoppingList(t, dbi.DB, space.ID, "Original Name")
list.Name = "Updated Name"
err := repo.Update(list)
require.NoError(t, err)
fetched, err := repo.GetByID(list.ID)
require.NoError(t, err)
assert.Equal(t, "Updated Name", fetched.Name)
})
}
func TestShoppingListRepository_Delete(t *testing.T) {
testutil.ForEachDB(t, func(t *testing.T, dbi testutil.DBInfo) {
repo := NewShoppingListRepository(dbi.DB)
user := testutil.CreateTestUser(t, dbi.DB, "test@example.com", nil)
space := testutil.CreateTestSpace(t, dbi.DB, user.ID, "Test Space")
list := testutil.CreateTestShoppingList(t, dbi.DB, space.ID, "To Delete")
err := repo.Delete(list.ID)
require.NoError(t, err)
_, err = repo.GetByID(list.ID)
assert.ErrorIs(t, err, ErrShoppingListNotFound)
})
}

View file

@ -0,0 +1,140 @@
package repository
import (
"testing"
"time"
"git.juancwu.dev/juancwu/budgit/internal/model"
"git.juancwu.dev/juancwu/budgit/internal/testutil"
"github.com/google/uuid"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestSpaceRepository_Create(t *testing.T) {
testutil.ForEachDB(t, func(t *testing.T, dbi testutil.DBInfo) {
repo := NewSpaceRepository(dbi.DB)
user := testutil.CreateTestUser(t, dbi.DB, "space-create@example.com", nil)
now := time.Now()
space := &model.Space{
ID: uuid.NewString(),
Name: "My Space",
OwnerID: user.ID,
CreatedAt: now,
UpdatedAt: now,
}
err := repo.Create(space)
require.NoError(t, err)
fetched, err := repo.ByID(space.ID)
require.NoError(t, err)
assert.Equal(t, "My Space", fetched.Name)
assert.Equal(t, user.ID, fetched.OwnerID)
isMember, err := repo.IsMember(space.ID, user.ID)
require.NoError(t, err)
assert.True(t, isMember, "owner should be a member after Create")
})
}
func TestSpaceRepository_ByUserID(t *testing.T) {
testutil.ForEachDB(t, func(t *testing.T, dbi testutil.DBInfo) {
repo := NewSpaceRepository(dbi.DB)
user := testutil.CreateTestUser(t, dbi.DB, "space-byuser@example.com", nil)
space := testutil.CreateTestSpace(t, dbi.DB, user.ID, "User Space")
spaces, err := repo.ByUserID(user.ID)
require.NoError(t, err)
require.Len(t, spaces, 1)
assert.Equal(t, space.ID, spaces[0].ID)
})
}
func TestSpaceRepository_AddMember(t *testing.T) {
testutil.ForEachDB(t, func(t *testing.T, dbi testutil.DBInfo) {
repo := NewSpaceRepository(dbi.DB)
owner := testutil.CreateTestUser(t, dbi.DB, "space-owner@example.com", nil)
member := testutil.CreateTestUser(t, dbi.DB, "space-member@example.com", nil)
space := testutil.CreateTestSpace(t, dbi.DB, owner.ID, "Shared Space")
err := repo.AddMember(space.ID, member.ID, model.RoleMember)
require.NoError(t, err)
isMember, err := repo.IsMember(space.ID, member.ID)
require.NoError(t, err)
assert.True(t, isMember)
})
}
func TestSpaceRepository_RemoveMember(t *testing.T) {
testutil.ForEachDB(t, func(t *testing.T, dbi testutil.DBInfo) {
repo := NewSpaceRepository(dbi.DB)
owner := testutil.CreateTestUser(t, dbi.DB, "remove-owner@example.com", nil)
member := testutil.CreateTestUser(t, dbi.DB, "remove-member@example.com", nil)
space := testutil.CreateTestSpace(t, dbi.DB, owner.ID, "Remove Test")
err := repo.AddMember(space.ID, member.ID, model.RoleMember)
require.NoError(t, err)
err = repo.RemoveMember(space.ID, member.ID)
require.NoError(t, err)
isMember, err := repo.IsMember(space.ID, member.ID)
require.NoError(t, err)
assert.False(t, isMember)
})
}
func TestSpaceRepository_GetMembers(t *testing.T) {
testutil.ForEachDB(t, func(t *testing.T, dbi testutil.DBInfo) {
repo := NewSpaceRepository(dbi.DB)
owner, _ := testutil.CreateTestUserWithProfile(t, dbi.DB, "members-owner@example.com", "Owner")
member, _ := testutil.CreateTestUserWithProfile(t, dbi.DB, "members-member@example.com", "Member")
space := testutil.CreateTestSpace(t, dbi.DB, owner.ID, "Members Space")
err := repo.AddMember(space.ID, member.ID, model.RoleMember)
require.NoError(t, err)
members, err := repo.GetMembers(space.ID)
require.NoError(t, err)
require.Len(t, members, 2)
// The query orders by role DESC (owner first), then joined_at ASC.
assert.Equal(t, model.RoleOwner, members[0].Role)
assert.Equal(t, "Owner", members[0].Name)
assert.Equal(t, model.RoleMember, members[1].Role)
assert.Equal(t, "Member", members[1].Name)
})
}
func TestSpaceRepository_UpdateName(t *testing.T) {
testutil.ForEachDB(t, func(t *testing.T, dbi testutil.DBInfo) {
repo := NewSpaceRepository(dbi.DB)
user := testutil.CreateTestUser(t, dbi.DB, "space-rename@example.com", nil)
space := testutil.CreateTestSpace(t, dbi.DB, user.ID, "Old Name")
err := repo.UpdateName(space.ID, "New Name")
require.NoError(t, err)
fetched, err := repo.ByID(space.ID)
require.NoError(t, err)
assert.Equal(t, "New Name", fetched.Name)
})
}
func TestSpaceRepository_NotFound(t *testing.T) {
testutil.ForEachDB(t, func(t *testing.T, dbi testutil.DBInfo) {
repo := NewSpaceRepository(dbi.DB)
_, err := repo.ByID("nonexistent-id")
assert.ErrorIs(t, err, ErrSpaceNotFound)
})
}

View file

@ -0,0 +1,120 @@
package repository
import (
"testing"
"time"
"git.juancwu.dev/juancwu/budgit/internal/model"
"git.juancwu.dev/juancwu/budgit/internal/testutil"
"github.com/google/uuid"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestTagRepository_Create(t *testing.T) {
testutil.ForEachDB(t, func(t *testing.T, dbi testutil.DBInfo) {
repo := NewTagRepository(dbi.DB)
user := testutil.CreateTestUser(t, dbi.DB, "tag-create@example.com", nil)
space := testutil.CreateTestSpace(t, dbi.DB, user.ID, "Tag Space")
color := "#ff0000"
now := time.Now()
tag := &model.Tag{
ID: uuid.NewString(),
SpaceID: space.ID,
Name: "Groceries",
Color: &color,
CreatedAt: now,
UpdatedAt: now,
}
err := repo.Create(tag)
require.NoError(t, err)
fetched, err := repo.GetByID(tag.ID)
require.NoError(t, err)
assert.Equal(t, "Groceries", fetched.Name)
assert.Equal(t, &color, fetched.Color)
assert.Equal(t, space.ID, fetched.SpaceID)
})
}
func TestTagRepository_GetBySpaceID(t *testing.T) {
testutil.ForEachDB(t, func(t *testing.T, dbi testutil.DBInfo) {
repo := NewTagRepository(dbi.DB)
user := testutil.CreateTestUser(t, dbi.DB, "tag-list@example.com", nil)
space := testutil.CreateTestSpace(t, dbi.DB, user.ID, "Tag List Space")
// Create tags with names that sort alphabetically: "Alpha" < "Beta".
testutil.CreateTestTag(t, dbi.DB, space.ID, "Beta", nil)
testutil.CreateTestTag(t, dbi.DB, space.ID, "Alpha", nil)
tags, err := repo.GetBySpaceID(space.ID)
require.NoError(t, err)
require.Len(t, tags, 2)
assert.Equal(t, "Alpha", tags[0].Name)
assert.Equal(t, "Beta", tags[1].Name)
})
}
func TestTagRepository_Update(t *testing.T) {
testutil.ForEachDB(t, func(t *testing.T, dbi testutil.DBInfo) {
repo := NewTagRepository(dbi.DB)
user := testutil.CreateTestUser(t, dbi.DB, "tag-update@example.com", nil)
space := testutil.CreateTestSpace(t, dbi.DB, user.ID, "Tag Update Space")
tag := testutil.CreateTestTag(t, dbi.DB, space.ID, "Old Tag", nil)
newColor := "#00ff00"
tag.Name = "New Tag"
tag.Color = &newColor
err := repo.Update(tag)
require.NoError(t, err)
fetched, err := repo.GetByID(tag.ID)
require.NoError(t, err)
assert.Equal(t, "New Tag", fetched.Name)
assert.Equal(t, &newColor, fetched.Color)
})
}
func TestTagRepository_Delete(t *testing.T) {
testutil.ForEachDB(t, func(t *testing.T, dbi testutil.DBInfo) {
repo := NewTagRepository(dbi.DB)
user := testutil.CreateTestUser(t, dbi.DB, "tag-delete@example.com", nil)
space := testutil.CreateTestSpace(t, dbi.DB, user.ID, "Tag Delete Space")
tag := testutil.CreateTestTag(t, dbi.DB, space.ID, "Doomed Tag", nil)
err := repo.Delete(tag.ID)
require.NoError(t, err)
_, err = repo.GetByID(tag.ID)
assert.ErrorIs(t, err, ErrTagNotFound)
})
}
func TestTagRepository_DuplicateTagName(t *testing.T) {
testutil.ForEachDB(t, func(t *testing.T, dbi testutil.DBInfo) {
repo := NewTagRepository(dbi.DB)
user := testutil.CreateTestUser(t, dbi.DB, "tag-dup@example.com", nil)
space := testutil.CreateTestSpace(t, dbi.DB, user.ID, "Tag Dup Space")
testutil.CreateTestTag(t, dbi.DB, space.ID, "Duplicate", nil)
now := time.Now()
duplicate := &model.Tag{
ID: uuid.NewString(),
SpaceID: space.ID,
Name: "Duplicate",
CreatedAt: now,
UpdatedAt: now,
}
err := repo.Create(duplicate)
assert.ErrorIs(t, err, ErrDuplicateTagName)
})
}

View file

@ -0,0 +1,78 @@
package repository
import (
"testing"
"time"
"git.juancwu.dev/juancwu/budgit/internal/model"
"git.juancwu.dev/juancwu/budgit/internal/testutil"
"github.com/google/uuid"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestTokenRepository_Create(t *testing.T) {
testutil.ForEachDB(t, func(t *testing.T, dbi testutil.DBInfo) {
repo := NewTokenRepository(dbi.DB)
user := testutil.CreateTestUser(t, dbi.DB, "token-create@example.com", nil)
token := &model.Token{
ID: uuid.NewString(),
UserID: user.ID,
Type: model.TokenTypeEmailVerify,
Token: uuid.NewString(),
ExpiresAt: time.Now().Add(1 * time.Hour),
CreatedAt: time.Now(),
}
id, err := repo.Create(token)
require.NoError(t, err)
assert.Equal(t, token.ID, id)
})
}
func TestTokenRepository_ConsumeToken(t *testing.T) {
testutil.ForEachDB(t, func(t *testing.T, dbi testutil.DBInfo) {
repo := NewTokenRepository(dbi.DB)
user := testutil.CreateTestUser(t, dbi.DB, "token-consume@example.com", nil)
tokenString := uuid.NewString()
testutil.CreateTestToken(t, dbi.DB, user.ID, model.TokenTypeEmailVerify, tokenString, time.Now().Add(1*time.Hour))
consumed, err := repo.ConsumeToken(tokenString)
require.NoError(t, err)
assert.NotNil(t, consumed.UsedAt)
assert.Equal(t, user.ID, consumed.UserID)
})
}
func TestTokenRepository_ConsumeExpiredToken(t *testing.T) {
testutil.ForEachDB(t, func(t *testing.T, dbi testutil.DBInfo) {
repo := NewTokenRepository(dbi.DB)
user := testutil.CreateTestUser(t, dbi.DB, "token-expired@example.com", nil)
tokenString := uuid.NewString()
testutil.CreateTestToken(t, dbi.DB, user.ID, model.TokenTypeEmailVerify, tokenString, time.Now().Add(-1*time.Hour))
_, err := repo.ConsumeToken(tokenString)
assert.ErrorIs(t, err, ErrTokenNotFound)
})
}
func TestTokenRepository_DeleteByUserAndType(t *testing.T) {
testutil.ForEachDB(t, func(t *testing.T, dbi testutil.DBInfo) {
repo := NewTokenRepository(dbi.DB)
user := testutil.CreateTestUser(t, dbi.DB, "token-delete@example.com", nil)
tokenString := uuid.NewString()
testutil.CreateTestToken(t, dbi.DB, user.ID, model.TokenTypeEmailVerify, tokenString, time.Now().Add(1*time.Hour))
err := repo.DeleteByUserAndType(user.ID, model.TokenTypeEmailVerify)
require.NoError(t, err)
// The token should no longer be consumable since it was deleted.
_, err = repo.ConsumeToken(tokenString)
assert.ErrorIs(t, err, ErrTokenNotFound)
})
}

View file

@ -0,0 +1,101 @@
package repository
import (
"testing"
"time"
"git.juancwu.dev/juancwu/budgit/internal/model"
"git.juancwu.dev/juancwu/budgit/internal/testutil"
"github.com/google/uuid"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestUserRepository_Create(t *testing.T) {
testutil.ForEachDB(t, func(t *testing.T, dbi testutil.DBInfo) {
repo := NewUserRepository(dbi.DB)
user := &model.User{
ID: uuid.NewString(),
Email: "create@example.com",
CreatedAt: time.Now(),
}
id, err := repo.Create(user)
require.NoError(t, err)
assert.Equal(t, user.ID, id)
fetched, err := repo.ByID(id)
require.NoError(t, err)
assert.Equal(t, user.Email, fetched.Email)
})
}
func TestUserRepository_ByEmail(t *testing.T) {
testutil.ForEachDB(t, func(t *testing.T, dbi testutil.DBInfo) {
repo := NewUserRepository(dbi.DB)
user := testutil.CreateTestUser(t, dbi.DB, "byemail@example.com", nil)
fetched, err := repo.ByEmail("byemail@example.com")
require.NoError(t, err)
assert.Equal(t, user.ID, fetched.ID)
assert.Equal(t, "byemail@example.com", fetched.Email)
})
}
func TestUserRepository_Update(t *testing.T) {
testutil.ForEachDB(t, func(t *testing.T, dbi testutil.DBInfo) {
repo := NewUserRepository(dbi.DB)
user := testutil.CreateTestUser(t, dbi.DB, "before@example.com", nil)
user.Email = "after@example.com"
err := repo.Update(user)
require.NoError(t, err)
fetched, err := repo.ByID(user.ID)
require.NoError(t, err)
assert.Equal(t, "after@example.com", fetched.Email)
})
}
func TestUserRepository_Delete(t *testing.T) {
testutil.ForEachDB(t, func(t *testing.T, dbi testutil.DBInfo) {
repo := NewUserRepository(dbi.DB)
user := testutil.CreateTestUser(t, dbi.DB, "delete@example.com", nil)
err := repo.Delete(user.ID)
require.NoError(t, err)
_, err = repo.ByID(user.ID)
assert.ErrorIs(t, err, ErrUserNotFound)
})
}
func TestUserRepository_DuplicateEmail(t *testing.T) {
testutil.ForEachDB(t, func(t *testing.T, dbi testutil.DBInfo) {
repo := NewUserRepository(dbi.DB)
testutil.CreateTestUser(t, dbi.DB, "dup@example.com", nil)
duplicate := &model.User{
ID: uuid.NewString(),
Email: "dup@example.com",
CreatedAt: time.Now(),
}
_, err := repo.Create(duplicate)
assert.ErrorIs(t, err, ErrDuplicateEmail)
})
}
func TestUserRepository_NotFound(t *testing.T) {
testutil.ForEachDB(t, func(t *testing.T, dbi testutil.DBInfo) {
repo := NewUserRepository(dbi.DB)
_, err := repo.ByID("nonexistent-id")
assert.ErrorIs(t, err, ErrUserNotFound)
})
}