2026-09-12 15:58:06 +00:00
package engine
import (
"errors"
"math"
"reflect"
"strings"
"testing"
"time"
)
func TestLoadRunsRecordedResolutionWithMapWriteback ( t * testing . T ) {
t . Parallel ( )
type artifact struct {
Output string ` yaml:"output" `
Timeout time . Duration ` yaml:"timeout" `
}
type config struct {
PollInterval time . Duration ` yaml:"poll_interval" `
Timeout time . Duration ` yaml:"timeout" `
Artifacts map [ string ] artifact ` yaml:"artifacts" `
}
definition := Definition [ config ] {
Defaults : func ( ) config {
return config { PollInterval : time . Minute , Timeout : 5 * time . Second }
} ,
Resolve : func ( configuration * config , resolution * Resolution ) error {
Default ( resolution , Keys ( "timeout" ) , & configuration . Timeout ,
configuration . PollInterval / 10 , "derived from poll interval" , Keys ( "poll_interval" ) )
for name , current := range configuration . Artifacts {
path := Keys ( "artifacts" , name )
Default ( resolution , path . Key ( "timeout" ) , & current . Timeout ,
configuration . Timeout , "inherited configuration timeout" , Keys ( "timeout" ) )
Normalize ( resolution , path . Key ( "output" ) , & current . Output ,
strings . TrimSpace ( current . Output ) , "trimmed surrounding whitespace" )
configuration . Artifacts [ name ] = current
}
resolution . Warning ( Keys ( "timeout" ) , "using derived timeout" , Keys ( "poll_interval" ) )
return nil
} ,
}
input := "poll_interval: 1m\nartifacts:\n second: {output: ' second '}\n first: {output: ' first '}\n"
2026-09-12 16:04:31 +00:00
result , err := testLoad ( Bytes ( "resolution.yml" , [ ] byte ( input ) ) , Options [ config ] { Definition : definition } )
2026-09-12 15:58:06 +00:00
if err != nil {
t . Fatal ( err )
}
if result . Config . Timeout != 6 * time . Second {
t . Fatalf ( "timeout = %s" , result . Config . Timeout )
}
for name , want := range map [ string ] string { "first" : "first" , "second" : "second" } {
current := result . Config . Artifacts [ name ]
if current . Timeout != 6 * time . Second || current . Output != want {
t . Errorf ( "artifact %q = %#v" , name , current )
}
}
if diagnostics := result . Diagnostics ( ) ; len ( diagnostics ) != 1 || diagnostics [ 0 ] . Code != CodeResolveWarning || diagnostics [ 0 ] . Primary == nil || len ( diagnostics [ 0 ] . Related ) != 1 {
t . Fatalf ( "diagnostics = %#v" , diagnostics )
}
metadata := result . Metadata ( )
timeout , ok := metadata . Lookup ( Keys ( "timeout" ) )
if ! ok || timeout . Explicit || timeout . Origin . Layer != LayerResolution || timeout . Origin . Operation != ChangeDerivedDefault {
t . Fatalf ( "timeout metadata = %#v, %v" , timeout , ok )
}
output , ok := metadata . Lookup ( Keys ( "artifacts" , "first" , "output" ) )
if ! ok || ! output . Explicit || output . Origin . Operation != ChangeNormalization {
t . Fatalf ( "output metadata = %#v, %v" , output , ok )
}
history := metadata . History ( Keys ( "timeout" ) )
last := history [ len ( history ) - 1 ]
if last . Origin . Operation != ChangeDerivedDefault || ! reflect . DeepEqual ( last . Reasons , [ ] string { "derived from poll interval" } ) || len ( last . Dependencies ) != 1 || last . Dependencies [ 0 ] . String ( ) != "/poll_interval" {
t . Fatalf ( "timeout history = %#v" , history )
}
wantOrder := [ ] string {
"/artifacts/first/output" , "/artifacts/first/timeout" ,
"/artifacts/second/output" , "/artifacts/second/timeout" , "/timeout" ,
}
gotOrder := make ( [ ] string , len ( result . resolution ) )
for index , snapshot := range result . resolution {
gotOrder [ index ] = snapshot . change . Path . String ( )
}
if ! reflect . DeepEqual ( gotOrder , wantOrder ) {
t . Fatalf ( "resolution order = %#v" , gotOrder )
}
}
func TestResolutionPreservesExplicitNullAndZeroWhileReplacingAbsentBaseline ( t * testing . T ) {
t . Parallel ( )
type config struct {
Optional * int ` yaml:"optional" `
Count int ` yaml:"count" `
Absent int ` yaml:"absent" `
}
five := 5
2026-09-12 16:04:31 +00:00
result , err := testLoad ( Bytes ( "explicit.yml" , [ ] byte ( "optional: null\ncount: 0\n" ) ) , Options [ config ] { Definition : Definition [ config ] {
2026-09-12 15:58:06 +00:00
Defaults : func ( ) config { return config { Optional : & five , Count : 5 , Absent : 5 } } ,
Resolve : func ( configuration * config , resolution * Resolution ) error {
if ! resolution . IsExplicit ( Keys ( "optional" ) ) || ! resolution . IsExplicit ( Keys ( "count" ) ) || resolution . IsExplicit ( Keys ( "absent" ) ) {
return errors . New ( "unexpected presence" )
}
Default ( resolution , Keys ( "optional" ) , & configuration . Optional , & five , "would derive optional" )
Default ( resolution , Keys ( "count" ) , & configuration . Count , 9 , "would derive count" )
Default ( resolution , Keys ( "absent" ) , & configuration . Absent , 9 , "derived absent value" )
return nil
} ,
} } )
if err != nil {
var loadError * LoadError
_ = errors . As ( err , & loadError )
t . Fatalf ( "%v: %#v" , err , loadError . Diagnostics ( ) )
}
if result . Config . Optional != nil || result . Config . Count != 0 || result . Config . Absent != 9 {
t . Fatalf ( "config = %#v" , result . Config )
}
if len ( result . Metadata ( ) . History ( Keys ( "optional" ) ) ) != 2 || len ( result . Metadata ( ) . History ( Keys ( "count" ) ) ) != 2 || len ( result . Metadata ( ) . History ( Keys ( "absent" ) ) ) != 2 {
t . Fatal ( "resolution history disagrees with explicitness" )
}
}
func TestResolutionCoalescesEqualAndRepeatedHelperIntent ( t * testing . T ) {
t . Parallel ( )
type config struct {
Value int ` yaml:"value" `
Other int ` yaml:"other" `
}
2026-09-12 16:04:31 +00:00
result , err := testLoad ( NoSource ( ) , Options [ config ] { Definition : Definition [ config ] {
2026-09-12 15:58:06 +00:00
Defaults : func ( ) config { return config { Value : 5 } } ,
Resolve : func ( configuration * config , resolution * Resolution ) error {
Default ( resolution , Keys ( "value" ) , & configuration . Value , 5 , "equal derived intent" , Keys ( "other" ) )
Default ( resolution , Keys ( "value" ) , & configuration . Value , 7 , "updated derived intent" , Keys ( "other" ) )
Normalize ( resolution , Keys ( "value" ) , & configuration . Value , 7 , "canonicalized value" , Keys ( "other" ) )
return nil
} ,
} } )
if err != nil {
t . Fatal ( err )
}
history := result . Metadata ( ) . History ( Keys ( "value" ) )
if len ( history ) != 2 {
t . Fatalf ( "history = %#v" , history )
}
change := history [ 1 ]
if change . Origin . Operation != ChangeNormalization || ! reflect . DeepEqual ( change . Reasons , [ ] string { "equal derived intent" , "updated derived intent" , "canonicalized value" } ) || len ( change . Dependencies ) != 1 {
t . Fatalf ( "coalesced change = %#v" , change )
}
}
func TestResolutionContainerRecordCoversSubtreeRemovalAndSnapshotsAreDetached ( t * testing . T ) {
t . Parallel ( )
type item struct {
Value string ` yaml:"value" `
}
type config struct {
Items map [ string ] item ` yaml:"items" `
}
2026-09-12 16:04:31 +00:00
result , err := testLoad ( Bytes ( "remove.yml" , [ ] byte ( "items:\n keep: {value: 'yes'}\n remove: {value: 'no'}\n" ) ) , Options [ config ] { Definition : Definition [ config ] {
2026-09-12 15:58:06 +00:00
Resolve : func ( configuration * config , resolution * Resolution ) error {
delete ( configuration . Items , "remove" )
resolution . Record ( Keys ( "items" ) , ChangeNormalization , "removed disabled entries" )
return nil
} ,
} } )
if err != nil {
t . Fatal ( err )
}
if _ , exists := result . Config . Items [ "remove" ] ; exists {
t . Fatal ( "removed entry remains" )
}
if _ , ok := result . Metadata ( ) . Lookup ( Keys ( "items" , "remove" ) ) ; ok {
t . Fatal ( "removed entry remains effective metadata" )
}
if len ( result . resolution ) != 1 || result . resolution [ 0 ] . before == nil || result . resolution [ 0 ] . after == nil {
t . Fatalf ( "snapshots = %#v" , result . resolution )
}
result . Config . Items [ "keep" ] = item { Value : "changed" }
if mappingValue ( t , result . resolution [ 0 ] . after , "keep" ) . Mapping [ 0 ] . Value . Text != "yes" {
t . Fatal ( "caller mutation changed private resolution snapshot" )
}
}
func TestResolutionSequenceReplacementUpdatesDescendantOrigins ( t * testing . T ) {
t . Parallel ( )
type config struct {
Values [ ] int ` yaml:"values" `
}
2026-09-12 16:04:31 +00:00
result , err := testLoad ( Bytes ( "sequence.yml" , [ ] byte ( "values: [1, 2]\n" ) ) , Options [ config ] { Definition : Definition [ config ] {
2026-09-12 15:58:06 +00:00
Resolve : func ( configuration * config , resolution * Resolution ) error {
Normalize ( resolution , Keys ( "values" ) , & configuration . Values , [ ] int { 3 } , "replaced values" )
return nil
} ,
} } )
if err != nil {
t . Fatal ( err )
}
info , ok := result . Metadata ( ) . Lookup ( Keys ( "values" ) . Index ( 0 ) )
if ! ok || ! info . Explicit || info . Origin . Layer != LayerResolution || info . Origin . Operation != ChangeNormalization {
t . Fatalf ( "element metadata = %#v, %v" , info , ok )
}
if _ , ok := result . Metadata ( ) . Lookup ( Keys ( "values" ) . Index ( 1 ) ) ; ok {
t . Fatal ( "removed sequence element remains effective" )
}
}
func TestResolutionRejectsUnrecordedAndMismatchedMutations ( t * testing . T ) {
t . Parallel ( )
type config struct {
Value int ` yaml:"value" `
}
tests := [ ] struct {
name string
resolve func ( * config , * Resolution ) error
code Code
} {
{ name : "unrecorded" , resolve : func ( configuration * config , _ * Resolution ) error {
configuration . Value = 2
return nil
} , code : CodeResolveUnrecordedChange } ,
{ name : "unrelated target" , resolve : func ( _ * config , resolution * Resolution ) error {
unrelated := 1
Normalize ( resolution , Keys ( "value" ) , & unrelated , 2 , "changed value" )
return nil
} , code : CodeResolveInvalidTarget } ,
{ name : "invalid record kind" , resolve : func ( _ * config , resolution * Resolution ) error {
resolution . Record ( Keys ( "value" ) , ChangeKind ( "other" ) , "invalid kind" )
return nil
} , code : CodeResolveInvalidKind } ,
{ name : "invalid path" , resolve : func ( _ * config , resolution * Resolution ) error {
resolution . Record ( Keys ( "unknown" ) , ChangeNormalization , "unknown field" )
return nil
} , code : CodeResolveInvalidPath } ,
}
for _ , test := range tests {
t . Run ( test . name , func ( t * testing . T ) {
2026-09-12 16:04:31 +00:00
result , err := testLoad ( Bytes ( "invalid-resolution.yml" , [ ] byte ( "value: 1\n" ) ) , Options [ config ] { Definition : Definition [ config ] { Resolve : test . resolve } } )
2026-09-12 15:58:06 +00:00
assertLoadDiagnostic ( t , result , err , test . code )
} )
}
}
func TestResolutionRejectsInvalidProjectedValuesAndSuppressesReturnedErrors ( t * testing . T ) {
t . Parallel ( )
type config struct {
Number float64 ` yaml:"number" `
Value int ` yaml:"value" `
}
tests := [ ] struct {
name string
resolve func ( * config , * Resolution ) error
code Code
} {
{ name : "invalid helper value" , resolve : func ( configuration * config , resolution * Resolution ) error {
Normalize ( resolution , Keys ( "number" ) , & configuration . Number , math . NaN ( ) , "invalid number" )
return nil
} , code : CodeResolveInvalidValue } ,
{ name : "reported error" , resolve : func ( _ * config , resolution * Resolution ) error {
resolution . Error ( Keys ( "value" ) , "value cannot be resolved" )
return errors . New ( "CANARY_RESOLUTION_ERROR" )
} , code : CodeResolveError } ,
{ name : "returned error" , resolve : func ( _ * config , _ * Resolution ) error {
return errors . New ( "CANARY_RESOLUTION_ERROR" )
} , code : CodeResolveHookFailed } ,
}
for _ , test := range tests {
t . Run ( test . name , func ( t * testing . T ) {
2026-09-12 16:04:31 +00:00
result , err := testLoad ( Bytes ( "resolution-errors.yml" , [ ] byte ( "value: 1\nnumber: 1\n" ) ) , Options [ config ] { Definition : Definition [ config ] { Resolve : test . resolve } } )
2026-09-12 15:58:06 +00:00
loadError := assertLoadDiagnostic ( t , result , err , test . code )
for _ , diagnostic := range loadError . Diagnostics ( ) {
if strings . Contains ( diagnostic . Message , "CANARY" ) {
t . Fatalf ( "diagnostic exposed returned error: %#v" , diagnostic )
}
}
} )
}
}
func TestResolutionEntryQueriesExposeDetachedLoadInput ( t * testing . T ) {
t . Parallel ( )
type config struct {
Declared string ` yaml:"declared" `
Default string ` yaml:"default" `
Optional * string ` yaml:"optional" `
}
filename := writeImportFile ( t , t . TempDir ( ) , "config.yml" , "declared: file\noptional: null\n" )
var savedField FieldInfo
var savedSource SourceInfo
2026-09-12 16:04:31 +00:00
result , err := testLoad [ config ] ( File ( filename ) , Options [ config ] { Definition : Definition [ config ] {
2026-09-12 15:58:06 +00:00
Defaults : func ( ) config { return config { Default : "retained" } } ,
Resolve : func ( _ * config , resolution * Resolution ) error {
for _ , path := range [ ] Path { Keys ( "declared" ) , Keys ( "default" ) , Keys ( "optional" ) } {
info , found := resolution . InputInfo ( path )
if ! found || info . Explicit != resolution . IsExplicit ( path ) {
return errors . New ( "entry metadata does not agree with explicitness" )
}
}
defaultInfo , _ := resolution . InputInfo ( Keys ( "default" ) )
optionalInfo , _ := resolution . InputInfo ( Keys ( "optional" ) )
if defaultInfo . Explicit || defaultInfo . Origin . Layer != LayerDefault || ! optionalInfo . Explicit || ! optionalInfo . Null {
return errors . New ( "entry metadata lost default or null state" )
}
if _ , found := resolution . InputInfo ( Keys ( "missing" ) ) ; found {
return errors . New ( "missing entry path was found" )
}
declared , _ := resolution . InputInfo ( Keys ( "declared" ) )
if len ( declared . Origin . Locations ) != 1 {
return errors . New ( "declared source location is missing" )
}
source , found := resolution . Source ( declared . Origin . Locations [ 0 ] . SourceID )
if ! found || source . Path != canonicalTestPath ( t , filename ) || source . ID != "source-1" {
return errors . New ( "declared source record is missing" )
}
if _ , found := resolution . Source ( "" ) ; found {
return errors . New ( "empty source identity was found" )
}
if _ , found := resolution . Source ( "unknown" ) ; found {
return errors . New ( "unknown source identity was found" )
}
savedField , savedSource = declared , source
return nil
} ,
} } )
if err != nil {
t . Fatal ( err )
}
if result . Config . Declared != "file" || result . Config . Default != "retained" || result . Config . Optional != nil {
t . Fatalf ( "configuration = %#v" , result . Config )
}
savedField . Origin . Locations [ 0 ] . SourceID = "mutated"
savedSource . Label = "mutated"
field , _ := result . Metadata ( ) . Lookup ( Keys ( "declared" ) )
if field . Origin . Locations [ 0 ] . SourceID != "source-1" || result . Sources ( ) [ 0 ] . Label == "mutated" {
t . Fatal ( "saved resolution records alias a completed result" )
}
2026-09-12 16:04:31 +00:00
noSource , err := testLoad [ config ] ( NoSource ( ) , Options [ config ] { Definition : Definition [ config ] {
2026-09-12 15:58:06 +00:00
Defaults : func ( ) config { return config { Default : "retained" } } ,
Resolve : func ( _ * config , resolution * Resolution ) error {
info , found := resolution . InputInfo ( Keys ( "default" ) )
if ! found || info . Explicit || resolution . IsExplicit ( Keys ( "default" ) ) {
return errors . New ( "defaults-only entry metadata is wrong" )
}
if _ , found := resolution . Source ( "source-1" ) ; found {
return errors . New ( "defaults-only load invented a source" )
}
return nil
} ,
} } )
if err != nil || noSource . Config . Default != "retained" {
t . Fatalf ( "defaults-only load = %#v, %v" , noSource , err )
}
}
func TestResolutionContextPanicsAfterCallback ( t * testing . T ) {
t . Parallel ( )
type config struct {
Value int ` yaml:"value" `
}
var retained * Resolution
2026-09-12 16:04:31 +00:00
if _ , err := testLoad ( NoSource ( ) , Options [ config ] { Definition : Definition [ config ] { Resolve : func ( _ * config , resolution * Resolution ) error {
2026-09-12 15:58:06 +00:00
retained = resolution
return nil
} } } ) ; err != nil {
t . Fatal ( err )
}
defer func ( ) {
if recovered := recover ( ) ; recovered != closedCallbackContextMessage {
t . Fatalf ( "panic = %#v" , recovered )
}
} ( )
retained . IsExplicit ( Keys ( "value" ) )
}
func TestResolutionEntryQueriesRequireAnActiveCallback ( t * testing . T ) {
t . Parallel ( )
type config struct {
Value int ` yaml:"value" `
}
requireClosed := func ( t * testing . T , call func ( ) ) {
t . Helper ( )
defer func ( ) {
if recovered := recover ( ) ; recovered != closedCallbackContextMessage {
t . Fatalf ( "panic = %#v" , recovered )
}
} ( )
call ( )
}
requireClosed ( t , func ( ) { ( * Resolution ) ( nil ) . InputInfo ( Keys ( "value" ) ) } )
requireClosed ( t , func ( ) { ( & Resolution { } ) . Source ( "source-1" ) } )
var successful * Resolution
2026-09-12 16:04:31 +00:00
if _ , err := testLoad ( NoSource ( ) , Options [ config ] { Definition : Definition [ config ] { Resolve : func ( _ * config , resolution * Resolution ) error {
2026-09-12 15:58:06 +00:00
successful = resolution
return nil
} } } ) ; err != nil {
t . Fatal ( err )
}
requireClosed ( t , func ( ) { successful . InputInfo ( Keys ( "value" ) ) } )
requireClosed ( t , func ( ) { successful . Source ( "source-1" ) } )
var failed * Resolution
2026-09-12 16:04:31 +00:00
if _ , err := testLoad ( NoSource ( ) , Options [ config ] { Definition : Definition [ config ] { Resolve : func ( _ * config , resolution * Resolution ) error {
2026-09-12 15:58:06 +00:00
failed = resolution
return errors . New ( "resolver failed" )
} } } ) ; err == nil {
t . Fatal ( "failed resolver succeeded" )
}
requireClosed ( t , func ( ) { failed . InputInfo ( Keys ( "value" ) ) } )
requireClosed ( t , func ( ) { failed . Source ( "source-1" ) } )
}
func TestValidationContextPanicsAfterVersionCallback ( t * testing . T ) {
t . Parallel ( )
type config struct {
Version string ` yaml:"version" `
}
var retained * Validation
2026-09-12 16:04:31 +00:00
if _ , err := testLoad ( Bytes ( "version-context.yml" , [ ] byte ( "version: one\n" ) ) , Options [ config ] { Definition : Definition [ config ] {
2026-09-12 15:58:06 +00:00
Version : & VersionRule { Path : Keys ( "version" ) , Check : func ( _ Version , validation * Validation ) error {
retained = validation
return nil
} } ,
} } ) ; err != nil {
t . Fatal ( err )
}
defer func ( ) {
if recovered := recover ( ) ; recovered != closedCallbackContextMessage {
t . Fatalf ( "panic = %#v" , recovered )
}
} ( )
retained . Warning ( Keys ( "version" ) , "too late" )
}
2026-09-12 16:12:01 +00:00
func assertLoadDiagnostic [ T any ] ( t * testing . T , result * testResult [ T ] , err error , code Code ) * LoadError {
2026-09-12 15:58:06 +00:00
t . Helper ( )
if result != nil || err == nil {
t . Fatalf ( "result, err = %#v, %v" , result , err )
}
var loadError * LoadError
if ! errors . As ( err , & loadError ) {
t . Fatalf ( "error type = %T" , err )
}
diagnostics := loadError . Diagnostics ( )
if len ( diagnostics ) == 0 || diagnostics [ 0 ] . Code != code {
t . Fatalf ( "diagnostics = %#v" , diagnostics )
}
return loadError
}