218 lines
5.6 KiB
Go
218 lines
5.6 KiB
Go
package fejkdata
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"go/format"
|
|
"io/fs"
|
|
"os"
|
|
"reflect"
|
|
"slices"
|
|
"sort"
|
|
"sync"
|
|
"testing"
|
|
)
|
|
|
|
const shippedIndexFile = "shippedindex.go"
|
|
|
|
// newShippedWhole loads every shipped category in New, as a --data-path load does, so a test
|
|
// reads the whole shipped tree.
|
|
func newShippedWhole(t testing.TB, opts ...Option) *Generator {
|
|
t.Helper()
|
|
data, err := fs.Sub(shippedFS, "data")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
f, err := New(append([]Option{WithoutShippedData(), WithDataFS(data)}, opts...)...)
|
|
if err != nil {
|
|
t.Fatalf("New() = %v", err)
|
|
}
|
|
return f
|
|
}
|
|
|
|
// loadedCategories is the dot path of every category f has parsed and linked.
|
|
func loadedCategories(f *Generator) []string {
|
|
var out []string
|
|
for _, s := range categorySites(&f.root) {
|
|
out = append(out, s.path)
|
|
}
|
|
return out
|
|
}
|
|
|
|
// REGENERATE=1, which go generate sets, rewrites the index.
|
|
func TestShippedIndexIsCurrent(t *testing.T) {
|
|
got, err := shippedIndexSource(newShippedWhole(t))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if os.Getenv("REGENERATE") == "1" {
|
|
if err := os.WriteFile(shippedIndexFile, got, 0o644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
return
|
|
}
|
|
file, err := os.ReadFile(shippedIndexFile)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
want, err := format.Source(file) // docs/decisions.md#the-format-check-runs-on-the-latest-go-only
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if string(got) != string(want) {
|
|
t.Fatalf("%s is stale for data/; regenerate it: docker compose run --rm --user \"$(id -u):$(id -g)\" generate", shippedIndexFile)
|
|
}
|
|
}
|
|
|
|
func shippedIndexSource(whole *Generator) ([]byte, error) {
|
|
var b bytes.Buffer
|
|
b.WriteString("// Code generated by go generate. DO NOT EDIT.\n\npackage fejkdata\n\nvar shippedIndex = map[string]shippedEntry{\n")
|
|
for _, s := range categorySites(&whole.root) {
|
|
fmt.Fprintf(&b, "%q: {", s.path)
|
|
if t, isTable := s.n.(*table); isTable && t.parentIndex >= 0 {
|
|
fmt.Fprintf(&b, "parent: %q, ", t.header[t.parentIndex])
|
|
}
|
|
ps := paths(s.n)
|
|
sort.Strings(ps)
|
|
fmt.Fprintf(&b, "paths: %#v},\n", ps)
|
|
}
|
|
b.WriteString("}\n")
|
|
return format.Source(b.Bytes())
|
|
}
|
|
|
|
func TestNewLoadsNoShippedCategory(t *testing.T) {
|
|
f, err := New()
|
|
if err != nil {
|
|
t.Fatalf("New() = %v", err)
|
|
}
|
|
if got := loadedCategories(f); len(got) > 0 {
|
|
t.Fatalf("New() loaded %v", got)
|
|
}
|
|
}
|
|
|
|
func TestReachingACategoryLoadsWhatItReads(t *testing.T) {
|
|
for _, tc := range []struct {
|
|
reach func(f *Generator) error
|
|
want, absent []string
|
|
}{
|
|
{
|
|
reach: func(f *Generator) error { _, err := f.Fake("sv_SE.person.first"); return err },
|
|
want: []string{"sv_SE.first-name", "sv_SE.last-name", "sv_SE.person", "sv_SE.sex", "sv_SE.title"},
|
|
},
|
|
{
|
|
reach: func(f *Generator) error { _, err := f.Fake("geo.SE.region"); return err },
|
|
want: []string{"geo.SE.locality", "geo.SE.municipality", "geo.SE.postal-code", "geo.SE.region", "geo.SE.street"},
|
|
absent: []string{"geo.SE.address", "geo.US.region"},
|
|
},
|
|
{
|
|
reach: func(f *Generator) error { _, err := f.FakeTemplate("{/misc.territory[SE].name}"); return err },
|
|
want: []string{"misc.territory", "misc.timezone"},
|
|
absent: []string{"misc.tld"},
|
|
},
|
|
{
|
|
reach: func(f *Generator) error { _, err := f.FakeRecord("misc.uuid"); return err },
|
|
want: []string{"misc.uuid"},
|
|
absent: []string{"misc.objectid"},
|
|
},
|
|
{
|
|
reach: func(f *Generator) error {
|
|
var v struct {
|
|
Name string `fake:"sv_SE.first-name"`
|
|
}
|
|
return f.FakeStruct(&v)
|
|
},
|
|
want: []string{"sv_SE.first-name"},
|
|
absent: []string{"sv_SE.person"},
|
|
},
|
|
} {
|
|
f, err := New()
|
|
if err != nil {
|
|
t.Fatalf("New() = %v", err)
|
|
}
|
|
if err := tc.reach(f); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
got := loadedCategories(f)
|
|
for _, w := range tc.want {
|
|
if !slices.Contains(got, w) {
|
|
t.Errorf("loaded %v, want %s among them", got, w)
|
|
}
|
|
}
|
|
for _, a := range tc.absent {
|
|
if slices.Contains(got, a) {
|
|
t.Errorf("loaded %v, want %s left unloaded", got, a)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestADataPathLoadsTheShippedSetWhole(t *testing.T) {
|
|
f, err := New(WithDataPath(writeData(t, map[string]string{"x": `"y"`})))
|
|
if err != nil {
|
|
t.Fatalf("New() = %v", err)
|
|
}
|
|
if got, want := loadedCategories(f), loadedCategories(newShippedWhole(t, WithDataPath(writeData(t, map[string]string{"x": `"y"`})))); !reflect.DeepEqual(got, want) {
|
|
t.Fatalf("loaded %v, want %v", got, want)
|
|
}
|
|
}
|
|
|
|
func TestOnDemandRendersAsTheWholeLoad(t *testing.T) {
|
|
whole := newShippedWhole(t)
|
|
paths := whole.List()
|
|
lazy, err := New()
|
|
if err != nil {
|
|
t.Fatalf("New() = %v", err)
|
|
}
|
|
if got := lazy.List(); !reflect.DeepEqual(got, paths) {
|
|
t.Fatalf("List() on demand = %v, want %v", got, paths)
|
|
}
|
|
a, err := New(WithSeed(7))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
b := newShippedWhole(t, WithSeed(7))
|
|
for _, p := range paths {
|
|
for range 3 {
|
|
got, gotErr := a.Fake(p)
|
|
want, wantErr := b.Fake(p)
|
|
if got != want || (gotErr == nil) != (wantErr == nil) {
|
|
t.Fatalf("Fake(%q) on demand = %q, %v; whole = %q, %v", p, got, gotErr, want, wantErr)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestEveryShippedCategoryLoadsAlone(t *testing.T) {
|
|
for _, p := range sortedNames(shippedIndex) {
|
|
f, err := New()
|
|
if err != nil {
|
|
t.Fatalf("New() = %v", err)
|
|
}
|
|
if _, err := f.Fake(p); err != nil {
|
|
t.Errorf("Fake(%q) on a fresh New() = %v", p, err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestListRunsBesideAnOnDemandLoad(t *testing.T) {
|
|
f, err := New()
|
|
if err != nil {
|
|
t.Fatalf("New() = %v", err)
|
|
}
|
|
var wg sync.WaitGroup
|
|
for _, p := range []string{"sv_SE.person", "geo.US.address", "misc.territory"} {
|
|
wg.Add(2)
|
|
go func() {
|
|
defer wg.Done()
|
|
if _, err := f.Fake(p); err != nil {
|
|
t.Error(err)
|
|
}
|
|
}()
|
|
go func() {
|
|
defer wg.Done()
|
|
f.List()
|
|
}()
|
|
}
|
|
wg.Wait()
|
|
}
|