2026-09-24 17:34:03 +00:00
package reporting
import (
2026-09-25 00:36:44 +00:00
"reflect"
"regexp"
2026-09-24 17:34:03 +00:00
"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" )
2026-09-25 00:36:44 +00:00
text := string ( got )
// Compare only complete table rows, preserving order and states while leaving
// prose and spacing outside the fixed matrices free to change.
wantRows := [ ] string {
"| Chunk | grammar_1 | grammar_2 |" ,
"| --- | ---: | ---: |" ,
"| Chunk 1 (segments 1– 2) | 1 | 0* |" ,
"| Chunk 2 (segments 3– 4) | 0 | — |" ,
"| Chunk | grammar_1 | grammar_2 |" ,
"| --- | ---: | ---: |" ,
"| Chunk 1 (segments 1– 2) | 1 | 2* |" ,
"| Chunk 2 (segments 3– 4) | 0 | — |" ,
2026-09-24 17:34:03 +00:00
}
2026-09-25 00:36:44 +00:00
if rows := markdownTableRows ( text ) ; ! reflect . DeepEqual ( rows , wantRows ) {
t . Fatalf ( "matrices: got %v; want %v" , rows , wantRows )
2026-09-24 17:34:03 +00:00
}
2026-09-25 00:36:44 +00:00
for _ , fragment := range [ ] string { "in\\|put.json" , "out<br>file.json" , "glossary\\`[REDACTED]\\`.yaml" , "`transport_failed`: 1" , "`output_repaired`: 2" , "`proposals_filtered`: 1" , "`service_recovered`: 1" } {
2026-09-24 17:34:03 +00:00
if ! strings . Contains ( text , fragment ) {
t . Fatalf ( "missing %q in:\n%s" , fragment , text )
}
}
2026-09-25 00:36:44 +00:00
// Assert summary quantities independently of the surrounding explanation.
numbers := regexp . MustCompile ( ` [0-9]+ ` )
for label , want := range map [ string ] [ ] string {
"Corrections applied" : { "1" } ,
"Errors" : { "1" , "0" } ,
"Recoveries" : { "3" , "4" } ,
} {
var got [ ] string
for _ , line := range strings . Split ( text , "\n" ) {
if value , ok := strings . CutPrefix ( strings . TrimSpace ( line ) , label + ":" ) ; ok {
got = numbers . FindAllString ( value , - 1 )
break
}
}
if ! reflect . DeepEqual ( got , want ) {
t . Fatalf ( "%s summary: got %v; want %v" , label , got , want )
}
}
2026-09-24 17:34:03 +00:00
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" ) )
2026-09-25 00:36:44 +00:00
if len ( markdownTableRows ( text ) ) != 0 || strings . Contains ( text , "secret" ) {
2026-09-24 17:34:03 +00:00
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 )
}
}
2026-09-25 00:36:44 +00:00
func markdownTableRows ( text string ) [ ] string {
var rows [ ] string
for _ , line := range strings . Split ( text , "\n" ) {
if line = strings . TrimSpace ( line ) ; strings . HasPrefix ( line , "|" ) {
rows = append ( rows , line )
}
}
return rows
}