Activate ordinary source collection declarations

This commit is contained in:
2026-10-23 19:12:39 +00:00
parent dfeaf90320
commit 9a7027a04c
9 changed files with 448 additions and 41 deletions

View File

@@ -0,0 +1,210 @@
package engine
import (
"errors"
"reflect"
"strings"
"testing"
)
type ordinarySequenceItem struct {
ID string `yaml:"id"`
}
type ordinarySequenceRecord struct {
ID string `yaml:"id"`
Children []ordinarySequenceItem `yaml:"children"`
}
type ordinarySequenceConfig struct {
Items []ordinarySequenceItem `yaml:"items"`
Catalog struct {
Items []ordinarySequenceItem `yaml:"items"`
} `yaml:"catalog"`
Records []ordinarySequenceRecord `yaml:"records"`
}
func TestOrdinaryLoadAcceptsDeclarationsWithoutImports(t *testing.T) {
result, err := testLoad[ordinarySequenceConfig](Bytes("catalog.yml", []byte(`configkit:
sequences:
- destination: [items]
key: id
items:
- id: prompt
`)))
if err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(result.Config.Items, []ordinarySequenceItem{{ID: "prompt"}}) {
t.Fatalf("items = %#v", result.Config.Items)
}
if _, ok := result.Metadata().Lookup(Keys("configkit")); ok {
t.Fatal("collection controls reached application metadata")
}
items, ok := result.Metadata().Lookup(Keys("items"))
if !ok || !items.Explicit || len(items.Origin.Locations) != 1 {
t.Fatalf("items metadata = %#v, %v", items, ok)
}
}
func TestOrdinaryLoadKeepsDisabledImportRejection(t *testing.T) {
_, err := testLoad[ordinarySequenceConfig](Bytes("disabled.yml", []byte(`configkit:
imports: [{path: fragment.yml}]
sequences: [{destination: [items], key: id}]
`)))
if err == nil {
t.Fatal("source with disabled imports succeeded")
}
var loadError *LoadError
if !errors.As(err, &loadError) || len(loadError.Diagnostics()) != 1 || loadError.Diagnostics()[0].Code != CodeImportDisabled {
t.Fatalf("error = %#v", err)
}
}
func TestOrdinaryLoadValidatesSingletonCollectionIdentity(t *testing.T) {
_, err := testLoad[ordinarySequenceConfig](Bytes("missing-identity.yml", []byte(`configkit:
sequences:
- destination: [items]
key: id
items: [{}]
`)))
if err == nil {
t.Fatal("singleton sequence without identity succeeded")
}
var loadError *LoadError
if !errors.As(err, &loadError) || len(loadError.Diagnostics()) != 1 || loadError.Diagnostics()[0].Code != CodeComposeInvalid {
t.Fatalf("error = %#v", err)
}
}
func TestOrdinaryLoadCombinesImportedCollectionPeers(t *testing.T) {
tests := []struct {
name string
second string
want []ordinarySequenceItem
wantCode Code
}{
{name: "distinct identities", second: "items: [{id: second}]\n", want: []ordinarySequenceItem{{ID: "first"}, {ID: "second"}}},
{name: "duplicate peer identity", second: "items: [{id: first}]\n", wantCode: CodeComposeConflict},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
directory := t.TempDir()
mainPath := writeImportFile(t, directory, "main.yml", `configkit:
imports:
- path: first.yml
- path: second.yml
sequences:
- destination: [items]
key: id
mode: append
`)
writeImportFile(t, directory, "first.yml", "items: [{id: first}]\n")
writeImportFile(t, directory, "second.yml", test.second)
result, err := testLoad[ordinarySequenceConfig](File(mainPath), Options[ordinarySequenceConfig]{Imports: true})
if test.wantCode != "" {
if result != nil || err == nil {
t.Fatalf("result, err = %#v, %v", result, err)
}
var loadError *LoadError
if !errors.As(err, &loadError) || len(loadError.Diagnostics()) == 0 || loadError.Diagnostics()[0].Code != test.wantCode {
t.Fatalf("error = %#v", err)
}
return
}
if err != nil {
var loadError *LoadError
if errors.As(err, &loadError) {
t.Fatalf("diagnostics = %#v", loadError.Diagnostics())
}
t.Fatal(err)
}
if !reflect.DeepEqual(result.Config.Items, test.want) {
t.Fatalf("items = %#v, want %#v", result.Config.Items, test.want)
}
inline, err := testLoad[ordinarySequenceConfig](Bytes("inline.yml", []byte(`configkit:
sequences:
- destination: [items]
key: id
mode: append
items: [{id: first}, {id: second}]
`)))
if err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(result.Config.Items, inline.Config.Items) {
t.Fatalf("imported items %#v differ from inline items %#v", result.Config.Items, inline.Config.Items)
}
})
}
}
func TestImportedCollectionDeclarationsUseRelativePlacement(t *testing.T) {
directory := t.TempDir()
mainPath := writeImportFile(t, directory, "main.yml", `configkit:
imports:
- path: first.yml
destination: [catalog]
- path: second.yml
destination: [catalog]
`)
fragment := `configkit:
sequences:
- destination: [items]
key: id
mode: append
items: [{id: ITEM}]
`
writeImportFile(t, directory, "first.yml", strings.ReplaceAll(fragment, "ITEM", "first"))
writeImportFile(t, directory, "second.yml", strings.ReplaceAll(fragment, "ITEM", "second"))
result, err := testLoad[ordinarySequenceConfig](File(mainPath), Options[ordinarySequenceConfig]{Imports: true})
if err != nil {
t.Fatal(err)
}
want := []ordinarySequenceItem{{ID: "first"}, {ID: "second"}}
if !reflect.DeepEqual(result.Config.Catalog.Items, want) {
t.Fatalf("catalog items = %#v, want %#v", result.Config.Catalog.Items, want)
}
}
func TestSequenceItemSourceAppliesItsCollectionDeclarations(t *testing.T) {
directory := t.TempDir()
mainPath := writeImportFile(t, directory, "main.yml", `configkit:
imports:
- path: item.yml
destination: [records]
placement: sequence-item
`)
writeImportFile(t, directory, "item.yml", `configkit:
sequences:
- destination: [children]
key: id
mode: append
id: parent
children: [{id: child}]
`)
result, err := testLoad[ordinarySequenceConfig](File(mainPath), Options[ordinarySequenceConfig]{Imports: true})
if err != nil {
t.Fatal(err)
}
want := []ordinarySequenceRecord{{ID: "parent", Children: []ordinarySequenceItem{{ID: "child"}}}}
if !reflect.DeepEqual(result.Config.Records, want) {
t.Fatalf("records = %#v, want %#v", result.Config.Records, want)
}
}
func TestOrdinaryLoadAllowsDeclarationsWithoutValues(t *testing.T) {
result, err := testLoad[ordinarySequenceConfig](Bytes("policy.yml", []byte(`configkit:
sequences:
- destination: [items]
key: id
`)))
if err != nil {
t.Fatal(err)
}
if result.Config.Items != nil {
t.Fatalf("items = %#v, want absent", result.Config.Items)
}
}