Created
January 17, 2020 19:38
-
-
Save srfrog/90101cb8d485e200117fabdd2fa9d2ae to your computer and use it in GitHub Desktop.
Random string generation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package randstr_test | |
import ( | |
"crypto/rand" | |
weak "math/rand" | |
"testing" | |
"time" | |
) | |
const ( | |
randChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" | |
randCharsLen = len(randChars) | |
) | |
// RandStringWeak uses a time-based pseudo random generated string. | |
// This func is fine for tests and limited use values. | |
func RandStringWeak(n int, t time.Time) string { | |
src := weak.NewSource(t.UTC().UnixNano()) | |
b := make([]byte, n) | |
for i := range b { | |
b[i] = randChars[src.Int63()%int64(randCharsLen)] | |
} | |
return string(b) | |
} | |
// RandString returns a random string using a crptographically secure RNG source. | |
// It will panic if n < 0. If n==0 it will return an empty string. | |
// This func may block if there isn't enough entrophy in the RNG source. | |
func RandString(n int) string { | |
bs := make([]byte, n) | |
if _, err := rand.Read(bs); err != nil { | |
return "" | |
} | |
for i, b := range bs { | |
bs[i] = randChars[int(b)%randCharsLen] | |
} | |
return string(bs) | |
} | |
func TestRandStr(t *testing.T) { | |
var tests = []struct { | |
name string | |
len int | |
}{ | |
{name: "len=0", len: 0}, | |
{name: "len=1", len: 1}, | |
{name: "len=2", len: 2}, | |
{name: "len=3", len: 3}, | |
{name: "len=4", len: 4}, | |
{name: "len=8", len: 8}, | |
{name: "len=16", len: 16}, | |
} | |
for _, tc := range tests { | |
t.Run(tc.name, func(t *testing.T) { | |
out := RandString(tc.len) | |
t.Logf("%s\n", out) | |
if len(out) != tc.len { | |
t.Errorf("RandString() = %v, got %v want %v", out, len(out), tc.len) | |
} | |
}) | |
} | |
} | |
func TestRandStrWeak(t *testing.T) { | |
var tests = []struct { | |
name string | |
len int | |
}{ | |
{name: "len=0", len: 0}, | |
{name: "len=1", len: 1}, | |
{name: "len=2", len: 2}, | |
{name: "len=3", len: 3}, | |
{name: "len=4", len: 4}, | |
{name: "len=8", len: 8}, | |
{name: "len=16", len: 16}, | |
} | |
for _, tc := range tests { | |
t.Run(tc.name, func(t *testing.T) { | |
out := RandStringWeak(tc.len, time.Now()) | |
t.Logf("%s\n", out) | |
if len(out) != tc.len { | |
t.Errorf("RandStringWeak() = %v, got %v want %v", out, len(out), tc.len) | |
} | |
}) | |
} | |
} | |
func BenchmarkRandString(b *testing.B) { | |
for i := 0; i < b.N; i++ { | |
RandString(10) | |
} | |
} | |
func BenchmarkRandStringWeak(b *testing.B) { | |
for i := 0; i < b.N; i++ { | |
RandStringWeak(10, time.Now()) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment