Keep the real data-path error, reject an empty data path, and report a crypto/rand failure instead of seeding zero
Tests / vet + fmt + tests (pull_request) Successful in 58s
Tests / vet + fmt + tests (pull_request) Successful in 58s
This commit is contained in:
@@ -10,13 +10,14 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// dataSource is one tree to load: an fs.FS and the directory in it to start from.
|
// dataSource is one tree to load: an fs.FS and the directory in it to start from.
|
||||||
// label prefixes file names in errors; path, when set, is a directory on disk that
|
// label prefixes file names in errors; onDisk marks path as a directory that must
|
||||||
// must exist.
|
// exist.
|
||||||
type dataSource struct {
|
type dataSource struct {
|
||||||
fsys fs.FS
|
fsys fs.FS
|
||||||
label string
|
label string
|
||||||
path string
|
onDisk bool
|
||||||
root string
|
path string
|
||||||
|
root string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s dataSource) name(p string) string {
|
func (s dataSource) name(p string) string {
|
||||||
@@ -36,10 +37,13 @@ func (s dataSource) name(p string) string {
|
|||||||
func loadData(sources []dataSource) (map[string]node, error) {
|
func loadData(sources []dataSource) (map[string]node, error) {
|
||||||
root := map[string]node{}
|
root := map[string]node{}
|
||||||
for _, src := range sources {
|
for _, src := range sources {
|
||||||
if src.path != "" {
|
if src.onDisk {
|
||||||
|
if src.path == "" {
|
||||||
|
return nil, fmt.Errorf("a data path is empty")
|
||||||
|
}
|
||||||
info, err := os.Stat(src.path)
|
info, err := os.Stat(src.path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("%s: no such directory", src.path)
|
return nil, err
|
||||||
}
|
}
|
||||||
if !info.IsDir() {
|
if !info.IsDir() {
|
||||||
return nil, fmt.Errorf("%s is not a directory", src.path)
|
return nil, fmt.Errorf("%s is not a directory", src.path)
|
||||||
|
|||||||
+18
-7
@@ -75,7 +75,7 @@ func WithSeed(seed uint64) Option {
|
|||||||
// layer several; the last wins a name clash.
|
// layer several; the last wins a name clash.
|
||||||
func WithDataPath(dir string) Option {
|
func WithDataPath(dir string) Option {
|
||||||
return func(c *config) {
|
return func(c *config) {
|
||||||
c.sources = append(c.sources, dataSource{fsys: os.DirFS(dir), label: dir, path: dir})
|
c.sources = append(c.sources, dataSource{fsys: os.DirFS(dir), label: dir, onDisk: true, path: dir})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -112,7 +112,11 @@ func New(opts ...Option) (*Generator, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("fejkdata: %w", err)
|
return nil, fmt.Errorf("fejkdata: %w", err)
|
||||||
}
|
}
|
||||||
return &Generator{rand: newRand(c.seed, c.seeded), categories: cats}, nil
|
rng, err := newRand(c.seed, c.seeded)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("fejkdata: %w", err)
|
||||||
|
}
|
||||||
|
return &Generator{rand: rng, categories: cats}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// List returns the sorted dotted paths Fake can render: every category, the dotted
|
// List returns the sorted dotted paths Fake can render: every category, the dotted
|
||||||
@@ -203,12 +207,19 @@ func join(prefix, name string) string {
|
|||||||
return prefix + "." + name
|
return prefix + "." + name
|
||||||
}
|
}
|
||||||
|
|
||||||
func newRand(seed uint64, seeded bool) *session {
|
// randomBytes seeds an unseeded generator; a failure is an error, never a fixed seed.
|
||||||
r := rand.New(rand.NewPCG(seed, seed^0x9e3779b97f4a7c15))
|
var randomBytes = crand.Read
|
||||||
if !seeded {
|
|
||||||
|
func newRand(seed uint64, seeded bool) (*session, error) {
|
||||||
|
var r *rand.Rand
|
||||||
|
if seeded {
|
||||||
|
r = rand.New(rand.NewPCG(seed, seed^0x9e3779b97f4a7c15))
|
||||||
|
} else {
|
||||||
var b [16]byte
|
var b [16]byte
|
||||||
_, _ = crand.Read(b[:])
|
if _, err := randomBytes(b[:]); err != nil {
|
||||||
|
return nil, fmt.Errorf("seeding from crypto/rand: %w", err)
|
||||||
|
}
|
||||||
r = rand.New(rand.NewPCG(binary.LittleEndian.Uint64(b[:8]), binary.LittleEndian.Uint64(b[8:])))
|
r = rand.New(rand.NewPCG(binary.LittleEndian.Uint64(b[:8]), binary.LittleEndian.Uint64(b[8:])))
|
||||||
}
|
}
|
||||||
return &session{Rand: r, counters: map[string]uint64{}}
|
return &session{Rand: r, counters: map[string]uint64{}}, nil
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user