package report import ( "bytes" "encoding/json" "os" "path/filepath" "strings" "testing" ) func TestNormalizeFillsMissingAsUntested(t *testing.T) { t.Parallel() items, err := Normalize(Results{Items: []Item{ {ID: "F01", Status: StatusPass, Note: "ok"}, {ID: "f08", Status: "失败", Note: "flaky"}, }}) if err != nil { t.Fatal(err) } if len(items) != 23 { t.Fatalf("len=%d", len(items)) } if items[0].Status != StatusPass || items[0].Note != "ok" { t.Fatalf("F01=%+v", items[0]) } if items[7].Status != StatusFail { t.Fatalf("F08=%+v", items[7]) } if items[22].Status != StatusUntested { t.Fatalf("F23=%+v", items[22]) } } func TestWriteMarkdownSample(t *testing.T) { t.Parallel() path := filepath.Join("testdata", "sample_results.json") r, err := LoadResults(path) if err != nil { t.Fatal(err) } items, err := Normalize(r) if err != nil { t.Fatal(err) } var buf bytes.Buffer if err := WriteMarkdown(&buf, items); err != nil { t.Fatal(err) } out := buf.String() for _, id := range []string{"F01", "F12", "F23"} { if !strings.Contains(out, id) { t.Fatalf("missing %s in:\n%s", id, out) } } if !strings.Contains(out, "未测") { t.Fatalf("expected 未测:\n%s", out) } if !strings.Contains(out, "通过 0,部分通过 0,失败 0,未测 23") { t.Fatalf("summary mismatch:\n%s", out) } } func TestCatalogHonestSummary(t *testing.T) { t.Parallel() items := CatalogItems() if len(items) != 23 { t.Fatalf("len=%d", len(items)) } var pass, partial, fail, untested int for _, it := range items { if it.Status == StatusPass && it.Total > 0 { if it.Passed != it.Total { t.Fatalf("%s pass but %d/%d", it.ID, it.Passed, it.Total) } } if it.Status == StatusPartial { if it.Passed == it.Total || it.Passed == 0 { t.Fatalf("%s partial but %d/%d", it.ID, it.Passed, it.Total) } } switch it.Status { case StatusPass: pass++ case StatusPartial: partial++ case StatusFail: fail++ default: untested++ } } if pass != 19 || partial != 4 || fail != 0 || untested != 0 { t.Fatalf("pass=%d partial=%d fail=%d untested=%d", pass, partial, fail, untested) } wantPartial := map[string]bool{"F03": true, "F08": true, "F21": true, "F22": true} for _, it := range items { if wantPartial[it.ID] && it.Status != StatusPartial { t.Fatalf("%s want partial got %s", it.ID, it.Status) } if !wantPartial[it.ID] && it.Status != StatusPass { t.Fatalf("%s want pass got %s", it.ID, it.Status) } } } func TestReconcileLiveFailWins(t *testing.T) { t.Parallel() out := Reconcile([]Item{{ID: "F04", Status: StatusFail, Note: "probe failed"}}) var f04 Item for _, it := range out { if it.ID == "F04" { f04 = it break } } if f04.Status != StatusFail || f04.Note != "probe failed" { t.Fatalf("F04=%+v", f04) } } func TestRollupPartial(t *testing.T) { t.Parallel() it := Rollup(Item{ID: "X", Subs: []SubItem{ {ID: "Xa", Status: StatusPass}, {ID: "Xb", Status: StatusUntested, Note: "skip"}, }}) if it.Status != StatusPartial || it.Passed != 1 || it.Total != 2 { t.Fatalf("%+v", it) } } func TestEmptyResultsRoundTrip(t *testing.T) { t.Parallel() dir := t.TempDir() path := filepath.Join(dir, "empty.json") raw, err := json.MarshalIndent(EmptyResults(), "", " ") if err != nil { t.Fatal(err) } if writeErr := os.WriteFile(path, raw, 0o644); writeErr != nil { t.Fatal(writeErr) } r, err := LoadResults(path) if err != nil { t.Fatal(err) } if len(r.Items) != 23 { t.Fatalf("items=%d", len(r.Items)) } } func TestWriteCatalogArtifacts(t *testing.T) { if os.Getenv("NIXMSG_WRITE_ACCEPT_REPORT") != "1" { t.Skip("set NIXMSG_WRITE_ACCEPT_REPORT=1 to rewrite ACCEPTANCE.md") } dir, wdErr := os.Getwd() if wdErr != nil { t.Fatal(wdErr) } for { if _, stErr := os.Stat(filepath.Join(dir, "go.mod")); stErr == nil { break } parent := filepath.Dir(dir) if parent == dir { t.Fatal("go.mod not found") } dir = parent } r := CatalogResults() raw, marshErr := json.MarshalIndent(r, "", " ") if marshErr != nil { t.Fatal(marshErr) } jsonPath := filepath.Join(dir, "test", "report", "testdata", "q2_results.json") if writeErr := os.WriteFile(jsonPath, append(raw, '\n'), 0o644); writeErr != nil { t.Fatal(writeErr) } items, normErr := Normalize(r) if normErr != nil { t.Fatal(normErr) } var buf bytes.Buffer if mdErr := WriteMarkdown(&buf, items); mdErr != nil { t.Fatal(mdErr) } mdPath := filepath.Join(dir, "test", "accept", "ACCEPTANCE.md") if writeMD := os.WriteFile(mdPath, buf.Bytes(), 0o644); writeMD != nil { t.Fatal(writeMD) } } func TestParseStatusRejectsUnknown(t *testing.T) { t.Parallel() if _, err := Normalize(Results{Items: []Item{{ID: "F01", Status: "maybe"}}}); err == nil { t.Fatal("expected error") } }