diff --git a/address.go b/address.go index 340bb94..2ca30b5 100644 --- a/address.go +++ b/address.go @@ -1,7 +1,6 @@ package faker import ( - "math/rand" "reflect" ) diff --git a/datetime.go b/datetime.go index 448c2d6..4f321d8 100644 --- a/datetime.go +++ b/datetime.go @@ -2,7 +2,6 @@ package faker import ( "fmt" - "math/rand" "reflect" "time" ) diff --git a/faker.go b/faker.go index d97bd3a..447f600 100644 --- a/faker.go +++ b/faker.go @@ -3,9 +3,10 @@ package faker // Faker is a simple fake data generator for your own struct. // Save your time, and Fake your data for your testing now. import ( + cryptorand "crypto/rand" "errors" "fmt" - "math/rand" + mathrand "math/rand" "reflect" "regexp" "strconv" @@ -263,10 +264,16 @@ var ( ) func init() { - rand.Seed(time.Now().UnixNano()) + rand = mathrand.New(NewSafeSource(mathrand.NewSource(time.Now().UnixNano()))) + crypto = cryptorand.Reader +} + +func init() { findLangReg, _ = regexp.Compile("lang=[a-z]{3}") findLenReg, _ = regexp.Compile(`len=\d+`) findSliceLenReg, _ = regexp.Compile(`slice_len=\d+`) + + randNameFlag = rand.Intn(100) // for person } // ResetUnique is used to forget generated unique values. diff --git a/faker_test.go b/faker_test.go index 7fff340..4c47701 100644 --- a/faker_test.go +++ b/faker_test.go @@ -2,7 +2,7 @@ package faker import ( "fmt" - "math/rand" + mathrand "math/rand" "reflect" "strings" "testing" @@ -1066,8 +1066,7 @@ func TestExtend(t *testing.T) { a := Sample{} sliceLen := 10 err := AddProvider("myint", func(v reflect.Value) (interface{}, error) { - s1 := rand.NewSource(time.Now().UnixNano()) - r1 := rand.New(s1) + r1 := mathrand.New(NewSafeSource(mathrand.NewSource(time.Now().UnixNano()))) r := make([]MyInt, sliceLen) for i := range r { r[i] = MyInt(r1.Intn(100)) diff --git a/internet.go b/internet.go index 799bee9..cd4f9cd 100644 --- a/internet.go +++ b/internet.go @@ -2,7 +2,6 @@ package faker import ( "fmt" - "math/rand" "net" "reflect" "strings" diff --git a/lorem.go b/lorem.go index 8ce2342..5b3a138 100644 --- a/lorem.go +++ b/lorem.go @@ -2,7 +2,6 @@ package faker import ( "fmt" - "math/rand" "reflect" "strings" ) diff --git a/payment.go b/payment.go index 5625464..1c7dfcd 100644 --- a/payment.go +++ b/payment.go @@ -1,7 +1,6 @@ package faker import ( - "math/rand" "reflect" "strconv" "strings" diff --git a/person.go b/person.go index dc9ccb9..8123fa1 100644 --- a/person.go +++ b/person.go @@ -2,7 +2,6 @@ package faker import ( "fmt" - "math/rand" "reflect" ) @@ -107,7 +106,8 @@ var lastNames = []string{ "Ullrich", "Upton", "Vandervort", "Veum", "Volkman", "Von", "VonRueden", "Waelchi", "Walker", "Walsh", "Walter", "Ward", "Waters", "Watsica", "Weber", "Wehner", "Weimann", "Weissnat", "Welch", "West", "White", "Wiegand", "Wilderman", "Wilkinson", "Will", "Williamson", "Willms", "Windler", "Wintheiser", "Wisoky", "Wisozk", "Witting", "Wiza", "Wolf", "Wolff", "Wuckert", "Wunsch", "Wyman", "Yost", "Yundt", "Zboncak", "Zemlak", "Ziemann", "Zieme", "Zulauf", } -var randNameFlag = rand.Intn(100) + +var randNameFlag int var genders = []string{"Male", "Female", "Prefer to skip"} diff --git a/phone.go b/phone.go index 3c20383..1f6f84f 100644 --- a/phone.go +++ b/phone.go @@ -2,7 +2,6 @@ package faker import ( "fmt" - "math/rand" "reflect" "strings" diff --git a/price.go b/price.go index 71641fa..ca3cf51 100644 --- a/price.go +++ b/price.go @@ -3,7 +3,6 @@ package faker import ( "fmt" "math" - "math/rand" "reflect" ) diff --git a/random_source.go b/random_source.go new file mode 100644 index 0000000..96b7a15 --- /dev/null +++ b/random_source.go @@ -0,0 +1,49 @@ +package faker + +import ( + "io" + mathrand "math/rand" + "sync" +) + +var ( + rand *mathrand.Rand + crypto io.Reader +) + +type safeSource struct { + mx sync.Mutex + mathrand.Source +} + +func (s *safeSource) Int63() int64 { + s.mx.Lock() + defer s.mx.Unlock() + + return s.Source.Int63() +} + +// NewSafeSource wraps an unsafe rand.Source with a mutex to guard the random source +// against concurrent access. +func NewSafeSource(in mathrand.Source) mathrand.Source { + return &safeSource{ + Source: in, + } +} + +// SetRandomSource sets a new random source at the package level. +// +// To use a concurrent-safe source, you may wrap it with NewSafeSource, +// e.g. SetRandomSource(NewSafeSource(mysource)). +// +// The default is the global, concurrent-safe source provided by math/rand. +func SetRandomSource(in mathrand.Source) { + rand = mathrand.New(in) +} + +// SetCryptoSource sets a new reader for functions using a cryptographically-safe random generator (e.g. UUID). +// +// The default is the global source provided by crypto/rand. +func SetCryptoSource(in io.Reader) { + crypto = in +} diff --git a/random_source_test.go b/random_source_test.go new file mode 100644 index 0000000..ed03026 --- /dev/null +++ b/random_source_test.go @@ -0,0 +1,25 @@ +package faker + +import ( + cryptorand "crypto/rand" + "io" + mathrand "math/rand" + "testing" + "time" +) + +func TestSetRandomSource(t *testing.T) { + SetRandomSource(NewSafeSource(mathrand.NewSource(time.Now().UnixNano()))) + + _ = rand.Int31n(100) +} + +func TestSetCryptoSource(t *testing.T) { + SetCryptoSource(cryptorand.Reader) + + buf := make([]byte, 10) + _, err := io.ReadFull(crypto, buf) + if err != nil { + t.Error("Expected Not Error, But Got: ", err) + } +} diff --git a/tag_argument_extractor.go b/tag_argument_extractor.go index 552df7f..701eda2 100644 --- a/tag_argument_extractor.go +++ b/tag_argument_extractor.go @@ -2,7 +2,6 @@ package faker import ( "fmt" - "math/rand" "strconv" "strings" ) diff --git a/uuid.go b/uuid.go index 3009c4a..368919f 100644 --- a/uuid.go +++ b/uuid.go @@ -1,7 +1,6 @@ package faker import ( - "crypto/rand" "fmt" "io" "reflect" @@ -32,7 +31,7 @@ type UUID struct{} // createUUID returns a 16 byte slice with random values func createUUID() ([]byte, error) { b := make([]byte, 16) - _, err := io.ReadFull(rand.Reader, b) + _, err := io.ReadFull(crypto, b) if err != nil { return b, err }