package state import ( "encoding/json" "fmt" "strings" "testing" ) func TestFormatCommentWrapsCompactJSONInHiddenComment(t *testing.T) { body, err := FormatComment(map[string]any{"column": "review", "branch": "feat/x"}) if err != nil { t.Fatalf("FormatComment 出错: %v", err) } want := "" if body != want { t.Fatalf("got %q\nwant %q", body, want) } } func TestFormatCommentEscapesCommentTerminators(t *testing.T) { raw := "a --> b ") if inner == body { t.Fatalf("输出不是隐藏注释格式: %q", body) } if strings.Contains(inner, "-->") || strings.ContainsAny(inner, "<>&") { t.Fatalf("JSON 正文里不应出现 `-->` 或裸的 < > &: %q", inner) } for _, esc := range []string{`\u003c`, `\u003e`, `\u0026`} { if !strings.Contains(inner, esc) { t.Fatalf("JSON 正文应把字符转义成 %s: %q", esc, inner) } } got, ok := ParseComment(body) if !ok { t.Fatalf("自己写出的评论应能读回: %q", body) } if got["handoffRequestError"] != raw { t.Fatalf("往返后值变了: got %q want %q", got["handoffRequestError"], raw) } } func TestParseCommentAcceptsAllThreeFormats(t *testing.T) { cases := map[string]string{ "隐藏注释": "", "隐藏注释带首尾空白": " \n\n ", "旧 YouTrack 格式": "\n{\"column\":\"review\"}", "旧裸 JSON": `{"column":"review"}`, "旧裸 JSON 带空白": "\n {\"column\":\"review\"} \n", } for name, body := range cases { t.Run(name, func(t *testing.T) { m, ok := ParseComment(body) if !ok { t.Fatalf("应当识别为 state 评论: %q", body) } if m["column"] != "review" { t.Fatalf("column 解析错误: %v", m) } }) } } func TestParseCommentRejectsNonStateBodies(t *testing.T) { bad := []string{ "", "LGTM", `{"foo":1}`, `["column"]`, `null`, `"column"`, "", "", "\n{\"foo\":1}", "状态如下: {\"column\":\"review\"}", "\n\nLGTM", } for _, body := range bad { if m, ok := ParseComment(body); ok { t.Fatalf("不应识别为 state 评论: %q -> %v", body, m) } } } func TestParseCommentKnowsEverySchemaProperty(t *testing.T) { var doc struct { Properties map[string]json.RawMessage `json:"properties"` } if err := json.Unmarshal(schemaBytes, &doc); err != nil { t.Fatalf("解析内嵌 schema 失败: %v", err) } if len(doc.Properties) == 0 { t.Fatal("内嵌 schema 没有 properties") } for name := range doc.Properties { body := fmt.Sprintf(`{%q:null}`, name) if _, ok := ParseComment(body); !ok { t.Errorf("schema 字段 %s 应当被识别为 state 字段", name) } } } func TestLatestPicksNewestValidStateComment(t *testing.T) { bodies := []string{ `{"column":"todo","branch":"old"}`, "\n{\"column\":\"in-progress\"}", "", "LGTM", `{"unrelated":true}`, } got := Latest(bodies) if got["column"] != "review" || got["branch"] != "new" { t.Fatalf("应取最新一条有效 state,得到 %v", got) } } func TestLatestReturnsEmptyMapWhenNoState(t *testing.T) { got := Latest([]string{"hello", `{"x":1}`}) if got == nil || len(got) != 0 { t.Fatalf("没有 state 时应返回非 nil 空 map,得到 %#v", got) } if got := Latest(nil); got == nil { t.Fatal("空评论列表也应返回非 nil 空 map") } }