github.com/treeverse/lakefs@v1.24.1-0.20240520134607-95648127bfb0/pkg/testutil/random.go (about) 1 package testutil 2 3 import ( 4 "io" 5 "math" 6 "math/rand" 7 "strings" 8 "unicode/utf8" 9 ) 10 11 // RandomRune returns a random Unicode rune from rand, weighting at least 12 // num out of den runes to be ASCII. 13 func RandomRune(rand *rand.Rand, num, den int) rune { 14 if rand.Intn(den) < num { 15 return rune(rand.Intn(utf8.RuneSelf)) 16 } 17 for { 18 r := rune(rand.Intn(utf8.MaxRune)) 19 // Almost all chars are legal, so this usually 20 // returns immediately. 21 if utf8.ValidRune(r) { 22 return r 23 } 24 } 25 } 26 27 // RandomString returns a random UTF-8 string of size or almost size bytes 28 // from rand. It is weighted towards using many ASCII characters. 29 func RandomString(rand *rand.Rand, size int) string { 30 sb := strings.Builder{} 31 for sb.Len() <= size { 32 sb.WriteRune(RandomRune(rand, 2, 5)) //nolint: mnd 33 } 34 ret := sb.String() 35 _, lastRuneSize := utf8.DecodeLastRuneInString(ret) 36 return ret[0 : len(ret)-lastRuneSize] 37 } 38 39 type randomReader struct { 40 rand *rand.Rand 41 remaining int64 42 } 43 44 func (r *randomReader) Read(p []byte) (int, error) { 45 if r.remaining <= 0 { 46 return 0, io.EOF 47 } 48 n := len(p) 49 if math.MaxInt >= r.remaining && n > int(r.remaining) { 50 n = int(r.remaining) 51 } 52 // n still fits into int! 53 r.rand.Read(p[:n]) 54 r.remaining -= int64(n) 55 return n, nil 56 } 57 58 // NewRandomReader returns a reader that will return size bytes from rand. 59 func NewRandomReader(rand *rand.Rand, size int64) io.Reader { 60 return &randomReader{rand: rand, remaining: size} 61 }