package service import ( "context" "testing" "github.com/gochat/gochat/internal/model" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) // ========== Create 测试 ========== func TestCaptainDocumentService_Create_成功(t *testing.T) { db, _, svc := setupCaptainDocumentService(t) account := createTestAccount(t, db) req := &CreateDocumentRequest{ Name: "测试文档", ExternalLink: "https://example.com/doc1", } doc, err := svc.Create(context.Background(), 1, account.ID, req) require.NoError(t, err) assert.NotZero(t, doc.ID) assert.Equal(t, "测试文档", doc.Name) assert.Equal(t, "https://example.com/doc1", doc.ExternalLink) assert.Equal(t, account.ID, doc.AccountID) assert.Equal(t, uint(1), doc.AssistantID) assert.Equal(t, model.DocumentStatusPending, doc.Status) } func TestCaptainDocumentService_Create_相同AssistantID多个文档(t *testing.T) { db, _, svc := setupCaptainDocumentService(t) account := createTestAccount(t, db) req1 := &CreateDocumentRequest{ Name: "文档A", ExternalLink: "https://example.com/a", } req2 := &CreateDocumentRequest{ Name: "文档B", ExternalLink: "https://example.com/b", } doc1, err := svc.Create(context.Background(), 1, account.ID, req1) require.NoError(t, err) doc2, err := svc.Create(context.Background(), 1, account.ID, req2) require.NoError(t, err) assert.NotEqual(t, doc1.ID, doc2.ID) assert.Equal(t, "文档A", doc1.Name) assert.Equal(t, "文档B", doc2.Name) } // ========== Get 测试 ========== func TestCaptainDocumentService_Get_成功(t *testing.T) { db, _, svc := setupCaptainDocumentService(t) account := createTestAccount(t, db) doc := createTestCaptainDocument(t, db, account.ID, 1, "获取测试文档", "https://example.com/get") result, err := svc.Get(context.Background(), doc.ID) require.NoError(t, err) assert.Equal(t, doc.ID, result.ID) assert.Equal(t, "获取测试文档", result.Name) assert.Equal(t, "https://example.com/get", result.ExternalLink) assert.Equal(t, account.ID, result.AccountID) } func TestCaptainDocumentService_Get_不存在(t *testing.T) { _, _, svc := setupCaptainDocumentService(t) result, err := svc.Get(context.Background(), 9999) assert.Error(t, err) assert.Nil(t, result) } // ========== Update 测试 ========== func TestCaptainDocumentService_Update_修改Name(t *testing.T) { db, _, svc := setupCaptainDocumentService(t) account := createTestAccount(t, db) doc := createTestCaptainDocument(t, db, account.ID, 1, "原名", "https://example.com/update") req := &UpdateDocumentRequest{ Name: "新名称", } updated, err := svc.Update(context.Background(), doc.ID, req) require.NoError(t, err) assert.Equal(t, "新名称", updated.Name) assert.Equal(t, "https://example.com/update", updated.ExternalLink) // 未修改字段保持原值 } func TestCaptainDocumentService_Update_修改ExternalLink(t *testing.T) { db, _, svc := setupCaptainDocumentService(t) account := createTestAccount(t, db) doc := createTestCaptainDocument(t, db, account.ID, 1, "文档名", "https://old.example.com") req := &UpdateDocumentRequest{ ExternalLink: "https://new.example.com", } updated, err := svc.Update(context.Background(), doc.ID, req) require.NoError(t, err) assert.Equal(t, "文档名", updated.Name) // 未修改字段保持原值 assert.Equal(t, "https://new.example.com", updated.ExternalLink) } func TestCaptainDocumentService_Update_同时修改Name和ExternalLink(t *testing.T) { db, _, svc := setupCaptainDocumentService(t) account := createTestAccount(t, db) doc := createTestCaptainDocument(t, db, account.ID, 1, "旧名", "https://old.example.com") req := &UpdateDocumentRequest{ Name: "新名", ExternalLink: "https://new.example.com", } updated, err := svc.Update(context.Background(), doc.ID, req) require.NoError(t, err) assert.Equal(t, "新名", updated.Name) assert.Equal(t, "https://new.example.com", updated.ExternalLink) } func TestCaptainDocumentService_Update_不存在(t *testing.T) { _, _, svc := setupCaptainDocumentService(t) req := &UpdateDocumentRequest{Name: "新名称"} updated, err := svc.Update(context.Background(), 9999, req) assert.Error(t, err) assert.Nil(t, updated) } func TestCaptainDocumentService_Update_空请求不修改字段(t *testing.T) { db, _, svc := setupCaptainDocumentService(t) account := createTestAccount(t, db) doc := createTestCaptainDocument(t, db, account.ID, 1, "原始名", "https://original.example.com") req := &UpdateDocumentRequest{} // 两个字段都为空 updated, err := svc.Update(context.Background(), doc.ID, req) require.NoError(t, err) assert.Equal(t, "原始名", updated.Name) assert.Equal(t, "https://original.example.com", updated.ExternalLink) } // ========== Delete 测试 ========== func TestCaptainDocumentService_Delete_成功(t *testing.T) { db, _, svc := setupCaptainDocumentService(t) account := createTestAccount(t, db) doc := createTestCaptainDocument(t, db, account.ID, 1, "删除测试", "https://example.com/delete") err := svc.Delete(context.Background(), doc.ID) require.NoError(t, err) // 验证删除后无法获取 result, err := svc.Get(context.Background(), doc.ID) assert.Error(t, err) assert.Nil(t, result) } func TestCaptainDocumentService_Delete_不存在(t *testing.T) { _, _, svc := setupCaptainDocumentService(t) // 删除不存在的文档不会返回错误(GORM Delete 对不存在记录不报错) err := svc.Delete(context.Background(), 9999) // GORM 删除不存在的记录返回 0 rows affected 但不报错 assert.NoError(t, err) } // ========== List 测试 ========== func TestCaptainDocumentService_List_成功(t *testing.T) { db, _, svc := setupCaptainDocumentService(t) account := createTestAccount(t, db) // 创建3个文档属于同一assistant createTestCaptainDocument(t, db, account.ID, 1, "文档1", "https://example.com/1") createTestCaptainDocument(t, db, account.ID, 1, "文档2", "https://example.com/2") createTestCaptainDocument(t, db, account.ID, 1, "文档3", "https://example.com/3") docs, count, err := svc.List(context.Background(), 1, 0, 10) require.NoError(t, err) assert.Equal(t, int64(3), count) assert.Len(t, docs, 3) } func TestCaptainDocumentService_List_分页(t *testing.T) { db, _, svc := setupCaptainDocumentService(t) account := createTestAccount(t, db) // 创建5个文档 for i := 0; i < 5; i++ { createTestCaptainDocument(t, db, account.ID, 1, "文档"+string(rune('A'+i)), "https://example.com/"+string(rune('A'+i))) } // 获取第一页(2条) docs, count, err := svc.List(context.Background(), 1, 0, 2) require.NoError(t, err) assert.Equal(t, int64(5), count) assert.Len(t, docs, 2) // 获取第二页(2条) docs2, count2, err := svc.List(context.Background(), 1, 2, 2) require.NoError(t, err) assert.Equal(t, int64(5), count2) assert.Len(t, docs2, 2) } func TestCaptainDocumentService_List_空结果(t *testing.T) { _, _, svc := setupCaptainDocumentService(t) // 查询不存在的assistantID docs, count, err := svc.List(context.Background(), 9999, 0, 10) require.NoError(t, err) assert.Equal(t, int64(0), count) assert.Len(t, docs, 0) } func TestCaptainDocumentService_List_不同AssistantID隔离(t *testing.T) { db, _, svc := setupCaptainDocumentService(t) account := createTestAccount(t, db) // assistant 1 有2个文档 createTestCaptainDocument(t, db, account.ID, 1, "助手1文档A", "https://example.com/a1") createTestCaptainDocument(t, db, account.ID, 1, "助手1文档B", "https://example.com/b1") // assistant 2 有1个文档 createTestCaptainDocument(t, db, account.ID, 2, "助手2文档A", "https://example.com/a2") // 查询assistant 1 docs1, count1, err := svc.List(context.Background(), 1, 0, 10) require.NoError(t, err) assert.Equal(t, int64(2), count1) assert.Len(t, docs1, 2) // 查询assistant 2 docs2, count2, err := svc.List(context.Background(), 2, 0, 10) require.NoError(t, err) assert.Equal(t, int64(1), count2) assert.Len(t, docs2, 1) } // ========== ProcessDocument 测试 ========== func TestCaptainDocumentService_ProcessDocument_不存在(t *testing.T) { _, _, svc := setupCaptainDocumentService(t) err := svc.ProcessDocument(context.Background(), 9999) assert.Error(t, err) } // ========== SyncDocument 测试 ========== func TestCaptainDocumentService_SyncDocument_不存在(t *testing.T) { _, _, svc := setupCaptainDocumentService(t) err := svc.SyncDocument(context.Background(), 9999) assert.Error(t, err) } // ========== computeFingerprint 测试 ========== func TestComputeFingerprint_一致性(t *testing.T) { content := "Hello, World!" fp1 := computeFingerprint(content) fp2 := computeFingerprint(content) assert.Equal(t, fp1, fp2) // 相同内容应产生相同指纹 } func TestComputeFingerprint_不同内容不同指纹(t *testing.T) { fp1 := computeFingerprint("Content A") fp2 := computeFingerprint("Content B") assert.NotEqual(t, fp1, fp2) // 不同内容应产生不同指纹 } func TestComputeFingerprint_空字符串(t *testing.T) { fp := computeFingerprint("") assert.NotEmpty(t, fp) // 空字符串也应产生指纹(SHA256 of empty bytes) }