Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 44601c90ab | |||
| 8ed8d9bb51 |
+1
-1
@@ -133,7 +133,7 @@ func transformArg(fields map[string]node, a []string) error {
|
|||||||
_, _, err := refShape(leaf)
|
_, _, err := refShape(leaf)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return checkArm(leaf, fields)
|
return checkArm(leaf, fields, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
func transformOperand(a []string) []string {
|
func transformOperand(a []string) []string {
|
||||||
|
|||||||
@@ -31,7 +31,8 @@ An argument containing a { token, or a JSON object, array or string, is a
|
|||||||
template; any other argument is a path (a path never contains a brace, a bracket
|
template; any other argument is a path (a path never contains a brace, a bracket
|
||||||
or a quote). Templates reach the data by reference from the root —
|
or a quote). Templates reach the data by reference from the root —
|
||||||
{/sv_SE.person.last} — whether the data is shipped or layered with --data-path. An
|
{/sv_SE.person.last} — whether the data is shipped or layered with --data-path. An
|
||||||
argument carrying one of those characters but no valid JSON names neither.
|
argument carrying a bracket, a closing brace or a quote but no valid JSON names
|
||||||
|
neither.
|
||||||
|
|
||||||
-d, --data-path D a data directory to layer over the shipped data (repeatable; last wins on a clash)
|
-d, --data-path D a data directory to layer over the shipped data (repeatable; last wins on a clash)
|
||||||
-h, --help print this help, then exit
|
-h, --help print this help, then exit
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
@@ -333,6 +334,15 @@ func TestClassify(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestUsageReferencesResolve(t *testing.T) {
|
||||||
|
for _, token := range regexp.MustCompile(`\{/[^}]+\}`).FindAllString(usage, -1) {
|
||||||
|
code, out, errb := runOut("--seed", "1", token)
|
||||||
|
if code != 0 || strings.TrimSpace(out) == "" {
|
||||||
|
t.Errorf("usage advertises %s: run = %d, %q, stderr %q", token, code, out, errb)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestRunShapeMisuseBeforeLoad(t *testing.T) {
|
func TestRunShapeMisuseBeforeLoad(t *testing.T) {
|
||||||
code, _, errb := runOut("--no-shipped-data", "[abc]")
|
code, _, errb := runOut("--no-shipped-data", "[abc]")
|
||||||
if code != 2 || !strings.Contains(errb, "[abc]") || strings.Contains(errb, "--data-path") {
|
if code != 2 || !strings.Contains(errb, "[abc]") || strings.Contains(errb, "--data-path") {
|
||||||
|
|||||||
+10
-6
@@ -83,12 +83,16 @@ func TestFieldlessTokenHint(t *testing.T) {
|
|||||||
t.Fatalf("FakeTemplate(bare token) = %v, want a hint naming {/sv_SE.person.last}", err)
|
t.Fatalf("FakeTemplate(bare token) = %v, want a hint naming {/sv_SE.person.last}", err)
|
||||||
}
|
}
|
||||||
_, err = f.FakeTemplate(`{"format":"{x}","repeat":2}`)
|
_, err = f.FakeTemplate(`{"format":"{x}","repeat":2}`)
|
||||||
if err == nil || strings.Contains(err.Error(), "bare string") {
|
if err == nil || !strings.Contains(err.Error(), `this template has none — write {/x}`) {
|
||||||
t.Errorf("FakeTemplate(fieldless object) = %v, want an error that does not call it a bare string", err)
|
t.Errorf("FakeTemplate(fieldless object) = %v, want the hint without calling it a bare string", err)
|
||||||
}
|
}
|
||||||
_, err = f.FakeTemplate(`{ /sv_SE.person.last }`)
|
// A hint is only a drop-in where the name is the whole token: {/x} inside a
|
||||||
if err == nil || strings.Contains(err.Error(), "write {") {
|
// transform or an alternation renders a different value, so none is offered.
|
||||||
t.Errorf("FakeTemplate(malformed token) = %v, want no hint naming a spelling that fails too", err)
|
for _, input := range []string{`{ /sv_SE.person.last }`, "{lowercase(x)}", "{x|y}"} {
|
||||||
|
_, err := f.FakeTemplate(input)
|
||||||
|
if err == nil || strings.Contains(err.Error(), "write {") {
|
||||||
|
t.Errorf("FakeTemplate(%q) = %v, want no hint naming a spelling that means something else", input, err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -105,7 +109,7 @@ func TestFakeTemplateErrors(t *testing.T) {
|
|||||||
{`name: {..nope}`, "write {/nope}"},
|
{`name: {..nope}`, "write {/nope}"},
|
||||||
{`{"format":"x"}`, "is a string"},
|
{`{"format":"x"}`, "is a string"},
|
||||||
{`{/misc.country} {/misc.country.alpha2}`, "renders a level"},
|
{`{/misc.country} {/misc.country.alpha2}`, "renders a level"},
|
||||||
{`{"format":"{/misc.country.alpha2} {x}","x":"{/misc.country}"}`, "renders"},
|
{`{"format":"{/misc.country.alpha2} {x}","x":"{/misc.country}"}`, "reads a path into"},
|
||||||
} {
|
} {
|
||||||
_, err := f.FakeTemplate(c.input)
|
_, err := f.FakeTemplate(c.input)
|
||||||
if err == nil || !strings.Contains(err.Error(), c.want) {
|
if err == nil || !strings.Contains(err.Error(), c.want) {
|
||||||
|
|||||||
+5
-3
@@ -140,7 +140,7 @@ func checkTokens(format string, fields map[string]node) error {
|
|||||||
}
|
}
|
||||||
continue // its target is checked at New (see linkRefs)
|
continue // its target is checked at New (see linkRefs)
|
||||||
}
|
}
|
||||||
if err := checkArm(name, fields); err != nil {
|
if err := checkArm(name, fields, len(names) == 1); err != nil {
|
||||||
return fmt.Errorf("token {%s}: %w", t.body, err)
|
return fmt.Errorf("token {%s}: %w", t.body, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -151,7 +151,9 @@ func checkTokens(format string, fields map[string]node) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// checkArm validates one sibling name or path against a template's fields.
|
// checkArm validates one sibling name or path against a template's fields.
|
||||||
func checkArm(name string, fields map[string]node) error {
|
// wholeToken says the name is the token's entire body, so {/name} would render
|
||||||
|
// the same value and can be offered as the reference spelling.
|
||||||
|
func checkArm(name string, fields map[string]node, wholeToken bool) error {
|
||||||
a := splitArm(name, nil)
|
a := splitArm(name, nil)
|
||||||
if err := checkSegments(a); err != nil {
|
if err := checkSegments(a); err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -166,7 +168,7 @@ func checkArm(name string, fields map[string]node) error {
|
|||||||
}
|
}
|
||||||
if len(fields) == 0 {
|
if len(fields) == 0 {
|
||||||
hint := ""
|
hint := ""
|
||||||
if hintableRef(name) {
|
if wholeToken && hintableRef(name) {
|
||||||
hint = fmt.Sprintf(" — write {/%s} to reference the data", name)
|
hint = fmt.Sprintf(" — write {/%s} to reference the data", name)
|
||||||
}
|
}
|
||||||
return fmt.Errorf("no field %q; a token names a sibling field, and this template has none%s", a.key, hint)
|
return fmt.Errorf("no field %q; a token names a sibling field, and this template has none%s", a.key, hint)
|
||||||
|
|||||||
Reference in New Issue
Block a user