package engine import ( "fmt" "reflect" "strings" "testing" "go.maximumdirect.net/configkit/internal/document" ) func TestMetadataLocationsAcrossBroadAuthoredAndDefaultMappings(t *testing.T) { type config map[string]map[string]string defaults := config{} var body strings.Builder for index := range 96 { name := fmt.Sprintf("authored-%03d", index) fmt.Fprintf(&body, "%s: {present: source}\n", name) defaults[name] = map[string]string{"absent": "default"} defaults[fmt.Sprintf("default-%03d", index)] = map[string]string{"absent": "default"} } input := parseDocumentForDecode(t, body.String()) decoded, issues := decodeConfiguration(mustSchemaFor[config](t), reflect.ValueOf(defaults), input) if len(issues) != 0 { t.Fatal(issues) } located := documentWithMetadataLocations(decoded.final, metadataFromDecoded(decoded), input) inputIndex := buildDocumentLookup(input) locatedIndex := buildDocumentLookup(located) for index := range 96 { authored := Keys(fmt.Sprintf("authored-%03d", index)) mapping, _ := documentAtPathWithLookup(input, authored, inputIndex) present, _ := documentAtPathWithLookup(input, authored.Key("present"), inputIndex) for _, test := range []struct { path Path want document.Location }{ {authored.Key("present"), present.Location}, {authored.Key("absent"), mapping.Location}, {Keys(fmt.Sprintf("default-%03d", index), "absent"), input.Location}, } { node, found := documentAtPathWithLookup(located, test.path, locatedIndex) if !found || node.Location != test.want { t.Fatalf("location at %s = %#v, want %#v", test.path, node, test.want) } } } walkDocument(located, Path{}, func(_ Path, node *document.Node) { for _, entry := range node.Mapping { if entry.KeyLocation != entry.Value.Location || entry.ValueLocation != entry.Value.Location { t.Fatal("entry and value locations disagree") } } }) before := decoded.final.Mapping[0].Value.Mapping[0].Value.Text located.Mapping[0].Value.Mapping[0].Value.Text = "changed snapshot" if decoded.final.Mapping[0].Value.Mapping[0].Value.Text != before || input.Mapping[0].Value.Mapping[0].Value.Text != "source" { t.Fatal("location projection changed a borrowed input") } } func TestIndexedNearestLocationsPreserveMissingAndSyntheticCoordinates(t *testing.T) { root := parseDocumentForDecode(t, "mapping: {'0': value}\nitems: [{value: source}]\nscalar: stop\n") lookup := buildDocumentLookup(root) for _, path := range []Path{Path{}, Keys("missing"), Keys("mapping", "missing"), Keys("mapping", "0"), Keys("mapping").Index(0), Keys("items").Index(4), Keys("items").Index(0).Key("missing"), Keys("scalar", "child"), Path{}.Index(-1)} { want, wantOK := nearestDocumentLocation(root, path) got, gotOK := nearestDocumentLocationWithLookup(root, path, lookup) if got != want || gotOK != wantOK { t.Fatalf("nearest location changed for %s: %#v/%t, want %#v/%t", path, got, gotOK, want, wantOK) } } final := parseDocumentForDecode(t, "value: cli\n") synthetic := Location{SourceID: "cli-1"} metadata := Metadata{ effectivePaths: effectivePathIndex(final), fields: map[string]FieldInfo{"/value": {Origin: Origin{Layer: LayerCLI, Locations: []Location{synthetic}}}}, } located := documentWithMetadataLocations(final, metadata, root) if location := located.Mapping[0].Value.Location; location.SourceID != "cli-1" || location.Line != 0 || location.Column != 0 { t.Fatalf("synthetic CLI location was replaced by fallback: %#v", location) } } func TestMetadataLocationFallbackDoesNotCrossKeyIndexShapes(t *testing.T) { fallback := parseDocumentForDecode(t, "settings:\n - value:\n child: input\n") final := parseDocumentForDecode(t, "settings:\n '0':\n value: final\n") metadata := Metadata{ effectivePaths: effectivePathIndex(final), fields: map[string]FieldInfo{"/settings/0/value": {Origin: Origin{Layer: LayerDefault}}}, } located := documentWithMetadataLocations(final, metadata, fallback) settings, _ := documentAtPath(located, Keys("settings")) value, _ := documentAtPath(located, Keys("settings", "0", "value")) if settings == nil || value == nil || value.Location != settings.Location { t.Fatalf("fallback crossed from a mapping key to an input sequence item: settings %#v, value %#v", settings, value) } inputChild, _ := documentAtPath(fallback, Keys("settings").Index(0).Key("value").Key("child")) if inputChild == nil || value.Location == inputChild.Location { t.Fatalf("fallback fabricated a key location from an index: input child %#v, value %#v", inputChild, value) } } func TestHistoricalLocationSelectionSeparatesNumericKeyAndIndex(t *testing.T) { mappingRoot := &document.Node{Kind: document.Mapping, Mapping: []document.Entry{{ Key: "shape", Value: &document.Node{Kind: document.Mapping, Mapping: []document.Entry{{ Key: "0", Value: &document.Node{Kind: document.Mapping, Mapping: []document.Entry{{ Key: "value", Value: &document.Node{Kind: document.String, Text: "mapping", Location: document.Location{SourceID: "mapping", Line: 3, Column: 5}}, }}}, }}}, }}} sequenceRoot := &document.Node{Kind: document.Mapping, Mapping: []document.Entry{{ Key: "shape", Value: &document.Node{Kind: document.Sequence, Sequence: []*document.Node{{ Kind: document.Mapping, Mapping: []document.Entry{{ Key: "value", Value: &document.Node{Kind: document.String, Text: "sequence", Location: document.Location{SourceID: "sequence", Line: 3, Column: 5}}, }}, }}}, }}} builder := newHistoryBuilder() builder.observeSourceEvidence(sequenceRoot, nil, []historyApplication{ {layer: LayerMain, value: mappingRoot}, {layer: LayerOverlay, value: sequenceRoot}, }, nil) model := builder.freeze() metadata := Metadata{historyModel: model} resolutionOrigin := Origin{Layer: LayerResolution, Operation: ChangeNormalization} for _, test := range []struct { path Path want string }{ {Keys("shape", "0", "value"), "mapping"}, {Keys("shape").Index(0).Key("value"), "sequence"}, } { location, ok := metadataFieldLocation(metadata, test.path, resolutionOrigin) if !ok || location.SourceID != test.want { t.Fatalf("historical location for %s = %#v, %v; want %q", test.path, location, ok, test.want) } } }