136 lines
5.5 KiB
Go
136 lines
5.5 KiB
Go
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 TestSourceInfoDestinationConversion(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)
|
|
}
|
|
}
|
|
|
|
func TestSourceVersionCheckConversion(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)
|
|
}
|
|
}
|
|
|
|
func TestImportSelectionConversion(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)
|
|
}
|
|
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")
|
|
}
|
|
}
|
|
|
|
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{}
|
|
}
|