Tests for options that cannot take effect, and entries that are not data

This commit is contained in:
M
2026-08-28 00:17:27 +02:00
committed by lilleman-tw
parent af09a86e71
commit 8d0393713c
2 changed files with 91 additions and 0 deletions
+66
View File
@@ -63,6 +63,72 @@ func TestNewErrors(t *testing.T) {
if _, err := New([]string{writeData(t, map[string]string{"broken": `{ not json`})}); err == nil {
t.Error("New(invalid JSON) = nil error")
}
// An option that cannot take effect, and a category or folder no dot path can
// reach, are mistakes New must name rather than accept and ignore.
rejected := map[string]struct {
files map[string]string
want string
}{
"separator without repeat": {
map[string]string{"a": `{"format":"{x}","x":["1"],"separator":","}`},
"has no effect without a repeat above 1",
},
"separator with an explicit repeat of 1": {
map[string]string{"a": `{"format":"{x}","x":["1"],"repeat":1,"separator":","}`},
"has no effect without a repeat above 1",
},
"weight outside a choice": {
map[string]string{"a": `{"format":"x","weight":5}`},
"weight only skews a choice's items",
},
"an option name used as a token": {
map[string]string{"a": `{"format":"{weight}"}`},
`"weight" is an option, never a field`,
},
"category name with a dot": {
map[string]string{"a.b": `["1"]`},
`category "a.b" contains a dot`,
},
"folder name with a dot": {
map[string]string{"a.b/cat": `["1"]`},
`/a.b: folder "a.b" contains a dot`,
},
}
for name, c := range rejected {
_, err := New([]string{writeData(t, c.files)})
if err == nil {
t.Errorf("%s: New = nil error, want it rejected at load", name)
continue
}
if !strings.Contains(err.Error(), c.want) {
t.Errorf("%s: New = %v, want it to mention %q", name, err, c.want)
}
}
// Data that works today must keep working, and stay reachable.
accepted := map[string]struct {
files map[string]string
path string
want string
}{
"option name as a field": {map[string]string{"a": `{"format":"{name} {Weight}kg","name":["Anvil"],"Weight":["7"]}`}, "a", "Anvil 7kg"},
"format spelling as a field": {map[string]string{"a": `{"format":"{Format}","Format":["PDF"]}`}, "a", "PDF"},
"dotted field via its token": {map[string]string{"a": `{"format":"[{a.b}]","a.b":["V"]}`}, "a", "[V]"},
"hyphenated field": {map[string]string{"a": `{"format":"{x-y}","x-y":["1"]}`}, "a.x-y", "1"},
"category named Format": {map[string]string{"Format": `["1"]`}, "Format", "1"},
"folder named Repeat": {map[string]string{"Repeat/cat": `["1"]`}, "Repeat.cat", "1"},
"field with a paren": {map[string]string{"a": `{"format":"{x}","x":["1"],"b(c":["2"]}`}, "a.b(c", "2"},
"repeat without a separator": {map[string]string{"a": `{"format":"{x}","repeat":3,"x":["1"]}`}, "a", "111"},
}
for name, c := range accepted {
f, err := New([]string{writeData(t, c.files)})
if err != nil {
t.Errorf("%s: New = %v, want it accepted", name, err)
continue
}
if got, err := f.Fake(c.path); err != nil || got != c.want {
t.Errorf("%s: Fake(%q) = %q, %v, want %q", name, c.path, got, err, c.want)
}
}
}
// --- deep path navigation ---
+25
View File
@@ -5,6 +5,7 @@ import (
"path/filepath"
"reflect"
"slices"
"strings"
"testing"
)
@@ -156,3 +157,27 @@ func TestListedPathsAllRender(t *testing.T) {
}
}
}
// TestHiddenEntriesAreSkipped keeps a data directory usable when it is also a
// checkout or an editor workspace: a dot-prefixed entry is not data, and a folder
// carrying no JSON never contributed a namespace, so neither may fail the load.
func TestHiddenEntriesAreSkipped(t *testing.T) {
dir := writeData(t, map[string]string{
"cat": `["V"]`,
".git/HEAD": `["ignored"]`,
".hidden": `["ignored"]`,
"empty.folder/doc": `["ignored"]`,
})
if err := os.Rename(filepath.Join(dir, "empty.folder", "doc.json"), filepath.Join(dir, "empty.folder", "doc.txt")); err != nil {
t.Fatal(err)
}
f := newFakes(t, dir, WithSeed(1))
if got := fake(t, f, "cat"); got != "V" {
t.Fatalf("cat = %q, want V", got)
}
for _, p := range f.List() {
if strings.HasPrefix(p, ".") || strings.Contains(p, "empty.folder") {
t.Errorf("List() advertises %q, which is not data", p)
}
}
}