1package options
2
3import (
4 "errors"
5 "fmt"
6 "math/rand"
7 "reflect"
8 "sync/atomic"
9 "time"
10 "unsafe"
11
12 fakerErrors "github.com/go-faker/faker/v4/pkg/errors"
13 "github.com/go-faker/faker/v4/pkg/interfaces"
14)
15
16var (
17 // global settings, read/write must be concurrent safe
18 generateUniqueValues atomic.Value
19 ignoreInterface atomic.Value
20 randomStringLen int32 = 25
21 lang unsafe.Pointer
22 randomMaxSize int32 = 100
23 randomMinSize int32
24 iBoundary unsafe.Pointer
25)
26
27func init() {
28 generateUniqueValues.Store(false)
29 ignoreInterface.Store(false)
30 lang = unsafe.Pointer(&interfaces.LangENG)
31 iBoundary = unsafe.Pointer(&interfaces.DefaultIntBoundary)
32}
33
34// Options represent all available option for faker.
35type Options struct {
36 // IgnoreFields used for ignoring a field when generating the fake data
37 IgnoreFields map[string]struct{}
38 // FieldProviders used for storing the custom provider function
39 FieldProviders map[string]interfaces.CustomProviderFunction
40 // StructTypeProviders used for storing the struct type of custom provider function
41 StructTypeProviders map[reflect.Type]interfaces.CustomProviderFunction
42 // MaxDepthOption used for configuring the max depth of nested identical structs for faker
43 MaxDepthOption *MaxDepthOption
44 // MaxFieldDepthOption used for configuring the max depth of fields that are filled for a struct
45 MaxFieldDepthOption int
46 // IgnoreInterface used for ignoring any interface field
47 IgnoreInterface bool
48 // StringLanguage used for setting the language for any string in faker
49 StringLanguage *interfaces.LangRuneBoundary
50 // GenerateUniqueValues to ensure the generated data is unique
51 GenerateUniqueValues bool
52 // RandomStringLength to ensure the generated string is expected as we want
53 RandomStringLength int
54 // RandomMaxSliceSize used for setting the maximum of slice size, or map size that will be generated
55 RandomMaxSliceSize int
56 // RandomMinSliceSize used for setting the minimum of slize, array, map size that will be generated
57 RandomMinSliceSize int
58 // MaxGenerateStringRetries set how much tries for generating random string
59 MaxGenerateStringRetries int
60 // SetSliceMapNilIfLenZero allows to set nil for the slice and maps, if size is 0.
61 SetSliceMapNilIfLenZero bool
62 // SetSliceMapRandomToZero sets random integer generation to zero for slice and maps
63 SetSliceMapRandomToZero bool
64 // RandomIntegerBoundary sets boundary random integer value generation. Boundaries can not exceed integer(4 byte...)
65 RandomIntegerBoundary *interfaces.RandomIntegerBoundary
66 // RandomFloatBoundary sets the boundary for random float value generation. Boundaries should comply with float values constraints (IEEE 754)
67 RandomFloatBoundary *interfaces.RandomFloatBoundary
68 // SetTagName sets the tag name that should be used
69 TagName string
70 // CustomDomain is used for specifying a custom domain when generating email
71 CustomDomain *string
72}
73
74// MaxDepthOption used for configuring the max depth of nested struct for faker
75type MaxDepthOption struct {
76 typeSeen map[reflect.Type]int
77 recursionMaxDepth int
78}
79
80func (o *MaxDepthOption) RememberType(t reflect.Type) {
81 o.typeSeen[t]++
82}
83
84func (o *MaxDepthOption) ForgetType(t reflect.Type) {
85 o.typeSeen[t]--
86}
87
88func (o *MaxDepthOption) RecursionOutOfLimit(t reflect.Type) bool {
89 return o.typeSeen[t] > o.recursionMaxDepth
90}
91
92// BuildOptions build all option functions into one option
93func BuildOptions(optFuncs []OptionFunc) *Options {
94 ops := DefaultOption()
95
96 for _, optFunc := range optFuncs {
97 optFunc(ops)
98 }
99
100 return ops
101}
102
103// DefaultOption build the default option
104func DefaultOption() *Options {
105 ops := &Options{}
106 ops.StructTypeProviders = make(map[reflect.Type]interfaces.CustomProviderFunction)
107 ops.StructTypeProviders[reflect.TypeOf(time.Time{})] = func() (interface{}, error) {
108 return time.Now().Add(time.Duration(rand.Int63())), nil
109 }
110 ops.MaxDepthOption = &MaxDepthOption{
111 typeSeen: make(map[reflect.Type]int, 1),
112 recursionMaxDepth: 1,
113 }
114 ops.MaxFieldDepthOption = -1
115 ops.GenerateUniqueValues = generateUniqueValues.Load().(bool)
116 ops.IgnoreInterface = ignoreInterface.Load().(bool)
117 ops.StringLanguage = (*interfaces.LangRuneBoundary)(atomic.LoadPointer(&lang))
118 ops.RandomStringLength = int(atomic.LoadInt32(&randomStringLen))
119 ops.RandomMaxSliceSize = int(atomic.LoadInt32(&randomMaxSize))
120 ops.RandomMinSliceSize = int(atomic.LoadInt32(&randomMinSize))
121 ops.MaxGenerateStringRetries = 1000000 //default
122 ops.RandomIntegerBoundary = (*interfaces.RandomIntegerBoundary)(atomic.LoadPointer(&iBoundary))
123 ops.RandomFloatBoundary = &interfaces.DefaultFloatBoundary
124 ops.TagName = "faker"
125 return ops
126}
127
128// OptionFunc define the options contract
129type OptionFunc func(oo *Options)
130
131// WithFieldsToIgnore used for ignoring a field when generating the fake data
132func WithFieldsToIgnore(fieldNames ...string) OptionFunc {
133 return func(oo *Options) {
134 if oo.IgnoreFields == nil {
135 oo.IgnoreFields = make(map[string]struct{}, len(fieldNames))
136 }
137 for _, f := range fieldNames {
138 oo.IgnoreFields[f] = struct{}{}
139 }
140 }
141}
142
143// WithCustomDomain is used to set a custom domain for generating fake email
144func WithCustomDomain(domain string) OptionFunc {
145 return func(oo *Options) {
146 oo.CustomDomain = &domain
147 }
148}
149
150// WithCustomFieldProvider used for storing the custom provider function
151func WithCustomFieldProvider(fieldName string, provider interfaces.CustomProviderFunction) OptionFunc {
152 return func(oo *Options) {
153 if oo.FieldProviders == nil {
154 oo.FieldProviders = make(map[string]interfaces.CustomProviderFunction, 1)
155 }
156 oo.FieldProviders[fieldName] = provider
157 }
158}
159
160// WithRecursionMaxDepth used for configuring the max depth of recursion struct for faker
161func WithRecursionMaxDepth(depth uint) OptionFunc {
162 return func(oo *Options) {
163 if oo.MaxDepthOption == nil {
164 oo.MaxDepthOption = &MaxDepthOption{
165 recursionMaxDepth: 1, // default
166 typeSeen: make(map[reflect.Type]int, 1),
167 }
168 }
169 oo.MaxDepthOption.recursionMaxDepth = int(depth)
170 }
171}
172
173// WithMaxFieldDepthOption used for configuring the max depth of fields that are filled for a struct
174func WithMaxFieldDepthOption(depth int) OptionFunc {
175 return func(oo *Options) {
176 oo.MaxFieldDepthOption = depth
177 }
178}
179
180// WithStructTypeProviders used for configuring the custom provider of struct type
181func WithStructTypeProviders(t interface{}, provider interfaces.CustomProviderFunction) OptionFunc {
182 if reflect.TypeOf(t).Kind() != reflect.Struct {
183 panic(fakerErrors.ErrOnlyStructTypeSupported)
184 }
185 return func(oo *Options) {
186 oo.StructTypeProviders[reflect.TypeOf(t)] = provider
187 }
188}
189
190// WithIgnoreInterface allows to set a flag to ignore found interface{}s.
191func WithIgnoreInterface(value bool) OptionFunc {
192 return func(oo *Options) {
193 oo.IgnoreInterface = value
194 }
195}
196
197// WithStringLanguage sets language of random string generation (LangENG, LangCHI, LangRUS, LangJPN, LangKOR, EmotEMJ)
198func WithStringLanguage(l interfaces.LangRuneBoundary) OptionFunc {
199 return func(oo *Options) {
200 oo.StringLanguage = &l
201 }
202}
203
204// WithGenerateUniqueValues allows to set the single fake data generator functions to generate unique data.
205func WithGenerateUniqueValues(unique bool) OptionFunc {
206 return func(oo *Options) {
207 oo.GenerateUniqueValues = unique
208 }
209}
210
211// WithRandomStringLength sets a length for random string generation
212func WithRandomStringLength(size uint) OptionFunc {
213 return func(oo *Options) {
214 oo.RandomStringLength = int(size)
215 }
216}
217
218// WithRandomMapAndSliceMaxSize sets the max size for maps and slices for random generation.
219func WithRandomMapAndSliceMaxSize(size uint) OptionFunc {
220 if size < 1 {
221 err := fmt.Errorf(fakerErrors.ErrSmallerThanOne, size)
222 panic(err)
223 }
224 return func(oo *Options) {
225 oo.RandomMaxSliceSize = int(size)
226 }
227}
228
229// WithRandomMapAndSliceMinSize sets the min size for maps and slices for random generation.
230func WithRandomMapAndSliceMinSize(size uint) OptionFunc {
231 return func(oo *Options) {
232 oo.RandomMinSliceSize = int(size)
233 }
234}
235
236// WithMaxGenerateStringRetries set how much tries for generating random string
237func WithMaxGenerateStringRetries(retries uint) OptionFunc {
238 return func(oo *Options) {
239 oo.MaxGenerateStringRetries = int(retries)
240 }
241}
242
243// WithNilIfLenIsZero allows to set nil for the slice and maps, if size is 0.
244func WithNilIfLenIsZero(setNil bool) OptionFunc {
245 return func(oo *Options) {
246 oo.SetSliceMapNilIfLenZero = setNil
247 }
248}
249
250// WithSliceMapRandomToZero Sets random integer generation to zero for slice and maps
251func WithSliceMapRandomToZero(setNumberToZero bool) OptionFunc {
252 return func(oo *Options) {
253 oo.SetSliceMapRandomToZero = setNumberToZero
254 }
255}
256
257// WithRandomIntegerBoundaries sets boundary random integer value generation. Boundaries can not exceed integer(4 byte...)
258func WithRandomIntegerBoundaries(boundary interfaces.RandomIntegerBoundary) OptionFunc {
259 if boundary.Start > boundary.End {
260 err := errors.New(fakerErrors.ErrStartValueBiggerThanEnd)
261 panic(err)
262 }
263 return func(oo *Options) {
264 oo.RandomIntegerBoundary = &boundary
265 }
266}
267
268// WithRandomFloatBoundaries sets the boundary for random float value generation. Boundaries should comply with float values constraints (IEEE 754)
269func WithRandomFloatBoundaries(boundary interfaces.RandomFloatBoundary) OptionFunc {
270 if boundary.Start > boundary.End {
271 err := errors.New(fakerErrors.ErrStartValueBiggerThanEnd)
272 panic(err)
273 }
274 return func(oo *Options) {
275 oo.RandomFloatBoundary = &boundary
276 }
277}
278
279// WithTagName sets the tag name to use. Default tag name is 'faker'.
280func WithTagName(tagName string) OptionFunc {
281 if tagName == "" {
282 err := errors.New(fakerErrors.ErrFieldTagIdentifierInvalid)
283 panic(err)
284 }
285 return func(oo *Options) {
286 oo.TagName = tagName
287 }
288}
289
290// SetGenerateUniqueValues allows to set the single fake data generator functions to generate unique data.
291func SetGenerateUniqueValues(unique bool) {
292 generateUniqueValues.Store(unique)
293}
294
295// SetIgnoreInterface allows to set a flag to ignore found interface{}s.
296func SetIgnoreInterface(ignore bool) {
297 ignoreInterface.Store(ignore)
298}
299
300// SetRandomStringLength sets a length for random string generation
301func SetRandomStringLength(size int) error {
302 if size < 0 {
303 return fmt.Errorf(fakerErrors.ErrSmallerThanZero, size)
304 }
305 atomic.StoreInt32(&randomStringLen, int32(size))
306 return nil
307}
308
309// SetStringLang sets language of random string generation (LangENG, LangCHI, LangRUS, LangJPN, LangKOR, EmotEMJ)
310func SetStringLang(l interfaces.LangRuneBoundary) {
311 atomic.StorePointer(&lang, unsafe.Pointer(&l))
312}
313
314// SetRandomMapAndSliceSize sets the size for maps and slices for random generation.
315// deprecates, currently left for old version usage
316func SetRandomMapAndSliceSize(size int) error {
317 return SetRandomMapAndSliceMaxSize(size)
318}
319
320// SetRandomMapAndSliceMaxSize sets the max size for maps and slices for random generation.
321func SetRandomMapAndSliceMaxSize(size int) error {
322 if size < 1 {
323 return fmt.Errorf(fakerErrors.ErrSmallerThanOne, size)
324 }
325 atomic.StoreInt32(&randomMaxSize, int32(size))
326 return nil
327}
328
329// SetRandomMapAndSliceMinSize sets the min size for maps and slices for random generation.
330func SetRandomMapAndSliceMinSize(size int) error {
331 if size < 0 {
332 return fmt.Errorf(fakerErrors.ErrSmallerThanZero, size)
333 }
334 atomic.StoreInt32(&randomMinSize, int32(size))
335 return nil
336}
337
338// SetRandomNumberBoundaries sets boundary for random number generation
339func SetRandomNumberBoundaries(start, end int) error {
340 if start > end {
341 return errors.New(fakerErrors.ErrStartValueBiggerThanEnd)
342 }
343 ptr := &interfaces.RandomIntegerBoundary{Start: start, End: end}
344 atomic.StorePointer(&iBoundary, unsafe.Pointer(ptr))
345 return nil
346}