Distinguish finite slice views from cycles

This commit is contained in:
2026-10-25 21:22:01 +00:00
parent deb9aa5c69
commit ae3408a096
3 changed files with 86 additions and 0 deletions

View File

@@ -0,0 +1,79 @@
package engine
import (
"reflect"
"testing"
)
type sliceViewConfig struct {
Value []any `yaml:"value"`
}
func finiteSliceView() []any {
shared := []any{"leaf", nil}
shared[1] = shared[:1]
return shared
}
func TestFiniteSliceViewsAreAcceptedAcrossValueBoundaries(t *testing.T) {
want := []any{"leaf", []any{"leaf"}}
mappingSource := Mapping("mapping.yml", map[string]any{"value": finiteSliceView()})
mapping, err := testLoad[sliceViewConfig](mappingSource)
if err != nil || !reflect.DeepEqual(mapping.Config.Value, want) {
t.Fatalf("mapping value = %#v, error = %v", mapping, err)
}
defaults, err := testLoad[sliceViewConfig](NoSource(), Options[sliceViewConfig]{Definition: Definition[sliceViewConfig]{
Defaults: func() sliceViewConfig { return sliceViewConfig{Value: finiteSliceView()} },
}})
if err != nil || !reflect.DeepEqual(defaults.Config.Value, want) {
t.Fatalf("typed default value = %#v, error = %v", defaults, err)
}
override, err := testLoad[sliceViewConfig](NoSource(), Options[sliceViewConfig]{Overrides: []Override{{
Path: Keys("value"), Value: finiteSliceView(), Flag: "--value",
}}})
if err != nil || !reflect.DeepEqual(override.Config.Value, want) {
t.Fatalf("CLI override value = %#v, error = %v", override, err)
}
original := sliceViewConfig{Value: finiteSliceView()}
schema := mustSchemaFor[sliceViewConfig](t)
projected, issue := projectConfiguration(schema, reflect.ValueOf(original), defaultProjectionLimits())
if issue != nil {
t.Fatalf("finite view projection issue = %#v", issue)
}
cloned, issue := cloneConfiguration(schema, reflect.ValueOf(original), defaultProjectionLimits())
if issue != nil {
t.Fatalf("finite view clone issue = %#v", issue)
}
if !reflect.DeepEqual(cloned.Interface(), original) || !reflect.DeepEqual(projected, mappingSource.mapping) {
t.Fatalf("equivalent finite values differ: clone=%#v projected=%#v mapping=%#v", cloned.Interface(), projected, mappingSource.mapping)
}
cloned.FieldByName("Value").Index(1).Interface().([]any)[0] = "changed"
if original.Value[0] != "leaf" || original.Value[1].([]any)[0] != "leaf" {
t.Fatal("mutating a cloned descendant changed the original value")
}
}
func TestSliceCyclesRemainRejected(t *testing.T) {
schema := mustSchemaFor[sliceViewConfig](t)
self := make([]any, 1)
self[0] = self
first := make([]any, 1)
second := make([]any, 1)
first[0], second[0] = second, first
for name, value := range map[string][]any{"self": self, "mutual": first} {
t.Run(name, func(t *testing.T) {
configuration := sliceViewConfig{Value: value}
if _, issue := projectConfiguration(schema, reflect.ValueOf(configuration), defaultProjectionLimits()); issue == nil || issue.code != CodeSchemaCycle {
t.Fatalf("projection cycle issue = %#v", issue)
}
if _, issue := cloneConfiguration(schema, reflect.ValueOf(configuration), defaultProjectionLimits()); issue == nil || issue.code != CodeSchemaCycle {
t.Fatalf("clone cycle issue = %#v", issue)
}
})
}
}