Tests for references held like siblings and the lowercase, uppercase and ascii transforms
This commit is contained in:
+6
-6
@@ -88,18 +88,18 @@ func TestCalcReproducible(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestCalcTokenOperandsReadsOnlyACalc pins what the helper answers for a body that
|
||||
// TestTokenOperandsReadsOnlyAnOperandBuiltin pins what the helper answers for a body that
|
||||
// is not a calc, and for one whose expression does not parse: nothing, either way.
|
||||
// checkCalc is what reports a bad expression, so the callers that run after it
|
||||
// never meet one — but they must not have to depend on that order to be safe.
|
||||
func TestCalcTokenOperandsReadsOnlyACalc(t *testing.T) {
|
||||
func TestTokenOperandsReadsOnlyAnOperandBuiltin(t *testing.T) {
|
||||
for _, body := range []string{"plain", "luhn()", "calc()", "calc(1 +)", "calc(()"} {
|
||||
if got := calcTokenOperands(body); got != nil {
|
||||
t.Errorf("calcTokenOperands(%q) = %v, want none", body, got)
|
||||
if got := tokenOperands(body); got != nil {
|
||||
t.Errorf("tokenOperands(%q) = %v, want none", body, got)
|
||||
}
|
||||
}
|
||||
if got := calcTokenOperands("calc(net * qty)"); len(got) != 2 {
|
||||
t.Errorf("calcTokenOperands(calc(net * qty)) = %v, want both operands", got)
|
||||
if got := tokenOperands("calc(net * qty)"); len(got) != 2 {
|
||||
t.Errorf("tokenOperands(calc(net * qty)) = %v, want both operands", got)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+62
-5
@@ -1,6 +1,9 @@
|
||||
package fejkdata
|
||||
|
||||
import "testing"
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// TestRootReferenceAcrossFolders is the headline case: a category in one folder
|
||||
// pulls a value from another via a {..path} reference resolved from the data root.
|
||||
@@ -15,8 +18,7 @@ func TestRootReferenceAcrossFolders(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestReferenceIntoAField reaches a field inside a referenced category, crossing
|
||||
// a single-variant choice and then a template field (..who.last).
|
||||
// TestReferenceIntoAField reaches a field inside a referenced category.
|
||||
func TestReferenceIntoAField(t *testing.T) {
|
||||
dir := writeData(t, map[string]string{
|
||||
"who": `{"format":"{first} {last}","first":"Ada","last":"Byron"}`,
|
||||
@@ -76,8 +78,8 @@ func TestReferenceErrors(t *testing.T) {
|
||||
cases := map[string]map[string]string{
|
||||
"missing target": {"card": `"{..nope.gone}"`},
|
||||
"folder target": {"en_US/word": `"w"`, "card": `"{..en_US}"`},
|
||||
"multi-variant on the path": {
|
||||
"who": `[{"format":"{f}","f":"1"},{"format":"{f}","f":"2"}]`,
|
||||
"a variant on the path lacks the field": {
|
||||
"who": `[{"format":"{f}","f":"1"},{"format":"{g}","g":"2"}]`,
|
||||
"card": `"{..who.f}"`,
|
||||
},
|
||||
"empty reference path": {"card": `"{..}"`},
|
||||
@@ -208,3 +210,58 @@ func TestNewErrorPathIsCanonical(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestReferencePathIsHeld(t *testing.T) {
|
||||
dir := writeData(t, map[string]string{
|
||||
"person": `[{"format":"{first} {last}","first":"Anna","last":"Andersson"},{"format":"{first} {last}","first":"Bo","last":"Berg"}]`,
|
||||
"card": `"{..person.first} {..person.last}"`,
|
||||
})
|
||||
f := newGenerator(t, dir, WithSeed(3))
|
||||
seen := map[string]bool{}
|
||||
for i := 0; i < 50; i++ {
|
||||
got := fake(t, f, "card")
|
||||
if got != "Anna Andersson" && got != "Bo Berg" {
|
||||
t.Fatalf("card = %q, want one person's first and last name", got)
|
||||
}
|
||||
seen[got] = true
|
||||
}
|
||||
if len(seen) != 2 {
|
||||
t.Fatalf("card only ever rendered %v", seen)
|
||||
}
|
||||
}
|
||||
|
||||
func TestReferenceThroughChoiceNeedsEveryVariant(t *testing.T) {
|
||||
_, err := New(WithoutShippedData(), WithDataPath(writeData(t, map[string]string{
|
||||
"who": `[{"format":"{f}{h}","f":"1","h":"x"},{"format":"{g}{h}","g":"2","h":"y"}]`,
|
||||
"card": `"{..who.f}"`,
|
||||
})))
|
||||
if err == nil || !strings.Contains(err.Error(), "not every variant") {
|
||||
t.Fatalf("New = %v, want the missing variant named", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBareReferenceDrawsEachTime(t *testing.T) {
|
||||
dir := writeData(t, map[string]string{
|
||||
"die": `["1","2","3","4","5","6"]`,
|
||||
"roll": `"{..die} {..die}"`,
|
||||
})
|
||||
f := newGenerator(t, dir, WithSeed(1))
|
||||
for i := 0; i < 50; i++ {
|
||||
if got := fake(t, f, "roll"); got[0] != got[2] {
|
||||
return
|
||||
}
|
||||
}
|
||||
t.Fatal("two bare references always agreed; each should be its own draw")
|
||||
}
|
||||
|
||||
func TestReferenceOverlapIsRejected(t *testing.T) {
|
||||
for name, file := range map[string]string{
|
||||
"head beside a path": `{"format":"{..cat.p} {..cat.p.first}","p":[{"format":"{first}","first":"A"},{"format":"{first}","first":"B"}]}`,
|
||||
"sibling path beside a reference path": `{"format":"{p.first} {..cat.p.last}","p":[{"format":"{first}","first":"A","last":"1"},{"format":"{first}","first":"B","last":"2"}]}`,
|
||||
} {
|
||||
_, err := New(WithoutShippedData(), WithDataPath(writeData(t, map[string]string{"cat": file})))
|
||||
if err == nil || !strings.Contains(err.Error(), "reads a path into") {
|
||||
t.Errorf("%s: New = %v, want the overlap rejected", name, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
package fejkdata
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestTransforms(t *testing.T) {
|
||||
f := engine(1)
|
||||
for src, want := range map[string]string{
|
||||
`{"format":"{uppercase(x)}|{lowercase(x)}|{ascii(x)}","x":"Åsa Ödegård-Nuñez"}`: "ÅSA ÖDEGÅRD-NUÑEZ|åsa ödegård-nuñez|Asa Odegard-Nunez",
|
||||
`{"format":"{lowercase(ascii(x))}","x":"Åsa"}`: "asa",
|
||||
`{"format":"{ascii(x)}","x":"Ærø ß 日本"}`: "AEro ss ",
|
||||
} {
|
||||
if got := mustRender(t, f, src); got != want {
|
||||
t.Errorf("render(%s) = %q, want %q", src, got, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestTransformReadsTheHeldDraw(t *testing.T) {
|
||||
f := engine(2)
|
||||
src := `{"format":"{p.first}={lowercase(p.first)}","p":[{"format":"{first}","first":"Anna"},{"format":"{first}","first":"Bo"}]}`
|
||||
for i := 0; i < 50; i++ {
|
||||
if got := mustRender(t, f, src); got != "Anna=anna" && got != "Bo=bo" {
|
||||
t.Fatalf("render = %q, want the transform over the same draw", got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestTransformOverAReference(t *testing.T) {
|
||||
dir := writeData(t, map[string]string{
|
||||
"person": `[{"format":"{first} {last}","first":"Åsa","last":"Öberg"},{"format":"{first} {last}","first":"Bo","last":"Ek"}]`,
|
||||
"email": `"{..person.first} {..person.last} <{lowercase(ascii(..person.first))}.{lowercase(ascii(..person.last))}@example.com>"`,
|
||||
})
|
||||
f := newGenerator(t, dir, WithSeed(5))
|
||||
for i := 0; i < 50; i++ {
|
||||
if got := fake(t, f, "email"); got != "Åsa Öberg <asa.oberg@example.com>" && got != "Bo Ek <bo.ek@example.com>" {
|
||||
t.Fatalf("email = %q, want a record from one draw", got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestTransformArgs(t *testing.T) {
|
||||
for _, bad := range []string{
|
||||
`{"format":"{lowercase()}","x":"v"}`,
|
||||
`{"format":"{lowercase(nope)}","x":"v"}`,
|
||||
`{"format":"{ascii(x,y)}","x":"v","y":"w"}`,
|
||||
`{"format":"{lowercase(hex(2))}","x":"v"}`,
|
||||
`{"format":"{lowercase(x)} {x.a}","x":{"format":"{a}","a":"1"}}`,
|
||||
} {
|
||||
if _, err := compile(parse(t, bad)); err == nil {
|
||||
t.Errorf("compile(%s) = nil error, want it rejected", bad)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user