package engine import ( "errors" "strings" "testing" ) func TestCompileSequencePolicyNormalizesRegistrations(t *testing.T) { parsed, err := ParsePath("/items/0/a~1b") if err != nil { t.Fatal(err) } tests := []struct { name string registrations []sequenceRegistration want map[string]string wantError bool }{ { name: "identical registrations coalesce", registrations: []sequenceRegistration{ {path: Keys("items"), identityField: "id"}, {path: Keys("items"), identityField: "id"}, }, want: map[string]string{"/items": "id"}, }, { name: "different identity fields conflict", registrations: []sequenceRegistration{ {path: Keys("items"), identityField: "id"}, {path: Keys("items"), identityField: "name"}, }, wantError: true, }, { name: "empty identity field is literal", registrations: []sequenceRegistration{{path: Keys("items"), identityField: ""}}, want: map[string]string{"/items": ""}, }, { name: "numeric and escaped tokens remain literal keys", registrations: []sequenceRegistration{{path: parsed, identityField: "id"}}, want: map[string]string{"/items/0/a~1b": "id"}, }, { name: "explicit index is invalid", registrations: []sequenceRegistration{{path: Keys("items").Index(0), identityField: "id"}}, wantError: true, }, { name: "unused and root registrations are accepted", registrations: []sequenceRegistration{ {path: Path{}, identityField: "id"}, {path: Keys("unused"), identityField: "name"}, }, want: map[string]string{"": "id", "/unused": "name"}, }, {name: "zero option policy", want: map[string]string{}}, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { policy, diagnostics := compileSequencePolicy(test.registrations) if (len(diagnostics) != 0) != test.wantError { t.Fatalf("diagnostics = %#v, wantError = %t", diagnostics, test.wantError) } if test.wantError { if diagnostics[0].Code != CodeOptionsInvalid { t.Fatalf("diagnostic code = %q", diagnostics[0].Code) } return } if len(policy.identityFields) != len(test.want) { t.Fatalf("compiled fields = %#v, want %#v", policy.identityFields, test.want) } for path, field := range test.want { if got := policy.identityFields[path]; got != field { t.Errorf("identity field at %q = %q, want %q", path, got, field) } } }) } } func TestSequenceRegistrationPreflightDoesNotReadSources(t *testing.T) { t.Parallel() type config struct { Value string `yaml:"value"` } ordinaryReader := strings.NewReader("value: ordinary\n") _, err := Load[config](Reader("ordinary.yml", ordinaryReader), SecretBinding{}, Options[config]{ Definition: Definition[config]{sequenceRegistrations: []sequenceRegistration{{path: Keys("items").Index(0), identityField: "id"}}}, }) requireSequenceRegistrationOptionError(t, err) if ordinaryReader.Len() == 0 { t.Fatal("ordinary reader was consumed before invalid registration was rejected") } mainReader := strings.NewReader("value: main\n") underlayReader := strings.NewReader("value: underlay\n") _, err = LoadLayered[config](Input{Source: Reader("main.yml", mainReader)}, SecretBinding{}, LayeredOptions[config]{ Definition: Definition[config]{sequenceRegistrations: []sequenceRegistration{{path: Keys("items").Index(0), identityField: "id"}}}, Underlays: []Underlay{{Inputs: []Input{{Source: Reader("underlay.yml", underlayReader)}}}}, }) requireSequenceRegistrationOptionError(t, err) if mainReader.Len() == 0 || underlayReader.Len() == 0 { t.Fatal("layered source was consumed before invalid registration was rejected") } } func requireSequenceRegistrationOptionError(t *testing.T, err error) { t.Helper() if err == nil { t.Fatal("expected invalid sequence registration error") } var loadErr *LoadError if !errors.As(err, &loadErr) { t.Fatalf("error type = %T, want *LoadError", err) } diagnostics := loadErr.Diagnostics() if len(diagnostics) != 1 || diagnostics[0].Code != CodeOptionsInvalid { t.Fatalf("diagnostics = %#v, want one options diagnostic", diagnostics) } }