First Commit
ci / go (push) Waiting to run
ci / go-db (agent) (push) Waiting to run
ci / go-db (config) (push) Waiting to run
ci / go-db (db) (push) Waiting to run
ci / go-db (evidence) (push) Waiting to run
ci / go-db (llmrec) (push) Waiting to run
ci / go-db (server) (push) Waiting to run
web / web (push) Waiting to run
docs / links (push) Canceled after 0s
detections / detections (push) Canceled after 0s

This commit is contained in:
dela
2026-10-09 08:38:16 +08:00
commit 0335d572de
756 changed files with 201663 additions and 0 deletions
+72
View File
@@ -0,0 +1,72 @@
package server
import (
"fmt"
"net/http/httptest"
"net/url"
"strings"
"testing"
)
// TestChatMentionErrorsLocalized guards F3b chat_mentions.go: every user-facing
// @멘션(인용) error response must be Korean (Hangul present, no Chinese Han). The
// wire token labels (chatMentionPattern·chatMentionKinds), the agent-input
// snapshot header, and the truncation markers fed into that snapshot stay in the
// original language by design and are intentionally not checked here.
func TestChatMentionErrorsLocalized(t *testing.T) {
// Fixed user-facing literals.
for label, msg := range map[string]string{
"badID": errChatMentionBadID,
"tooMany": errChatMentionTooMany,
"badSearch": errChatMentionBadSearch,
"dataUnavail": errChatMentionDataUnavail,
"tooLarge": errChatMentionTooLarge,
} {
assertKoreanError(t, label, msg)
}
// parseChatMentions — a non-positive id inside a valid wire token.
if _, err := parseChatMentions("@[漏洞#0]"); err == nil {
t.Fatal("잘못된 인용 ID 가 통과해서는 안 됩니다")
} else {
assertKoreanError(t, "parse.badID", err.Error())
}
// parseChatMentions — exceeding the per-message mention cap (11 distinct ids).
var b strings.Builder
for i := 1; i <= 11; i++ {
fmt.Fprintf(&b, "@[漏洞#%d] ", i)
}
if _, err := parseChatMentions(b.String()); err == nil {
t.Fatal("인용 상한 초과가 통과해서는 안 됩니다")
} else {
assertKoreanError(t, "parse.tooMany", err.Error())
}
// composeChatMentionMessage — a mention is present but the database is nil.
if _, err := composeChatMentionMessage(nil, "@[漏洞#1]"); err == nil {
t.Fatal("DB 없이 인용 해석이 통과해서는 안 됩니다")
} else {
assertKoreanError(t, "compose.dataUnavail", err.Error())
}
// searchChatMentions — invalid kind and over-long query are rejected before
// the database handle is touched, so &Server{} is enough to reach the branch.
for _, q := range []string{"kind=unsupported", "q=" + url.QueryEscape(strings.Repeat("字", 201))} {
w := httptest.NewRecorder()
(&Server{}).searchChatMentions(w, httptest.NewRequest("GET", "/api/chat/mentions?"+q, nil))
if w.Code != 400 {
t.Fatalf("검증 실패(400)를 기대했으나 %d 가 반환되었습니다 (%s)", w.Code, q)
}
assertKoreanError(t, "search."+q, decodeErrorField(t, w.Body.Bytes()))
}
// The display label map mirrors the UI mention kinds, and the not-found
// template resolves to a fully Korean message for a known kind.
for _, kind := range []string{"finding", "asset", "company", "endpoint", "ip", "app", "root_domain", "subdomain", "service"} {
if chatMentionKindLabel[kind] == "" {
t.Fatalf("종류 라벨이 누락되었습니다: %s", kind)
}
}
assertKoreanError(t, "notFound", fmt.Sprintf(errChatMentionNotFoundFmt, chatMentionKindLabel["finding"], 7))
}