Tests for a name no token can spell
A dot is already rejected in a category, folder or field name. The token
grammar reserves three more characters: '|' separates a token's arms, '('
opens a function call, and '}' ends the token. A name carrying one resolves
by dot path and is advertised by List, yet no format can name it.
These pin the rejection, and one accepted case fixes the boundary: ')' on
its own is spellable, so it stays legal.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
+1
-1
@@ -405,7 +405,7 @@ func TestDottedTokenErrors(t *testing.T) {
|
|||||||
},
|
},
|
||||||
"dotted field key": {
|
"dotted field key": {
|
||||||
`{"format":"[{a.b}]","a.b":["V"]}`,
|
`{"format":"[{a.b}]","a.b":["V"]}`,
|
||||||
`contains a dot`,
|
`contains "."`,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for name, c := range rejected {
|
for name, c := range rejected {
|
||||||
|
|||||||
+27
-4
@@ -95,11 +95,34 @@ func TestNewErrors(t *testing.T) {
|
|||||||
},
|
},
|
||||||
"category name with a dot": {
|
"category name with a dot": {
|
||||||
map[string]string{"a.b": `["1"]`},
|
map[string]string{"a.b": `["1"]`},
|
||||||
`category "a.b" contains a dot`,
|
`category "a.b" contains "."`,
|
||||||
},
|
},
|
||||||
"folder name with a dot": {
|
"folder name with a dot": {
|
||||||
map[string]string{"a.b/cat": `["1"]`},
|
map[string]string{"a.b/cat": `["1"]`},
|
||||||
`/a.b: folder "a.b" contains a dot`,
|
`/a.b: folder "a.b" contains "."`,
|
||||||
|
},
|
||||||
|
// The token grammar reserves three more characters. A name carrying one
|
||||||
|
// still resolves by dot path, but no format can name it, so it is rejected
|
||||||
|
// where it is authored rather than at the token that cannot reach it.
|
||||||
|
"field name with a pipe": {
|
||||||
|
map[string]string{"a": `{"format":"{x}","x":["1"],"b|c":["2"]}`},
|
||||||
|
`field "b|c" contains "|"`,
|
||||||
|
},
|
||||||
|
"field name with a paren": {
|
||||||
|
map[string]string{"a": `{"format":"{x}","x":["1"],"b(c":["2"]}`},
|
||||||
|
`field "b(c" contains "("`,
|
||||||
|
},
|
||||||
|
"field name with a closing brace": {
|
||||||
|
map[string]string{"a": `{"format":"{x}","x":["1"],"b}c":["2"]}`},
|
||||||
|
`field "b}c" contains "}"`,
|
||||||
|
},
|
||||||
|
"category name with a pipe": {
|
||||||
|
map[string]string{"a|b": `["1"]`},
|
||||||
|
`category "a|b" contains "|"`,
|
||||||
|
},
|
||||||
|
"folder name with a paren": {
|
||||||
|
map[string]string{"a(b/cat": `["1"]`},
|
||||||
|
`folder "a(b" contains "("`,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for name, c := range rejected {
|
for name, c := range rejected {
|
||||||
@@ -123,7 +146,7 @@ func TestNewErrors(t *testing.T) {
|
|||||||
"hyphenated field": {map[string]string{"a": `{"format":"{x-y}","x-y":["1"]}`}, "a.x-y", "1"},
|
"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"},
|
"category named Format": {map[string]string{"Format": `["1"]`}, "Format", "1"},
|
||||||
"folder named Repeat": {map[string]string{"Repeat/cat": `["1"]`}, "Repeat.cat", "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"},
|
"field with a closing paren": {map[string]string{"a": `{"format":"{b)c}","b)c":["2"]}`}, "a", "2"},
|
||||||
"repeat without a separator": {map[string]string{"a": `{"format":"{x}","repeat":3,"x":["1"]}`}, "a", "111"},
|
"repeat without a separator": {map[string]string{"a": `{"format":"{x}","repeat":3,"x":["1"]}`}, "a", "111"},
|
||||||
}
|
}
|
||||||
for name, c := range accepted {
|
for name, c := range accepted {
|
||||||
@@ -205,7 +228,7 @@ func TestPathKeyIsUnambiguous(t *testing.T) {
|
|||||||
"cat": `[{"format":"{a.b}","a.b":["1"]},{"format":"{a}","a":{"format":"{b}","b":["2"]}}]`,
|
"cat": `[{"format":"{a.b}","a.b":["1"]},{"format":"{a}","a":{"format":"{b}","b":["2"]}}]`,
|
||||||
})
|
})
|
||||||
_, err := New([]string{dir})
|
_, err := New([]string{dir})
|
||||||
if err == nil || !strings.Contains(err.Error(), `field "a.b" contains a dot`) {
|
if err == nil || !strings.Contains(err.Error(), `field "a.b" contains "."`) {
|
||||||
t.Fatalf("New = %v, want the dotted field name rejected", err)
|
t.Fatalf("New = %v, want the dotted field name rejected", err)
|
||||||
}
|
}
|
||||||
// The same data without the dotted key is fine, and the path resolves.
|
// The same data without the dotted key is fine, and the path resolves.
|
||||||
|
|||||||
Reference in New Issue
Block a user