From cc8f8db83f2f3ea20150026b43c160d349ba7de0 Mon Sep 17 00:00:00 2001 From: M Date: Sun, 30 Aug 2026 23:03:12 +0200 Subject: [PATCH] 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 --- bound_test.go | 2 +- edge_test.go | 31 +++++++++++++++++++++++++++---- 2 files changed, 28 insertions(+), 5 deletions(-) diff --git a/bound_test.go b/bound_test.go index 5207fa9..c225615 100644 --- a/bound_test.go +++ b/bound_test.go @@ -405,7 +405,7 @@ func TestDottedTokenErrors(t *testing.T) { }, "dotted field key": { `{"format":"[{a.b}]","a.b":["V"]}`, - `contains a dot`, + `contains "."`, }, } for name, c := range rejected { diff --git a/edge_test.go b/edge_test.go index 9b46e83..a5564f5 100644 --- a/edge_test.go +++ b/edge_test.go @@ -95,11 +95,34 @@ func TestNewErrors(t *testing.T) { }, "category name with a dot": { map[string]string{"a.b": `["1"]`}, - `category "a.b" contains a dot`, + `category "a.b" contains "."`, }, "folder name with a dot": { 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 { @@ -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"}, "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"}, + "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"}, } 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"]}}]`, }) _, 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) } // The same data without the dotted key is fine, and the path resolves.