Files
fejkdata/shape_test.go
T
lilleman 16f2e96fe8
Tests / vet + fmt + tests (pull_request) Successful in 1m7s
Tests / Gitea release from CHANGELOG.md (pull_request) Has been skipped
Tests / vet + fmt + tests (push) Successful in 2m3s
Tests / Gitea release from CHANGELOG.md (push) Successful in 3s
Refuse a release whose tag sits elsewhere, pin a typed nullable column and a relative reference in the reads test, and narrow the pin's claim to template formats
2026-09-16 20:17:50 +02:00

115 lines
2.8 KiB
Go

package fejkdata
import (
"os"
"sort"
"strconv"
"strings"
"testing"
)
const shapePin = "testdata/shipped_shape.txt"
// REPIN=1 rewrites the pin.
func TestShippedShapeIsPinned(t *testing.T) {
f, err := New(WithSeed(1))
if err != nil {
t.Fatal(err)
}
got := shippedShape(f)
if os.Getenv("REPIN") == "1" {
if err := os.WriteFile(shapePin, []byte(got), 0o644); err != nil {
t.Fatal(err)
}
return
}
want, err := os.ReadFile(shapePin)
if err != nil {
t.Fatal(err)
}
if got != string(want) {
t.Fatalf("the shipped shape differs from %s: a removed, renamed or retyped line is a breaking change; add the CHANGELOG.md entry, then repin with REPIN=1", shapePin)
}
}
func shippedShape(f *Generator) string {
facts := map[string]string{}
var walk func(prefix string, n node)
walk = func(prefix string, n node) {
switch n := n.(type) {
case *folder:
for _, name := range sortedNames(n.children) {
walk(join(prefix, name), n.children[name])
}
case *choice:
facts[prefix] = reads(n)
case *template:
facts[prefix] = "\tformat " + strconv.Quote(n.format) + reads(n)
if _, columns, err := recordOf(n); err == nil {
for _, c := range columns {
fact := "\t" + c.DataType.String()
if _, nullable := columnItems(n.fields[c.Name]); nullable {
fact += " null"
}
facts[join(prefix, c.Name)] = fact
}
}
}
}
for _, name := range sortedNames(f.categories) {
walk(name, f.categories[name])
}
var b strings.Builder
for _, p := range f.List() {
b.WriteString(p + facts[p] + "\n")
}
return b.String()
}
// reads names the categories any template under n references, sorted.
func reads(n node) string {
set := map[string]bool{}
var collect func(node)
collect = func(n node) {
switch n := n.(type) {
case *choice:
for _, it := range n.items {
collect(it)
}
case *template:
for _, b := range n.refs {
set[strings.TrimPrefix(b.key, "/")] = true
}
for name, field := range n.fields {
if !isRef(name) {
collect(field)
}
}
}
}
collect(n)
if len(set) == 0 {
return ""
}
keys := make([]string, 0, len(set))
for k := range set {
keys = append(keys, k)
}
sort.Strings(keys)
return "\treads " + strings.Join(keys, " ")
}
func TestShippedShapeNamesReads(t *testing.T) {
f := newGenerator(t, writeData(t, map[string]string{
"a": `{"format":"{x}","x":["{/b}",{"format":"{/c.v}","weight":2}]}`,
"b": `"y"`,
"c": `{"format":"{v} {n}","n":[null,{"format":"{int(1,9)}","datatype":"integer"}],"v":["z","w"]}`,
"d/pos": `["{.q}","{/b}"]`,
"d/q": `"r"`,
}))
want := "a\tformat \"{x}\"\treads b c\na.x\tstring\nb\tformat \"y\"\nc\tformat \"{v} {n}\"\nc.n\tinteger null\nc.v\tstring\nd.pos\treads b d.q\nd.q\tformat \"r\"\n"
if got := shippedShape(f); got != want {
t.Fatalf("shippedShape =\n%s\nwant\n%s", got, want)
}
}