Files
gochat/internal/service/category_service_test.go
T

316 lines
9.1 KiB
Go

package service
import (
"context"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/gochat/gochat/internal/repository"
)
// ========== Test Setup ==========
func setupCategoryService(t *testing.T) (*CategoryService, uint, uint) {
t.Helper()
db := setupServiceTestDB(t)
repo := repository.NewCategoryRepo(db)
relatedRepo := repository.NewRelatedCategoryRepo(db)
svc := NewCategoryService(repo, relatedRepo)
account := createTestAccount(t, db)
portal := createTestPortal(t, db, account.ID)
return svc, portal.ID, account.ID
}
// ========== Create ==========
func TestCategoryService_Create(t *testing.T) {
svc, portalID, accountID := setupCategoryService(t)
req := &CreateCategoryRequest{
Name: "Announcements",
Slug: "announcements",
Description: "Official announcements",
Icon: "📢",
Position: 1,
Locale: "en",
}
category, err := svc.Create(context.Background(), portalID, accountID, req)
require.NoError(t, err)
assert.NotZero(t, category.ID)
assert.Equal(t, portalID, category.PortalID)
assert.Equal(t, accountID, category.AccountID)
assert.Equal(t, "Announcements", category.Name)
assert.Equal(t, "announcements", category.Slug)
assert.Equal(t, "Official announcements", category.Description)
assert.Equal(t, "📢", category.Icon)
assert.Equal(t, 1, category.Position)
assert.Equal(t, "en", category.Locale)
}
// ========== GetByID ==========
func TestCategoryService_GetByID(t *testing.T) {
svc, portalID, accountID := setupCategoryService(t)
req := &CreateCategoryRequest{
Name: "FAQ",
Slug: "faq",
}
created, err := svc.Create(context.Background(), portalID, accountID, req)
require.NoError(t, err)
category, err := svc.GetByID(context.Background(), created.ID)
require.NoError(t, err)
assert.Equal(t, created.ID, category.ID)
assert.Equal(t, "FAQ", category.Name)
assert.Equal(t, "faq", category.Slug)
}
func TestCategoryService_GetByID_NotFound(t *testing.T) {
svc, _, _ := setupCategoryService(t)
category, err := svc.GetByID(context.Background(), 99999)
assert.Nil(t, category)
assert.Error(t, err)
}
// ========== Update ==========
func TestCategoryService_Update(t *testing.T) {
svc, portalID, accountID := setupCategoryService(t)
req := &CreateCategoryRequest{
Name: "Guides",
Slug: "guides",
Position: 0,
Locale: "en",
}
created, err := svc.Create(context.Background(), portalID, accountID, req)
require.NoError(t, err)
newPos := 5
newName := "User Guides"
newDescription := "Updated description"
newIcon := "📖"
newLocale := "zh"
updateReq := &UpdateCategoryRequest{
Name: &newName,
Description: &newDescription,
Icon: &newIcon,
Position: &newPos,
Locale: &newLocale,
}
updated, err := svc.Update(context.Background(), created.ID, updateReq)
require.NoError(t, err)
assert.Equal(t, "User Guides", updated.Name)
assert.Equal(t, "Updated description", updated.Description)
assert.Equal(t, "📖", updated.Icon)
assert.Equal(t, 5, updated.Position)
assert.Equal(t, "zh", updated.Locale)
}
func TestCategoryService_Update_NotFound(t *testing.T) {
svc, _, _ := setupCategoryService(t)
newPos := 1
newName := "Nonexistent"
updateReq := &UpdateCategoryRequest{
Name: &newName,
Position: &newPos,
}
updated, err := svc.Update(context.Background(), 99999, updateReq)
assert.Nil(t, updated)
assert.Error(t, err)
}
func TestCategoryService_Update_WithRelatedCategories(t *testing.T) {
svc, portalID, accountID := setupCategoryService(t)
// Create three categories in the same portal so related links can reference real IDs
cat1, err := svc.Create(context.Background(), portalID, accountID, &CreateCategoryRequest{
Name: "Cat1", Slug: "cat1", Locale: "en",
})
require.NoError(t, err)
cat2, err := svc.Create(context.Background(), portalID, accountID, &CreateCategoryRequest{
Name: "Cat2", Slug: "cat2", Locale: "en",
})
require.NoError(t, err)
cat3, err := svc.Create(context.Background(), portalID, accountID, &CreateCategoryRequest{
Name: "Cat3", Slug: "cat3", Locale: "en",
})
require.NoError(t, err)
// Update cat1 to have cat2 and cat3 as related categories
updateReq := &UpdateCategoryRequest{
RelatedCategoryIDs: []uint{cat2.ID, cat3.ID},
}
updated, err := svc.Update(context.Background(), cat1.ID, updateReq)
require.NoError(t, err)
assert.Equal(t, cat1.ID, updated.ID)
// Verify the related categories were saved by fetching the category again
fetched, err := svc.GetByID(context.Background(), cat1.ID)
require.NoError(t, err)
assert.Len(t, fetched.RelatedCategories, 2)
// Verify the related IDs match
relatedIDs := make([]uint, 0, len(fetched.RelatedCategories))
for _, rc := range fetched.RelatedCategories {
relatedIDs = append(relatedIDs, rc.RelatedCategoryID)
}
assert.Contains(t, relatedIDs, cat2.ID)
assert.Contains(t, relatedIDs, cat3.ID)
// Now update to replace with only cat3
updateReq2 := &UpdateCategoryRequest{
RelatedCategoryIDs: []uint{cat3.ID},
}
_, err = svc.Update(context.Background(), cat1.ID, updateReq2)
require.NoError(t, err)
fetched2, err := svc.GetByID(context.Background(), cat1.ID)
require.NoError(t, err)
assert.Len(t, fetched2.RelatedCategories, 1)
assert.Equal(t, cat3.ID, fetched2.RelatedCategories[0].RelatedCategoryID)
}
// ========== Delete ==========
func TestCategoryService_Delete(t *testing.T) {
svc, portalID, accountID := setupCategoryService(t)
req := &CreateCategoryRequest{
Name: "Temporary",
Slug: "temporary",
}
created, err := svc.Create(context.Background(), portalID, accountID, req)
require.NoError(t, err)
err = svc.Delete(context.Background(), created.ID)
require.NoError(t, err)
// Verify it's gone
category, err := svc.GetByID(context.Background(), created.ID)
assert.Error(t, err)
assert.Nil(t, category)
}
func TestCategoryService_Delete_NotFound(t *testing.T) {
svc, _, _ := setupCategoryService(t)
err := svc.Delete(context.Background(), 99999)
assert.Error(t, err)
}
func TestCategoryService_Delete_CleansUpRelatedCategories(t *testing.T) {
svc, portalID, accountID := setupCategoryService(t)
// Create two categories
cat1, err := svc.Create(context.Background(), portalID, accountID, &CreateCategoryRequest{
Name: "Main", Slug: "main", Locale: "en",
})
require.NoError(t, err)
cat2, err := svc.Create(context.Background(), portalID, accountID, &CreateCategoryRequest{
Name: "Related", Slug: "related", Locale: "en",
})
require.NoError(t, err)
// Link cat1 → cat2 as related
updateReq := &UpdateCategoryRequest{
RelatedCategoryIDs: []uint{cat2.ID},
}
_, err = svc.Update(context.Background(), cat1.ID, updateReq)
require.NoError(t, err)
// Delete cat1 — should clean up the related category link
err = svc.Delete(context.Background(), cat1.ID)
require.NoError(t, err)
// cat2 should still exist
cat2Fetched, err := svc.GetByID(context.Background(), cat2.ID)
require.NoError(t, err)
assert.Equal(t, cat2.ID, cat2Fetched.ID)
}
// ========== ListByPortalID ==========
func TestCategoryService_ListByPortalID(t *testing.T) {
svc, portalID, accountID := setupCategoryService(t)
// Create several categories with different positions
names := []string{"First", "Second", "Third"}
for i, name := range names {
_, err := svc.Create(context.Background(), portalID, accountID, &CreateCategoryRequest{
Name: name,
Slug: name,
Position: i + 1,
Locale: "en",
})
require.NoError(t, err)
}
// List page 1, perPage 2
categories, count, err := svc.ListByPortalID(context.Background(), portalID, "", 1, 2)
require.NoError(t, err)
assert.Equal(t, int64(3), count)
assert.Len(t, categories, 2)
// List page 2, perPage 2
categories2, count2, err := svc.ListByPortalID(context.Background(), portalID, "", 2, 2)
require.NoError(t, err)
assert.Equal(t, int64(3), count2)
assert.Len(t, categories2, 1)
// List all at once
categories3, count3, err := svc.ListByPortalID(context.Background(), portalID, "", 1, 10)
require.NoError(t, err)
assert.Equal(t, int64(3), count3)
assert.Len(t, categories3, 3)
// Verify ordering by position
assert.Equal(t, "First", categories3[0].Name)
assert.Equal(t, "Second", categories3[1].Name)
assert.Equal(t, "Third", categories3[2].Name)
}
func TestCategoryService_ListByPortalID_WithLocale(t *testing.T) {
svc, portalID, accountID := setupCategoryService(t)
// Create categories with different locales
_, err := svc.Create(context.Background(), portalID, accountID, &CreateCategoryRequest{
Name: "English Cat", Slug: "english-cat", Locale: "en",
})
require.NoError(t, err)
_, err = svc.Create(context.Background(), portalID, accountID, &CreateCategoryRequest{
Name: "Chinese Cat", Slug: "chinese-cat", Locale: "zh",
})
require.NoError(t, err)
_, err = svc.Create(context.Background(), portalID, accountID, &CreateCategoryRequest{
Name: "Another English", Slug: "another-english", Locale: "en",
})
require.NoError(t, err)
// Filter by locale "en"
categories, count, err := svc.ListByPortalID(context.Background(), portalID, "en", 1, 10)
require.NoError(t, err)
assert.Equal(t, int64(2), count)
assert.Len(t, categories, 2)
for _, cat := range categories {
assert.Equal(t, "en", cat.Locale)
}
}