forked from brianvoe/gofakeit
-
Notifications
You must be signed in to change notification settings - Fork 0
/
faker.go
112 lines (93 loc) · 2.81 KB
/
faker.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
package gofakeit
import (
"errors"
"math/rand/v2"
"reflect"
"sync"
"github.com/brianvoe/gofakeit/v7/source"
)
// Create global variable to deal with global function call
var GlobalFaker *Faker = New(0)
// Faker struct is the primary struct for using localized
type Faker struct {
Rand rand.Source
// Lock to make thread safe
Locked bool
mu sync.Mutex
}
// New creates and returns a new Faker struct seeded with a given seed
// using the PCG algorithm in lock mode for thread safety
func New(seed uint64) *Faker {
// If seed is 0, use a random crypto seed
if seed == 0 {
faker := NewFaker(source.NewCrypto(), false)
seed = faker.Uint64()
}
return &Faker{
Rand: rand.NewPCG(seed, seed),
Locked: true,
}
}
// NewFaker takes in a rand.Source and thread lock state and returns a new Faker struct
func NewFaker(src rand.Source, lock bool) *Faker {
return &Faker{
Rand: src,
Locked: lock,
}
}
// Seed attempts to seed the Faker with the given seed
func (f *Faker) Seed(args ...any) error {
// Lock if locked
if f.Locked {
f.mu.Lock()
defer f.mu.Unlock()
}
// Ensure GlobalFaker is not nil and Rand is initialized
if GlobalFaker == nil || GlobalFaker.Rand == nil {
return errors.New("GlobalFaker or GlobalFaker.Rand is nil")
}
// If args is empty or 0, seed with a random crypto seed
if len(args) == 0 {
faker := NewFaker(source.NewCrypto(), false)
args = append(args, faker.Uint64())
}
if args[0] == 0 {
faker := NewFaker(source.NewCrypto(), false)
args[0] = faker.Uint64()
}
// Retrieve the Seed method
method := reflect.ValueOf(GlobalFaker.Rand).MethodByName("Seed")
if !method.IsValid() {
return errors.New("Seed method not found")
}
// Adjust args if method requires exactly 2 args but only 1 was provided
if method.Type().NumIn() == 2 && len(args) == 1 {
args = append(args, args[0]) // Duplicate the first value if only one is provided
}
// Get array of function argument types and prepare converted arguments
argTypes := make([]reflect.Type, method.Type().NumIn())
convertedArgs := make([]reflect.Value, len(args))
for i := 0; i < method.Type().NumIn(); i++ {
argTypes[i] = method.Type().In(i)
}
// Convert args to the expected type by the Seed method
for i, arg := range args {
if i < len(argTypes) { // Ensure arg index is within argTypes bounds
argValue := reflect.ValueOf(arg)
// Check if conversion is necessary
if argValue.Type().ConvertibleTo(argTypes[i]) {
convertedArgs[i] = argValue.Convert(argTypes[i])
} else {
// If not convertible, use the argument as is (reflectively)
convertedArgs[i] = argValue
}
}
}
// Dynamically call the Seed method with converted arguments
method.Call(convertedArgs)
return nil
}
// Seed attempts to seed the GlobalFaker with the given seed
func Seed(args ...any) error {
return GlobalFaker.Seed(args...)
}