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  }