package docgov_test import ( "errors" "os" "path/filepath" "testing" "chat-agent-system/internal/docgov" ) func TestReadDocumentContent_TypedErrors(t *testing.T) { ctx := t.Context() eng := docgov.NewGovernanceEngine(nil) _, err := eng.ReadDocumentContent(ctx, "doc_missing", t.TempDir()) if !errors.Is(err, docgov.ErrDocumentNotFound) { t.Fatalf("not-found: %v", err) } var nf *docgov.ContentError if !errors.As(err, &nf) || nf.Code != docgov.ErrCodeDocumentNotFound { t.Fatalf("not-found code: %v", err) } dir := t.TempDir() if _, err := eng.CreateOrGetDocument(ctx, "doc_nofile", 1, "intake", "t", "V0.1", filepath.Join(dir, "missing-ws"), 1, "a", 2, "r", 3, "p"); err != nil { t.Fatal(err) } _, err = eng.ReadDocumentContent(ctx, "doc_nofile", dir) var miss *docgov.ContentError if !errors.As(err, &miss) || miss.Code != docgov.ErrCodeProjectionMissing { t.Fatalf("missing: %v", err) } if !miss.Retryable || !miss.NeedsAdmin { t.Fatalf("missing flags %+v", miss) } emptyDir := filepath.Join(dir, "empty-ws") if err := os.MkdirAll(emptyDir, 0o755); err != nil { t.Fatal(err) } if err := os.WriteFile(filepath.Join(emptyDir, "output.md"), nil, 0o644); err != nil { t.Fatal(err) } if _, err := eng.CreateOrGetDocument(ctx, "doc_empty", 1, "intake", "t", "V0.1", emptyDir, 1, "a", 2, "r", 3, "p"); err != nil { t.Fatal(err) } _, err = eng.ReadDocumentContent(ctx, "doc_empty", dir) var empty *docgov.ContentError if !errors.As(err, &empty) || empty.Code != docgov.ErrCodeProjectionEmpty { t.Fatalf("empty: %v", err) } ws := filepath.Join(dir, "mismatch-ws") if err := os.MkdirAll(ws, 0o755); err != nil { t.Fatal(err) } if err := os.WriteFile(filepath.Join(ws, "output.md"), []byte("file-bytes\n"), 0o644); err != nil { t.Fatal(err) } if _, err := eng.CreateOrGetDocument(ctx, "doc_mismatch", 1, "intake", "t", "V0.1", ws, 1, "a", 2, "r", 3, "p"); err != nil { t.Fatal(err) } if err := eng.MarkDocumentContentUpdated(ctx, "doc_mismatch", "deadbeef", false); err != nil { t.Fatal(err) } _, err = eng.ReadDocumentContent(ctx, "doc_mismatch", dir) var mm *docgov.ContentError if !errors.As(err, &mm) || mm.Code != docgov.ErrCodeIntegrityMismatch { t.Fatalf("mismatch: %v", err) } if mm.Retryable || !mm.NeedsAdmin { t.Fatalf("mismatch flags %+v", mm) } } func TestSaveDocumentContent_CanonicalBytesMatchHash(t *testing.T) { ctx := t.Context() dir := t.TempDir() ws := filepath.Join(dir, "ws") if err := os.MkdirAll(ws, 0o755); err != nil { t.Fatal(err) } eng := docgov.NewGovernanceEngine(nil) if _, err := eng.CreateOrGetDocument(ctx, "doc_save", 1, "intake", "t", "V0.1", ws, 9, "a", 2, "r", 3, "p"); err != nil { t.Fatal(err) } res, err := eng.SaveDocumentContent(ctx, docgov.ContentSaveRequest{ DocID: "doc_save", ActorID: 9, ActorRole: docgov.RoleAuthor, ActorName: "a", MarkdownBody: "标题 \r\n下一行\r\n", }) if err != nil { t.Fatal(err) } got, err := os.ReadFile(filepath.Join(ws, "output.md")) if err != nil { t.Fatal(err) } if string(got) != "标题 \n下一行\n" { t.Fatalf("saved bytes %q", got) } if res.ContentSHA256 == "" || res.ContentSHA256 != res.Doc.ContentSHA256 { t.Fatalf("sha not synced: %+v", res) } }