80 lines
3.5 KiB
Go
80 lines
3.5 KiB
Go
package reporting
|
||
|
||
import (
|
||
"bytes"
|
||
"os"
|
||
"path/filepath"
|
||
"strings"
|
||
"testing"
|
||
"time"
|
||
|
||
"gopkg.in/yaml.v3"
|
||
)
|
||
|
||
func TestMarkdownFixedLayoutAndCounts(t *testing.T) {
|
||
one, two, three, four, zero := 1, 2, 3, 4, 0
|
||
snapshot := Snapshot{
|
||
RunID: "run-123", Status: StatusCompleted, StartedAt: time.Date(2026, 9, 24, 10, 0, 0, 0, time.UTC),
|
||
TranscriptPath: "in|put.json", GlossaryPath: "glossary`secret`.yaml", OutputPath: "out\nfile.json",
|
||
StageNames: []string{"grammar_1", "grammar_2"},
|
||
WorkUnits: []WorkUnit{
|
||
{StageIndex: 0, ModuleInstance: "grammar_1", ChunkIndex: 0, StartSegmentID: 1, EndSegmentID: 2, State: "completed", ErrorCount: 1, RecoveryCount: 1, CorrectionsApplied: 1},
|
||
{StageIndex: 1, ModuleInstance: "grammar_2", ChunkIndex: 0, StartSegmentID: 1, EndSegmentID: 2, State: "interrupted", RecoveryCount: 2},
|
||
{StageIndex: 0, ModuleInstance: "grammar_1", ChunkIndex: 1, StartSegmentID: 3, EndSegmentID: 4, State: "completed"},
|
||
{StageIndex: 1, ModuleInstance: "grammar_2", ChunkIndex: 1, StartSegmentID: 3, EndSegmentID: 4, State: "not_started"},
|
||
},
|
||
Summary: Summary{WorkUnitsTotal: &four, WorkUnitsCompleted: &two, WorkUnitsInterrupted: &one, WorkUnitsNotStarted: &one,
|
||
WorkUnitsWithErrors: &one, RunErrors: &zero, CorrectionsApplied: &one, LLMOperations: &four,
|
||
ProposalResponses: &one, ProposalResponsesWithFiltering: &one, Recoveries: &three},
|
||
Errors: []ErrorRecord{{Scope: "work_unit", Failures: []Failure{{Reason: "transport_failed"}, {Reason: "transport_failed"}}}},
|
||
Recoveries: []RecoveryRecord{{Reasons: []string{"output_repaired", "proposals_filtered"}}, {Reasons: []string{"output_repaired"}}, {Reasons: []string{"service_recovered"}}},
|
||
}
|
||
got := Markdown(snapshot, "secret")
|
||
fixture := filepath.Join("testdata", "report.md")
|
||
if os.Getenv("UPDATE_REPORT_GOLDEN") == "1" {
|
||
if err := os.WriteFile(fixture, got, 0600); err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
}
|
||
want, err := os.ReadFile(fixture)
|
||
if err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
if !bytes.Equal(got, want) {
|
||
t.Fatalf("Markdown differs from %s:\n%s", fixture, got)
|
||
}
|
||
text := string(got)
|
||
for _, fragment := range []string{"| grammar_1 | grammar_2 |", "| Chunk 1 (segments 1–2) | 1 | 0* |", "| Chunk 1 (segments 1–2) | 1 | 2* |", "| Chunk 2 (segments 3–4) | 0 | — |", "in\\|put.json", "out<br>file.json", "glossary\\`[REDACTED]\\`.yaml", "- `transport_failed`: 1", "- `output_repaired`: 2"} {
|
||
if !strings.Contains(text, fragment) {
|
||
t.Fatalf("missing %q in:\n%s", fragment, text)
|
||
}
|
||
}
|
||
if strings.Contains(text, "secret") {
|
||
t.Fatal("secret leaked")
|
||
}
|
||
var decoded struct {
|
||
Summary Summary `yaml:"summary"`
|
||
}
|
||
yamlBytes, err := YAML(snapshot.ErrorsDocument())
|
||
if err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
if err := yaml.Unmarshal(yamlBytes, &decoded); err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
if CompletionLine(snapshot) != "Completed: 1 corrections applied; 1 work units with errors; 3 recoveries." || *decoded.Summary.WorkUnitsWithErrors != 1 || *decoded.Summary.Recoveries != 3 {
|
||
t.Fatalf("CLI/YAML count disagreement: %s %+v", CompletionLine(snapshot), decoded.Summary)
|
||
}
|
||
}
|
||
|
||
func TestMarkdownNoWorkAndEscapedStageLabel(t *testing.T) {
|
||
text := string(Markdown(Snapshot{RunID: "r", StageNames: []string{"bad|label`\nsecret"}}, "secret"))
|
||
if strings.Count(text, "No work units.") != 2 || strings.Contains(text, "secret") {
|
||
t.Fatal(text)
|
||
}
|
||
text = string(Markdown(Snapshot{RunID: "r", StageNames: []string{"bad|label`\nsecret"}, WorkUnits: []WorkUnit{{StageIndex: 0, ChunkIndex: 0, State: "completed"}}}, "secret"))
|
||
if !strings.Contains(text, "bad\\|label\\`<br>[REDACTED]") {
|
||
t.Fatal(text)
|
||
}
|
||
}
|