2026-10-23 13:49:22 +00:00
package engine
import (
"math/big"
"reflect"
"sort"
"strings"
"testing"
2026-11-01 14:19:37 +00:00
"go.maximumdirect.net/configkit/internal/document"
2026-10-23 13:49:22 +00:00
)
func TestNormalizeSequenceIdentityFields ( t * testing . T ) {
got , err := normalizeSequenceIdentityFields ( [ ] string { "name" , "id" , "id" , "" } )
if err != nil {
t . Fatal ( err )
}
if want := [ ] string { "" , "id" , "name" } ; ! reflect . DeepEqual ( got , want ) {
t . Fatalf ( "normalized fields = %#v, want %#v" , got , want )
}
if _ , err := normalizeSequenceIdentityFields ( nil ) ; err == nil {
t . Fatal ( "empty field set unexpectedly succeeded" )
}
}
func TestNormalizeSequenceIdentityNumbers ( t * testing . T ) {
tests := [ ] struct {
left , right string
equal bool
} {
{ left : "1" , right : "1.0" , equal : true } ,
{ left : "1" , right : "1e0" , equal : true } ,
{ left : "0" , right : "-0.000e999" , equal : true } ,
{ left : "0.0012300" , right : "123e-5" , equal : true } ,
{ left : "9007199254740992" , right : "9007199254740993" , equal : false } ,
{ left : "1.0000000000000000001" , right : "1.0000000000000000002" , equal : false } ,
}
for _ , test := range tests {
left , leftErr := normalizeSequenceIdentityNumber ( test . left )
right , rightErr := normalizeSequenceIdentityNumber ( test . right )
if leftErr != nil || rightErr != nil {
t . Fatalf ( "normalize(%q, %q) errors = %v, %v" , test . left , test . right , leftErr , rightErr )
}
if ( left == right ) != test . equal {
t . Errorf ( "normalize(%q) = %q; normalize(%q) = %q; equal = %t, want %t" , test . left , left , test . right , right , left == right , test . equal )
}
}
}
func TestNormalizeSequenceIdentityNumberLargeExponentWithoutExpansion ( t * testing . T ) {
exponent := "999999999999999999999999999999999999999999999999999999999999999999999999999999999999"
left , err := normalizeSequenceIdentityNumber ( "1e" + exponent )
if err != nil {
t . Fatal ( err )
}
plusOne , ok := new ( big . Int ) . SetString ( exponent , 10 )
if ! ok {
t . Fatal ( "test exponent did not parse" )
}
plusOne . Add ( plusOne , big . NewInt ( 1 ) )
right , err := normalizeSequenceIdentityNumber ( "10e" + exponent )
if err != nil {
t . Fatal ( err )
}
if want := "1e" + plusOne . String ( ) ; right != want {
t . Fatalf ( "normalized large exponent = %q, want %q" , right , want )
}
if left == right {
t . Fatal ( "unequal large exponents normalized to equal values" )
}
}
func TestSequenceIdentityTupleUsesTypeTagsAndLengthBoundaries ( t * testing . T ) {
tests := [ ] struct {
name string
left [ ] * document . Node
right [ ] * document . Node
equal bool
} {
{ name : "empty string differs from null" , left : [ ] * document . Node { stringNode ( "" ) } , right : [ ] * document . Node { nullNode ( ) } , equal : false } ,
{ name : "empty strings match exactly" , left : [ ] * document . Node { stringNode ( "" ) } , right : [ ] * document . Node { stringNode ( "" ) } , equal : true } ,
{ name : "explicit null matches explicit null" , left : [ ] * document . Node { nullNode ( ) } , right : [ ] * document . Node { nullNode ( ) } , equal : true } ,
{ name : "string and number differ" , left : [ ] * document . Node { stringNode ( "1" ) } , right : [ ] * document . Node { numberNode ( "1.0" ) } , equal : false } ,
{ name : "boolean and number differ" , left : [ ] * document . Node { booleanNode ( "true" ) } , right : [ ] * document . Node { numberNode ( "1" ) } , equal : false } ,
{ name : "compound boundaries are encoded" , left : [ ] * document . Node { stringNode ( "ab" ) , stringNode ( "c" ) } , right : [ ] * document . Node { stringNode ( "a" ) , stringNode ( "bc" ) } , equal : false } ,
{ name : "number spelling is normalized" , left : [ ] * document . Node { numberNode ( "1" ) } , right : [ ] * document . Node { numberNode ( "1e0" ) } , equal : true } ,
}
for _ , test := range tests {
t . Run ( test . name , func ( t * testing . T ) {
left , leftErr := sequenceIdentityTuple ( test . left )
right , rightErr := sequenceIdentityTuple ( test . right )
if leftErr != nil || rightErr != nil {
t . Fatalf ( "tuple errors = %v, %v" , leftErr , rightErr )
}
if ( left == right ) != test . equal {
t . Fatalf ( "tuple equality = %t, want %t" , left == right , test . equal )
}
} )
}
}
func TestValidateSequenceIdentityUsesOneTupleIndexAndPreservesNodes ( t * testing . T ) {
first := identityRecord ( map [ string ] * document . Node {
"namespace" : stringNode ( "support" ) ,
"id" : numberNode ( "1.0" ) ,
} )
second := identityRecord ( map [ string ] * document . Node {
"id" : numberNode ( "1e0" ) ,
"namespace" : stringNode ( "support" ) ,
} )
sequence := & document . Node { Kind : document . Sequence , Location : document . Location { SourceID : "source" , Line : 1 } , Sequence : [ ] * document . Node { first , second } }
_ , diagnostics := validateSequenceIdentity ( sequence , Keys ( "prompts" ) , [ ] string { "namespace" , "id" , "id" } , sequenceIdentityDiagnosticCodes { invalid : CodeComposeInvalid , conflict : CodeComposeConflict } )
if len ( diagnostics ) != 1 {
t . Fatalf ( "diagnostics = %#v, want one duplicate diagnostic" , diagnostics )
}
diagnostic := diagnostics [ 0 ]
if diagnostic . Code != CodeComposeConflict || diagnostic . Path . String ( ) != "/prompts" || diagnostic . Primary == nil || len ( diagnostic . Related ) != 1 {
t . Fatalf ( "duplicate diagnostic = %#v" , diagnostic )
}
if diagnostic . Message == "" || strings . Contains ( diagnostic . Message , "support" ) || strings . Contains ( diagnostic . Message , "1.0" ) {
t . Fatalf ( "diagnostic unexpectedly contains identity data: %#v" , diagnostic )
}
if first . Mapping [ 0 ] . Value . Text != "1.0" || second . Mapping [ 0 ] . Value . Text != "1e0" {
t . Fatalf ( "identity validation rewrote authored values: %q, %q" , first . Mapping [ 0 ] . Value . Text , second . Mapping [ 0 ] . Value . Text )
}
}
func TestValidateSequenceIdentityReportsMalformedFieldsWithoutValues ( t * testing . T ) {
tests := [ ] struct {
name string
item * document . Node
wantPath string
} {
{ name : "non-mapping item" , item : stringNode ( "private" ) , wantPath : "/items/0" } ,
{ name : "missing field" , item : identityRecord ( map [ string ] * document . Node { "other" : stringNode ( "private" ) } ) , wantPath : "/items/0/id" } ,
{ name : "mapping field" , item : identityRecord ( map [ string ] * document . Node { "id" : { Kind : document . Mapping } } ) , wantPath : "/items/0/id" } ,
{ name : "sequence field" , item : identityRecord ( map [ string ] * document . Node { "id" : { Kind : document . Sequence } } ) , wantPath : "/items/0/id" } ,
}
for _ , test := range tests {
t . Run ( test . name , func ( t * testing . T ) {
sequence := & document . Node { Kind : document . Sequence , Sequence : [ ] * document . Node { test . item } }
_ , diagnostics := validateSequenceIdentity ( sequence , Keys ( "items" ) , [ ] string { "id" } , sequenceIdentityDiagnosticCodes { invalid : CodeOptionsInvalid , conflict : CodeComposeConflict } )
if len ( diagnostics ) != 1 || diagnostics [ 0 ] . Code != CodeOptionsInvalid || diagnostics [ 0 ] . Path . String ( ) != test . wantPath {
t . Fatalf ( "diagnostics = %#v" , diagnostics )
}
if diagnostics [ 0 ] . Message == "" || strings . Contains ( diagnostics [ 0 ] . Message , "private" ) {
t . Fatalf ( "diagnostic exposed value or lacked message: %#v" , diagnostics [ 0 ] )
}
} )
}
}
func TestSequenceIdentityExcludesStructuralExtendsField ( t * testing . T ) {
item := identityRecord ( map [ string ] * document . Node {
"extends" : nullNode ( ) ,
"name" : stringNode ( "ordinary payload" ) ,
} )
sequence := & document . Node { Kind : document . Sequence , Sequence : [ ] * document . Node { item } }
_ , diagnostics := validateSequenceIdentity ( sequence , Keys ( "items" ) , [ ] string { "extends" } , sequenceIdentityDiagnosticCodes { invalid : CodeComposeInvalid , conflict : CodeComposeConflict } )
if len ( diagnostics ) != 1 || diagnostics [ 0 ] . Path . String ( ) != "/items/0/extends" || diagnostics [ 0 ] . Code != CodeComposeInvalid {
t . Fatalf ( "diagnostics = %#v, want structural field treated as absent" , diagnostics )
}
}
func TestSequenceIdentityUsesLiteralPunctuationFieldNames ( t * testing . T ) {
item := identityRecord ( map [ string ] * document . Node { "metadata.id" : stringNode ( "literal" ) , "metadata" : identityRecord ( map [ string ] * document . Node { "id" : stringNode ( "nested" ) } ) } )
sequence := & document . Node { Kind : document . Sequence , Sequence : [ ] * document . Node { item } }
identities , diagnostics := validateSequenceIdentity ( sequence , Keys ( "items" ) , [ ] string { "metadata.id" } , sequenceIdentityDiagnosticCodes { invalid : CodeComposeInvalid , conflict : CodeComposeConflict } )
if len ( diagnostics ) != 0 {
t . Fatalf ( "diagnostics = %#v" , diagnostics )
}
if len ( identities ) != 1 {
t . Fatalf ( "identity index has %d entries, want 1" , len ( identities ) )
}
}
func TestValidateSequenceIdentityUsesCallerDiagnosticCodes ( t * testing . T ) {
item := identityRecord ( map [ string ] * document . Node { "id" : stringNode ( "same" ) } )
sequence := & document . Node { Kind : document . Sequence , Sequence : [ ] * document . Node { item , document . Clone ( item ) } }
_ , diagnostics := validateSequenceIdentity ( sequence , Keys ( "items" ) , [ ] string { "id" } , sequenceIdentityDiagnosticCodes { invalid : CodeOptionsInvalid , conflict : CodeValidateMutation } )
if len ( diagnostics ) != 1 || diagnostics [ 0 ] . Code != CodeValidateMutation {
t . Fatalf ( "diagnostics = %#v, want caller-selected conflict code" , diagnostics )
}
}
func identityRecord ( fields map [ string ] * document . Node ) * document . Node {
entries := make ( [ ] document . Entry , 0 , len ( fields ) )
keys := make ( [ ] string , 0 , len ( fields ) )
for key := range fields {
keys = append ( keys , key )
}
sort . Strings ( keys )
for _ , key := range keys {
value := fields [ key ]
entries = append ( entries , document . Entry { Key : key , Value : value , ValueLocation : value . Location } )
}
return & document . Node { Kind : document . Mapping , Mapping : entries , Location : document . Location { SourceID : "source" , Line : 2 } }
}
func stringNode ( value string ) * document . Node {
return & document . Node { Kind : document . String , Text : value }
}
func numberNode ( value string ) * document . Node {
return & document . Node { Kind : document . Number , Text : value }
}
func booleanNode ( value string ) * document . Node {
return & document . Node { Kind : document . Boolean , Text : value }
}
func nullNode ( ) * document . Node { return & document . Node { Kind : document . Null } }