316 lines
9.1 KiB
Go
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)
|
|
}
|
|
}
|