diff --git a/strutil/random.go b/strutil/random.go index fe404a017..4b578d3fe 100644 --- a/strutil/random.go +++ b/strutil/random.go @@ -1,8 +1,7 @@ package strutil import ( - "encoding/base64" - mathRand "math/rand" + mRand "math/rand" "time" "github.com/gookit/goutil/byteutil" @@ -11,7 +10,7 @@ import ( // some consts string chars const ( Numbers = "0123456789" - HexChars = "0123456789abcdef" + HexChars = "0123456789abcdef" // base16 AlphaBet = "abcdefghijklmnopqrstuvwxyz" AlphaBet1 = "AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz" @@ -19,70 +18,47 @@ const ( AlphaNum = "abcdefghijklmnopqrstuvwxyz0123456789" AlphaNum2 = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" AlphaNum3 = "0123456789AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz" - - Base62Chars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" - Base64Chars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ+/" ) // RandomChars generate give length random chars at `a-z` func RandomChars(ln int) string { cs := make([]byte, ln) + // UnixNano: 1607400451937462000 + rn := mRand.New(mRand.NewSource(time.Now().UnixNano())) + for i := 0; i < ln; i++ { - // 1607400451937462000 - mathRand.Seed(time.Now().UnixNano()) - idx := mathRand.Intn(25) // 0 - 25 - cs[i] = AlphaBet[idx] + // rand in 0 - 25 + cs[i] = AlphaBet[rn.Intn(25)] } - return string(cs) } // RandomCharsV2 generate give length random chars in `0-9a-z` func RandomCharsV2(ln int) string { cs := make([]byte, ln) + // UnixNano: 1607400451937462000 + rn := mRand.New(mRand.NewSource(time.Now().UnixNano())) + for i := 0; i < ln; i++ { - // 1607400451937462000 - mathRand.Seed(time.Now().UnixNano()) - idx := mathRand.Intn(35) // 0 - 35 - cs[i] = AlphaNum[idx] + // rand in 0 - 35 + cs[i] = AlphaNum[rn.Intn(35)] } - return string(cs) } // RandomCharsV3 generate give length random chars in `0-9a-zA-Z` func RandomCharsV3(ln int) string { cs := make([]byte, ln) + // UnixNano: 1607400451937462000 + rn := mRand.New(mRand.NewSource(time.Now().UnixNano())) + for i := 0; i < ln; i++ { - // 1607400451937462000 - mathRand.Seed(time.Now().UnixNano()) - idx := mathRand.Intn(61) // 0 - 61 - cs[i] = AlphaNum2[idx] + // rand in 0 - 61 + cs[i] = AlphaNum2[rn.Intn(61)] } - return string(cs) } -// RandomBytes generate -func RandomBytes(length int) ([]byte, error) { - return byteutil.Random(length) -} - -// RandomString generate. -// -// Example: -// -// // this will give us a 44 byte, base64 encoded output -// token, err := RandomString(32) -// if err != nil { -// // Serve an appropriately vague error to the -// // user, but log the details internally. -// } -func RandomString(length int) (string, error) { - b, err := RandomBytes(length) - return base64.URLEncoding.EncodeToString(b), err -} - // RandWithTpl generate random string with give template func RandWithTpl(n int, letters string) string { if len(letters) == 0 { @@ -92,10 +68,26 @@ func RandWithTpl(n int, letters string) string { ln := len(letters) cs := make([]byte, n) for i := 0; i < n; i++ { - mathRand.Seed(int64(time.Now().Nanosecond())) - idx := mathRand.Intn(ln) - cs[i] = letters[idx] + rn := mRand.New(mRand.NewSource(time.Now().UnixNano())) + // rand in 0 - ln + cs[i] = letters[rn.Intn(ln)] } return byteutil.String(cs) } + +// RandomString generate. +// +// Example: +// +// // this will give us a 44 byte, base64 encoded output +// token, err := RandomString(16) // eg: "I7S4yFZddRMxQoudLZZ-eg" +func RandomString(length int) (string, error) { + b, err := RandomBytes(length) + return B64URL.EncodeToString(b), err +} + +// RandomBytes generate +func RandomBytes(length int) ([]byte, error) { + return byteutil.Random(length) +} diff --git a/strutil/random_test.go b/strutil/random_test.go index 85c108f75..862b1cfbc 100644 --- a/strutil/random_test.go +++ b/strutil/random_test.go @@ -1,7 +1,6 @@ package strutil_test import ( - "encoding/base64" "encoding/hex" "fmt" "math/rand" @@ -16,27 +15,62 @@ func TestRandomChars(t *testing.T) { for i := 0; i < 10; i++ { str := strutil.RandomChars(4) fmt.Println(str) - assert.Len(t, str, 4) } } func TestRandomCharsV2(t *testing.T) { + keyMp := make(map[string]bool) for i := 0; i < 10; i++ { - str := strutil.RandomCharsV2(4) + str := strutil.RandomCharsV2(6) fmt.Println(str) + assert.Len(t, str, 6) + keyMp[str] = true + } + assert.Len(t, keyMp, 10) +} - assert.Len(t, str, 4) +// https://github.com/gookit/goutil/issues/121 +func TestRandomCharsV2_issues121(t *testing.T) { + keyMp := make(map[string]bool) + + for i := 0; i < 10; i++ { + str := strutil.RandomCharsV2(32) + fmt.Println(str) + assert.Len(t, str, 32) + keyMp[str] = true } + + assert.Len(t, keyMp, 10) } func TestRandomCharsV3(t *testing.T) { - for i := 0; i < 10; i++ { + size := 10 + keyMp := make(map[string]bool) + + for i := 0; i < size; i++ { str := strutil.RandomCharsV3(4) fmt.Println(str) + assert.Len(t, str, 4) + keyMp[str] = true + } + assert.Len(t, keyMp, size) +} +func TestRandWithTpl(t *testing.T) { + size := 10 + keyMp := make(map[string]bool) + + for i := 0; i < size; i++ { + str := strutil.RandWithTpl(4, strutil.AlphaBet1) + fmt.Println(str) assert.Len(t, str, 4) + keyMp[str] = true } + assert.Len(t, keyMp, size) + + assert.NotEmpty(t, strutil.RandWithTpl(8, "")) + assert.NotEmpty(t, strutil.RandWithTpl(8, strutil.AlphaBet1)) } func TestRandomBytes(t *testing.T) { @@ -44,26 +78,22 @@ func TestRandomBytes(t *testing.T) { // 1607400451937462000 tsn := time.Now().UnixNano() - rand.Seed(tsn) + rn := rand.New(rand.NewSource(tsn)) fmt.Println(tsn) - fmt.Println(rand.Intn(12)) - fmt.Println(rand.Intn(12)) + fmt.Println(rn.Intn(12), rn.Intn(12)) fmt.Println(string(b)) - fmt.Println(base64.URLEncoding.EncodeToString(b)) - fmt.Println(base64.StdEncoding.EncodeToString(b)) + fmt.Println(strutil.B64Std.EncodeToString(b)) + fmt.Println(strutil.B64URL.EncodeToString(b)) fmt.Println(hex.EncodeToString(b)) assert.NoErr(t, err) } func TestRandomString(t *testing.T) { - s, err := strutil.RandomString(3) + s, err := strutil.RandomString(16) fmt.Println(s) assert.NoErr(t, err) assert.True(t, len(s) > 3) - - assert.NotEmpty(t, strutil.RandWithTpl(8, "")) - assert.NotEmpty(t, strutil.RandWithTpl(8, strutil.AlphaBet)) }