143 lines
5.2 KiB
Go
143 lines
5.2 KiB
Go
package engine
|
|
|
|
import (
|
|
"reflect"
|
|
"testing"
|
|
|
|
"gitea.maximumdirect.net/eric/ConfigKit/internal/document"
|
|
)
|
|
|
|
func TestOverlayDocumentsRecursesMappingsAndReplacesAtomicSubtrees(t *testing.T) {
|
|
baseRoot := parseCompositionDocument(t, "source-1", `shared:
|
|
kept: base
|
|
changed: old
|
|
sequence: [one, two]
|
|
nullable: value
|
|
to_map: scalar
|
|
to_scalar: {child: old}
|
|
`)
|
|
base, diagnostics := composeDocuments(baseRoot)
|
|
if len(diagnostics) != 0 {
|
|
t.Fatal(diagnostics)
|
|
}
|
|
overlay := parseCompositionDocument(t, "source-2", `shared:
|
|
changed: new
|
|
added: overlay
|
|
sequence: []
|
|
nullable: null
|
|
to_map: {child: new}
|
|
to_scalar: scalar
|
|
`)
|
|
baseBefore := document.Clone(base.root)
|
|
overlayBefore := document.Clone(overlay)
|
|
|
|
result, diagnostics := overlayDocuments(base, overlay)
|
|
if len(diagnostics) != 0 {
|
|
t.Fatalf("overlayDocuments() diagnostics = %#v", diagnostics)
|
|
}
|
|
checks := []struct {
|
|
path Path
|
|
kind document.Kind
|
|
text string
|
|
}{
|
|
{path: Keys("shared", "kept"), kind: document.String, text: "base"},
|
|
{path: Keys("shared", "changed"), kind: document.String, text: "new"},
|
|
{path: Keys("shared", "added"), kind: document.String, text: "overlay"},
|
|
{path: Keys("sequence"), kind: document.Sequence},
|
|
{path: Keys("nullable"), kind: document.Null},
|
|
{path: Keys("to_map"), kind: document.Mapping},
|
|
{path: Keys("to_map", "child"), kind: document.String, text: "new"},
|
|
{path: Keys("to_scalar"), kind: document.String, text: "scalar"},
|
|
}
|
|
for _, check := range checks {
|
|
node, ok := documentAtPath(result.root, check.path)
|
|
if !ok || node.Kind != check.kind || node.Text != check.text {
|
|
t.Errorf("node %s = %#v, %v", check.path.String(), node, ok)
|
|
}
|
|
}
|
|
if _, exists := result.origins["/sequence/0"]; exists {
|
|
t.Fatal("replaced empty sequence retained a stale index origin")
|
|
}
|
|
if _, exists := result.origins["/to_scalar/child"]; exists {
|
|
t.Fatal("parent replacement retained a stale child origin")
|
|
}
|
|
shared := result.origins["/shared"]
|
|
if shared.Layer != LayerOverlay || len(shared.Locations) != 2 {
|
|
t.Fatalf("shared mapping origin = %#v", shared)
|
|
}
|
|
if len(result.overlays) != 5 {
|
|
t.Fatalf("overlay records = %#v, want five replacements", result.overlays)
|
|
}
|
|
if !reflect.DeepEqual(base.root, baseBefore) || !reflect.DeepEqual(overlay, overlayBefore) {
|
|
t.Fatal("overlay mutated an input document")
|
|
}
|
|
result.root.Mapping[0].Value.Mapping[0].Value.Text = "changed"
|
|
if !reflect.DeepEqual(base.root, baseBefore) || !reflect.DeepEqual(overlay, overlayBefore) {
|
|
t.Fatal("overlay result aliases an input document")
|
|
}
|
|
}
|
|
|
|
func TestOwnedOverlayKeepsCompositeContributorsAndAcquiredInputs(t *testing.T) {
|
|
baseInput := parseCompositionDocument(t, "source-1", "catalog:\n base: true\n")
|
|
base, diagnostics := composeDocuments(baseInput)
|
|
if len(diagnostics) != 0 {
|
|
t.Fatal(diagnostics)
|
|
}
|
|
first := parseCompositionDocument(t, "source-2", "catalog:\n first: true\n")
|
|
second := parseCompositionDocument(t, "source-3", "catalog:\n second: true\n")
|
|
firstBefore, secondBefore := document.Clone(first), document.Clone(second)
|
|
incoming, diagnostics := composeDocuments(first, second)
|
|
if len(diagnostics) != 0 {
|
|
t.Fatal(diagnostics)
|
|
}
|
|
assembly := newAssemblyAccumulator(base)
|
|
if diagnostics := assembly.applyOverlay(incoming.root, incoming.origins, incoming.applications, LayerOverlay); len(diagnostics) != 0 {
|
|
t.Fatal(diagnostics)
|
|
}
|
|
for _, key := range []string{"base", "first", "second"} {
|
|
if _, ok := documentAtPath(assembly.current.root, Keys("catalog", key)); !ok {
|
|
t.Fatalf("catalog is missing %q", key)
|
|
}
|
|
}
|
|
origin := assembly.current.origins[Keys("catalog").String()]
|
|
if got, want := origin.Locations, []Location{{SourceID: "source-1", Line: 2, Column: 3}, {SourceID: "source-2", Line: 2, Column: 3}, {SourceID: "source-3", Line: 2, Column: 3}}; !reflect.DeepEqual(got, want) {
|
|
t.Fatalf("catalog origin locations = %#v, want %#v", got, want)
|
|
}
|
|
if len(assembly.current.applications) != 3 {
|
|
t.Fatalf("history applications = %d, want three source contributions", len(assembly.current.applications))
|
|
}
|
|
for _, application := range assembly.current.applications[1:] {
|
|
if application.layer != LayerOverlay {
|
|
t.Fatalf("incoming application layer = %q", application.layer)
|
|
}
|
|
}
|
|
assembly.current.root.Mapping[0].Value.Mapping[1].Value.Text = "false"
|
|
if !reflect.DeepEqual(first, firstBefore) || !reflect.DeepEqual(second, secondBefore) ||
|
|
!reflect.DeepEqual(first, assembly.current.applications[1].value) || !reflect.DeepEqual(second, assembly.current.applications[2].value) {
|
|
t.Fatal("working tree mutation changed an acquired input")
|
|
}
|
|
}
|
|
|
|
func TestDisplacedOriginsSortEscapedPointers(t *testing.T) {
|
|
input := parseCompositionDocument(t, "source-1", `values:
|
|
z: old
|
|
a/b: slash
|
|
a~b: tilde
|
|
nested: {x: old}
|
|
`)
|
|
composed, diagnostics := composeDocuments(input)
|
|
if len(diagnostics) != 0 {
|
|
t.Fatal(diagnostics)
|
|
}
|
|
displaced := displacedOrigins(composed.root, composed.origins, Path{})
|
|
want := []string{"", "/values", "/values/a~0b", "/values/a~1b", "/values/nested", "/values/nested/x", "/values/z"}
|
|
if len(displaced) != len(want) {
|
|
t.Fatalf("displaced definitions = %d, want %d", len(displaced), len(want))
|
|
}
|
|
for i, definition := range displaced {
|
|
if got := definition.path.String(); got != want[i] {
|
|
t.Fatalf("displaced[%d] path = %q, want %q", i, got, want[i])
|
|
}
|
|
}
|
|
}
|