package configkit import ( "os" "path/filepath" "testing" "gitea.maximumdirect.net/eric/ConfigKit/internal/engine" ) func TestOverlayPublicValues(t *testing.T) { if LayerOverlay != "overlay" { t.Fatalf("LayerOverlay = %q", LayerOverlay) } for code, value := range map[Code]string{ CodeOverlayInvalid: "overlay.invalid", CodeOverlayMissing: "overlay.missing", CodeOverlayOutsideRoot: "overlay.outside_root", CodeOverlayRepeated: "overlay.repeated", CodeOverlayDirective: "overlay.directive", CodeOverlayVersion: "overlay.version", CodeOverlayLimitExceeded: "overlay.limit_exceeded", } { if string(code) != value { t.Errorf("code = %q, want %q", code, value) } } } func TestSourceInfoDestinationConversionsAndCopies(t *testing.T) { destination := Keys("collections", "a/b", "0") path := writeRecordConfig(t, "value: main\n") options := engine.OptionsWithPlacement(engine.Options[map[string]any]{}, engine.Keys("collections", "a/b", "0"), uint8(PlacementModeSequenceItem)) internal := engineSourceInfoFromLoad(t, path, "source-1", options) converted := fromEngineSourceInfo(internal) if converted.Destination.String() != destination.String() || converted.PlacementMode != PlacementModeSequenceItem || converted.DestinationUnresolved { t.Fatalf("public source evidence = %#v", converted) } copy := cloneSourceInfo(converted) copy.Destination = Path{} if converted.Destination.String() != destination.String() { t.Fatalf("source record destination changed through clone: %q", converted.Destination.String()) } } func TestSourceVersionCheckConversionsAndCopies(t *testing.T) { path := Keys("version") file := writeRecordConfig(t, "version: '123'\nvalue: main\n") options := engine.Options[recordConfig]{ Definition: engine.Definition[recordConfig]{ Version: &engine.VersionRule{ Path: engine.Keys("version"), Check: func(version engine.Version, _ *engine.Validation) error { if !version.Present || version.Text != "123" { t.Fatalf("version callback input = %#v", version) } return nil }, }, }, SourceVersionMode: engine.SourceVersionModeFromFacade(uint8(SourceVersionModeIfPresent)), } internal := engineSourceInfoFromLoad(t, file, "source-1", options) converted := fromEngineSourceInfo(internal) if converted.VersionCheck == nil || converted.VersionCheck.Path.String() != path.String() || !converted.VersionCheck.Version.Present || converted.VersionCheck.Version.Text != "123" || converted.VersionCheck.Location == nil || converted.VersionCheck.Location.SourceID != internal.ID || converted.VersionCheck.Location.Line != 1 { t.Fatalf("public source version check = %#v", converted.VersionCheck) } copy := cloneSourceInfo(converted) copy.VersionCheck.Path = Keys("changed") copy.VersionCheck.Version.Text = "changed" copy.VersionCheck.Location.Line = 99 copy.VersionCheck.Redacted = true if converted.VersionCheck.Path.String() != path.String() || converted.VersionCheck.Version.Text != "123" || converted.VersionCheck.Location.Line != 1 || converted.VersionCheck.Redacted { t.Fatalf("source version check changed through a detached copy: %#v", converted.VersionCheck) } } func TestImportSelectionConversionsAndCopies(t *testing.T) { file := writeRecordConfig(t, "configkit:\n imports:\n - glob: absent/*.yml\nvalue: main\n") internal := engineSourceInfoFromLoad(t, file, "source-1", engine.Options[recordConfig]{Imports: true}) converted := fromEngineSourceInfo(internal) if len(converted.ImportSelections) != 1 || converted.ImportSelections[0].Path.String() != "/configkit/imports/0" || converted.ImportSelections[0].Location.SourceID != internal.ID || converted.ImportSelections[0].Location.Line != 3 || converted.ImportSelections[0].Selector != ImportSelectorGlob || converted.ImportSelections[0].Outcome != ImportSelectionNone { t.Fatalf("converted selection evidence = %#v", converted.ImportSelections) } copy := cloneSourceInfo(converted) copy.ImportSelections[0].Path = Keys("copy") copy.ImportSelections[0].Selector = ImportSelectorPath if converted.ImportSelections[0].Path.String() != "/configkit/imports/0" || converted.ImportSelections[0].Selector != ImportSelectorGlob { t.Fatalf("source selection evidence changed through copy: %#v", converted.ImportSelections) } if converted.ImportSelections[0].Outcome != ImportSelectionNone { t.Fatalf("source selection outcome = %q", converted.ImportSelections[0].Outcome) } if fromEngineImportSelections(nil) != nil { t.Fatal("converting nil engine selections returned a non-nil slice") } if fromEngineImportSelections([]engine.ImportSelectionForFacade{}) == nil { t.Fatal("converting an empty engine selection slice returned nil") } empty := cloneSourceInfo(SourceInfo{ImportSelections: make([]ImportSelection, 0)}) if empty.ImportSelections == nil { t.Fatal("cloning collapsed a non-nil empty selection slice") } } func TestOverrideConversionsPreserveSliceShapeAndCopyRecords(t *testing.T) { if toEngineOverrides(nil) != nil { t.Fatal("nil overrides converted to a non-nil slice") } empty := make([]Override, 0) if toEngineOverrides(empty) == nil || toEngineOptions(Options[recordConfig]{Overrides: empty}).Overrides == nil || toEngineLayeredOptions(LayeredOptions[recordConfig]{Overrides: empty}).Overrides == nil { t.Fatal("a non-nil empty override slice was collapsed") } overrides := []Override{{Path: Keys("feature", "enabled"), Value: "yes", Flag: "--feature-enabled"}} ordinary := toEngineOptions(Options[recordConfig]{Overrides: overrides}) layered := toEngineLayeredOptions(LayeredOptions[recordConfig]{Overrides: overrides}) overrides[0] = Override{Path: Keys("changed"), Value: "no", Flag: "--changed"} for label, converted := range map[string][]engine.Override{"ordinary": ordinary.Overrides, "layered": layered.Overrides} { if len(converted) != 1 || converted[0].Path.String() != "/feature/enabled" || converted[0].Value != "yes" || converted[0].Flag != "--feature-enabled" { t.Errorf("%s overrides = %#v", label, converted) } } } type recordConfig struct { Value string `yaml:"value"` Version string `yaml:"version"` } func writeRecordConfig(t *testing.T, content string) string { t.Helper() path := filepath.Join(t.TempDir(), "config.yml") if err := os.WriteFile(path, []byte(content), 0o600); err != nil { t.Fatal(err) } return path } func engineSourceInfoFromLoad[T any](t *testing.T, path, sourceID string, options engine.Options[T]) engine.SourceInfo { t.Helper() loaded, err := engine.Load(engine.File(path), engine.SecretBinding{}, options) if err != nil { t.Fatalf("engine load: %v", err) } for _, source := range loaded.Inspection.Sources() { if source.ID == sourceID { return source } } t.Fatalf("engine inspection contains no source %q", sourceID) return engine.SourceInfo{} }