Files

132 lines
3.8 KiB
Go

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 := "<!-- spx-state\n{\"branch\":\"feat/x\",\"column\":\"review\"}\n-->"
if body != want {
t.Fatalf("got %q\nwant %q", body, want)
}
}
func TestFormatCommentEscapesCommentTerminators(t *testing.T) {
raw := "a --> b <!-- c & d"
body, err := FormatComment(map[string]any{"handoffRequestError": raw})
if err != nil {
t.Fatalf("FormatComment 出错: %v", err)
}
inner := strings.TrimSuffix(strings.TrimPrefix(body, "<!-- spx-state\n"), "\n-->")
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{
"隐藏注释": "<!-- spx-state\n{\"column\":\"review\"}\n-->",
"隐藏注释带首尾空白": " \n<!-- spx-state\n{\"column\":\"review\"}\n-->\n ",
"旧 YouTrack 格式": "<!--spx-state-->\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"`,
"<!-- spx-state\n{\"column\":\"review\"}",
"<!-- spx-state\n[1]\n-->",
"<!-- spx-state\n{\"foo\":1}\n-->",
"<!--spx-state-->\n{\"foo\":1}",
"状态如下: {\"column\":\"review\"}",
"<!-- spx:review=1 -->\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"}`,
"<!--spx-state-->\n{\"column\":\"in-progress\"}",
"<!-- spx-state\n{\"column\":\"review\",\"branch\":\"new\"}\n-->",
"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")
}
}