2026-11-07 04:52:58 +00:00
package ckconfig
import (
"bytes"
"context"
"encoding/json"
"errors"
"io"
"strings"
"testing"
commandkit "go.maximumdirect.net/commandkit"
configkit "go.maximumdirect.net/configkit"
)
func validationDiagnostic ( message string ) commandkit . Diagnostic {
return commandkit . Diagnostic { Severity : commandkit . SeverityWarning , Write : func ( w io . Writer ) error { _ , err := io . WriteString ( w , message + "\n" ) ; return err } }
}
func TestDetailedValidationFiltersAndRetainsFailureEvidence ( t * testing . T ) {
cause := errors . New ( "second scope failed" )
calls := [ ] string { }
reader := & sourceInventory { values : [ ] configkit . SourceInfo { { ID : "primary" , Label : "main" , Path : "main.yml" } , { ID : "related" , Label : "included" , Path : "include.yml" } , { ID : "unused" , Label : "unused" } } }
records := [ ] configkit . Diagnostic {
{ Code : "chosen" , Severity : configkit . SeverityWarning , Path : configkit . Keys ( "a/b" ) , Message : "selected warning" , Primary : & configkit . Location { SourceID : "primary" , Line : 2 , Column : 3 } , Related : [ ] configkit . Location { { SourceID : "related" , Line : 7 , Column : 8 } } } ,
{ Code : "other" , Severity : configkit . SeverityWarning , Path : configkit . Keys ( "other" ) , Message : "other warning" } ,
}
scopes := [ ] Scope [ struct { } , struct { } ] {
{ Name : "app" , Operations : [ ] Operation { Validate } , Acquire : func ( context . Context , Request , struct { } , struct { } ) ( commandkit . Acquired [ View ] , error ) {
calls = append ( calls , "app" )
return commandkit . Acquired [ View ] { Value : View { Sources : reader , Findings : & Findings { Records : records , Messages : [ ] commandkit . Diagnostic { validationDiagnostic ( "native warnings" ) } } } , Diagnostics : [ ] commandkit . Diagnostic { validationDiagnostic ( "application warning" ) } } , nil
} } ,
{ Name : "second" , Operations : [ ] Operation { Validate } , Acquire : func ( context . Context , Request , struct { } , struct { } ) ( commandkit . Acquired [ View ] , error ) {
calls = append ( calls , "second" )
return commandkit . Acquired [ View ] { Value : View { Findings : & Findings { Records : [ ] configkit . Diagnostic { { Code : "failed" , Severity : configkit . SeverityError , Message : "failed finding" } } } } , Explanation : commandkit . Explanation { Message : "terminal failure" } } , cause
} } ,
{ Name : "third" , Operations : [ ] Operation { Validate } , Acquire : func ( context . Context , Request , struct { } , struct { } ) ( commandkit . Acquired [ View ] , error ) {
calls = append ( calls , "third" )
return commandkit . Acquired [ View ] { } , nil
} } ,
}
app := newConfigTestApp ( t , Command ( Suite [ struct { } , struct { } ] { Scopes : scopes } ) )
var out , diag bytes . Buffer
result := app . Execute ( context . Background ( ) , [ ] string { "config" , "validate" , "--scope=all" , "--details" , "--severity=warning" , "--code=chosen" , "--format=json" , "--verbose" } , commandkit . Streams { Out : & out , Err : & diag } )
decoder := json . NewDecoder ( & out )
var report validationReport
if err := decoder . Decode ( & report ) ; err != nil {
t . Fatal ( err )
}
if err := decoder . Decode ( new ( any ) ) ; err != io . EOF {
t . Fatalf ( "extra JSON: %v" , err )
}
if ! errors . Is ( result . Cause , cause ) || result . Kind != commandkit . OutcomeOperational || len ( calls ) != 2 || calls [ 0 ] != "app" || calls [ 1 ] != "second" || len ( report . Scopes ) != 2 || report . Scopes [ 0 ] . Outcome != "valid" || report . Scopes [ 1 ] . Outcome != "failed" {
t . Fatalf ( "result=%#v calls=%v report=%#v" , result , calls , report )
}
first , second := report . Scopes [ 0 ] . Details , report . Scopes [ 1 ] . Details
if first == nil || first . State != "present" || len ( first . Findings ) != 1 || first . Findings [ 0 ] . Path != "/a~1b" || len ( first . Sources ) != 2 || first . Sources [ 0 ] . ID != "primary" || first . Sources [ 1 ] . ID != "related" || second == nil || second . State != "filtered" || len ( second . Findings ) != 0 {
t . Fatalf ( "details=%#v %#v" , first , second )
}
if strings . Contains ( diag . String ( ) , "native warnings" ) || ! strings . Contains ( diag . String ( ) , "application warning" ) || ! strings . Contains ( diag . String ( ) , "terminal failure" ) {
t . Fatalf ( "diagnostics=%q" , diag . String ( ) )
}
2026-11-07 12:07:50 +00:00
for _ , tc := range [ ] struct {
name string
flags [ ] string
first , second [ ] string
} {
{ "any within filters" , [ ] string { "--severity=warning" , "--severity=error" , "--code=chosen" , "--code=other" , "--code=failed" } , [ ] string { "selected warning" , "other warning" } , [ ] string { "failed finding" } } ,
{ "duplicates and unknown" , [ ] string { "--severity=warning" , "--severity=warning" , "--code=chosen" , "--code=chosen" , "--code=future-code" } , [ ] string { "selected warning" } , nil } ,
{ "both filters" , [ ] string { "--severity=error" , "--code=chosen" , "--code=failed" } , nil , [ ] string { "failed finding" } } ,
{ "no matching code" , [ ] string { "--code=future-code" } , nil , nil } ,
} {
t . Run ( tc . name , func ( t * testing . T ) {
var out bytes . Buffer
args := append ( [ ] string { "config" , "validate" , "--scope=all" , "--details" , "--format=json" } , tc . flags ... )
got := app . Execute ( context . Background ( ) , args , commandkit . Streams { Out : & out , Err : io . Discard } )
var report validationReport
if err := json . Unmarshal ( out . Bytes ( ) , & report ) ; err != nil {
t . Fatal ( err )
}
if ! errors . Is ( got . Cause , cause ) || len ( report . Scopes ) != 2 {
t . Fatalf ( "outcome=%#v report=%#v" , got , report )
}
for index , want := range [ ] [ ] string { tc . first , tc . second } {
details := report . Scopes [ index ] . Details
if len ( details . Findings ) != len ( want ) {
t . Fatalf ( "findings=%#v want=%v" , details . Findings , want )
}
for i , message := range want {
if details . Findings [ i ] . Message != message {
t . Fatalf ( "finding order=%#v want=%v" , details . Findings , want )
}
}
if len ( want ) == 0 && details . State != "filtered" {
t . Fatalf ( "state=%q" , details . State )
}
}
} )
}
2026-11-07 04:52:58 +00:00
before := len ( calls )
for _ , args := range [ ] [ ] string { { "--severity=warning" } , { "--code=x" } , { "--details" , "--severity=unknown" } } {
result = app . Execute ( context . Background ( ) , append ( [ ] string { "config" , "validate" } , args ... ) , commandkit . Streams { Out : io . Discard , Err : io . Discard } )
if result . Kind != commandkit . OutcomeUsage || len ( calls ) != before {
t . Fatalf ( "invalid %v: %#v" , args , result )
}
}
}
func TestValidationCancellationAndDeliveryRetainReachedScopes ( t * testing . T ) {
ctx , cancel := context . WithCancel ( context . Background ( ) )
defer cancel ( )
calls := 0
scopes := [ ] Scope [ struct { } , struct { } ] {
{ Name : "app" , Operations : [ ] Operation { Validate } , Acquire : func ( context . Context , Request , struct { } , struct { } ) ( commandkit . Acquired [ View ] , error ) {
calls ++
return commandkit . Acquired [ View ] { Value : View { Findings : & Findings { } } } , nil
} } ,
{ Name : "second" , Operations : [ ] Operation { Validate } , Acquire : func ( context . Context , Request , struct { } , struct { } ) ( commandkit . Acquired [ View ] , error ) {
calls ++
cancel ( )
return commandkit . Acquired [ View ] { } , nil
} } ,
{ Name : "third" , Operations : [ ] Operation { Validate } , Acquire : func ( context . Context , Request , struct { } , struct { } ) ( commandkit . Acquired [ View ] , error ) {
calls ++
return commandkit . Acquired [ View ] { } , nil
} } ,
}
app := newConfigTestApp ( t , Command ( Suite [ struct { } , struct { } ] { Scopes : scopes } ) )
var out bytes . Buffer
result := app . Execute ( ctx , [ ] string { "config" , "validate" , "--scope=all" , "--details" , "--format=json" } , commandkit . Streams { Out : & out , Err : io . Discard } )
var report validationReport
if err := json . Unmarshal ( out . Bytes ( ) , & report ) ; err != nil {
t . Fatal ( err )
}
if ! errors . Is ( result . Cause , context . Canceled ) || calls != 2 || len ( report . Scopes ) != 2 || report . Scopes [ 0 ] . Details . State != "empty" || report . Scopes [ 1 ] . Details . State != "unavailable" || report . Scopes [ 1 ] . Outcome != "canceled" {
t . Fatalf ( "result=%#v calls=%d report=%#v" , result , calls , report )
}
failure := errors . New ( "load failure" )
scope := Scope [ struct { } , struct { } ] { Name : "app" , Operations : [ ] Operation { Validate } , Acquire : func ( context . Context , Request , struct { } , struct { } ) ( commandkit . Acquired [ View ] , error ) {
return commandkit . Acquired [ View ] { } , failure
} }
app = newConfigTestApp ( t , Command ( Suite [ struct { } , struct { } ] { Scopes : [ ] Scope [ struct { } , struct { } ] { scope } } ) )
result = app . Execute ( context . Background ( ) , [ ] string { "config" , "validate" , "--details" } , commandkit . Streams { Out : shortWriter { } , Err : io . Discard } )
if ! errors . Is ( result . Cause , failure ) || result . Presentation . Output . State != commandkit . DeliveryIncomplete {
t . Fatalf ( "failure and delivery: %#v" , result )
}
out . Reset ( )
result = app . Execute ( context . Background ( ) , [ ] string { "config" , "validate" , "--details" , "--quiet" } , commandkit . Streams { Out : & out , Err : io . Discard } )
if ! errors . Is ( result . Cause , failure ) || out . Len ( ) != 0 {
t . Fatalf ( "quiet failure: %#v %q" , result , out . String ( ) )
}
}
func TestDetailedValidationReportsNativeLoadError ( t * testing . T ) {
_ , failure := configkit . Load [ map [ string ] any ] ( configkit . Bytes ( "invalid source" , [ ] byte ( "invalid: [" ) ) )
var native * configkit . LoadError
if ! errors . As ( failure , & native ) {
t . Fatalf ( "fixture: %v" , failure )
}
scope := FromConfigKit ( "app" , "" , func ( context . Context , Selection , struct { } , struct { } ) ( * configkit . Result [ map [ string ] any ] , error ) {
return nil , failure
} )
app := newConfigTestApp ( t , Command ( Suite [ struct { } , struct { } ] { Scopes : [ ] Scope [ struct { } , struct { } ] { scope } } ) )
var out bytes . Buffer
result := app . Execute ( context . Background ( ) , [ ] string { "config" , "validate" , "--details" , "--format=json" } , commandkit . Streams { Out : & out , Err : io . Discard } )
var report validationReport
if err := json . Unmarshal ( out . Bytes ( ) , & report ) ; err != nil {
t . Fatal ( err )
}
if ! errors . Is ( result . Cause , failure ) || len ( report . Scopes ) != 1 || report . Scopes [ 0 ] . Outcome != "failed" || report . Scopes [ 0 ] . Details . State != "present" || len ( report . Scopes [ 0 ] . Details . Findings ) != len ( native . Diagnostics ( ) ) {
t . Fatalf ( "native failure: %#v %q" , result , out . String ( ) )
}
}