Files
agentic-coding-workflow/internal/run/exec_parsers_test.go
T
2026-06-22 08:55:57 +08:00

130 lines
3.7 KiB
Go

package run
import (
"os"
"path/filepath"
"testing"
)
func readFixture(t *testing.T, name string) []byte {
t.Helper()
b, err := os.ReadFile(filepath.Join("testdata", name))
if err != nil {
t.Fatalf("read fixture %s: %v", name, err)
}
return b
}
func TestParseGoTestJSON(t *testing.T) {
sum, err := parseGoTestJSON(readFixture(t, "gotest.jsonl"))
if err != nil {
t.Fatalf("parse: %v", err)
}
if sum.Framework != "gotest" {
t.Fatalf("framework = %q", sum.Framework)
}
if sum.Passed != 1 || sum.Failed != 1 || sum.Skipped != 1 || sum.Total != 3 {
t.Fatalf("counts p=%d f=%d s=%d t=%d", sum.Passed, sum.Failed, sum.Skipped, sum.Total)
}
if len(sum.Failures) != 1 || sum.Failures[0].Name != "TestFail" || sum.Failures[0].Package != "example/pkg" {
t.Fatalf("failures = %+v", sum.Failures)
}
if sum.Failures[0].Message == "" {
t.Fatal("failure message should not be empty")
}
}
func TestParseJUnitXML(t *testing.T) {
sum, err := parseJUnitXML(readFixture(t, "junit.xml"))
if err != nil {
t.Fatalf("parse: %v", err)
}
if sum.Framework != "junit" {
t.Fatalf("framework = %q", sum.Framework)
}
if sum.Passed != 1 || sum.Failed != 1 || sum.Skipped != 1 || sum.Total != 3 {
t.Fatalf("counts p=%d f=%d s=%d t=%d", sum.Passed, sum.Failed, sum.Skipped, sum.Total)
}
if len(sum.Failures) != 1 || sum.Failures[0].Name != "testFails" {
t.Fatalf("failures = %+v", sum.Failures)
}
if sum.Failures[0].Message != "expected true but was false" {
t.Fatalf("failure message = %q", sum.Failures[0].Message)
}
}
func TestParseVitestJSON(t *testing.T) {
sum, err := parseVitestJSON(readFixture(t, "vitest.json"))
if err != nil {
t.Fatalf("parse: %v", err)
}
if sum.Framework != "vitest" {
t.Fatalf("framework = %q", sum.Framework)
}
if sum.Passed != 1 || sum.Failed != 1 || sum.Skipped != 1 || sum.Total != 3 {
t.Fatalf("counts p=%d f=%d s=%d t=%d", sum.Passed, sum.Failed, sum.Skipped, sum.Total)
}
if len(sum.Failures) != 1 || sum.Failures[0].Name != "sum > subtracts" {
t.Fatalf("failures = %+v", sum.Failures)
}
if sum.Failures[0].Message != "expected 1 to be 2" {
t.Fatalf("failure message = %q", sum.Failures[0].Message)
}
}
// TestParseTestOutput_Auto 验证 auto 嗅探把各格式路由到正确解析器。
func TestParseTestOutput_Auto(t *testing.T) {
cases := []struct {
name string
fixture string
want string
}{
{"gotest", "gotest.jsonl", "gotest"},
{"junit", "junit.xml", "junit"},
{"vitest", "vitest.json", "vitest"},
}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
sum, err := parseTestOutput("auto", string(readFixture(t, tc.fixture)), "")
if err != nil {
t.Fatalf("parse: %v", err)
}
if sum.Framework != tc.want {
t.Fatalf("framework = %q, want %q", sum.Framework, tc.want)
}
})
}
}
// TestParseTestOutput_Malformed 验证解析失败返回 error(由 RunTests 折成 ParseError),
// 永不 panic。
func TestParseTestOutput_Malformed(t *testing.T) {
cases := []struct {
format string
in string
}{
{"gotest", "not json at all"},
{"junit", "<broken><xml"},
{"vitest", "{not valid"},
{"auto", ""},
{"auto", "random text with no structure"},
}
for _, tc := range cases {
_, err := parseTestOutput(tc.format, tc.in, "")
if err == nil {
t.Fatalf("format %q input %q: expected parse error, got nil", tc.format, tc.in)
}
}
}
// TestParseGoTestJSON_StderrFallback 验证 stdout 为空时退回 stderr。
func TestParseTestOutput_StderrFallback(t *testing.T) {
sum, err := parseTestOutput("auto", "", string(readFixture(t, "gotest.jsonl")))
if err != nil {
t.Fatalf("parse: %v", err)
}
if sum.Framework != "gotest" || sum.Total != 3 {
t.Fatalf("got %+v", sum)
}
}