diff options
| author | Dave Henderson <dhenderson@gmail.com> | 2019-02-28 20:34:31 -0500 |
|---|---|---|
| committer | Dave Henderson <dhenderson@gmail.com> | 2019-03-17 13:00:23 -0400 |
| commit | 0347dd1f69480206fb23ff754cbf5b459bf06817 (patch) | |
| tree | 91cc47762c0cb13c53d66d969fda29c511523a5a /random/random.go | |
| parent | 13c1c4bf680acb6c9421c30c72ec21a626897b70 (diff) | |
New random namespace for generating random strings and numbers
Signed-off-by: Dave Henderson <dhenderson@gmail.com>
Diffstat (limited to 'random/random.go')
| -rw-r--r-- | random/random.go | 109 |
1 files changed, 109 insertions, 0 deletions
diff --git a/random/random.go b/random/random.go new file mode 100644 index 00000000..58a44d7d --- /dev/null +++ b/random/random.go @@ -0,0 +1,109 @@ +package random + +import ( + "math" + "math/rand" + "regexp" + "time" + "unicode" + + "github.com/pkg/errors" +) + +// Rnd - +var Rnd = rand.New(rand.NewSource(time.Now().UnixNano())) + +// Default set, matches "[a-zA-Z0-9_.-]" +const defaultSet = "-.0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz" + +// StringRE - Generate a random string that matches a given regular +// expression. Defaults to "[a-zA-Z0-9_.-]" +func StringRE(count int, match string) (r string, err error) { + var chars []rune + chars = []rune(defaultSet) + if match != "" { + chars, err = matchChars(match) + if err != nil { + return "", err + } + } + + return rndString(count, chars) +} + +// StringBounds returns a random string of characters with a codepoint +// between the lower and upper bounds. Only valid characters are returned +// and if a range is given where no valid characters can be found, an error +// will be returned. +func StringBounds(count int, lower, upper rune) (r string, err error) { + chars := filterRange(lower, upper) + if len(chars) == 0 { + return "", errors.Errorf("No printable codepoints found between U%#q and U%#q.", lower, upper) + } + return rndString(count, chars) +} + +// produce a string containing a random selection of given characters +func rndString(count int, chars []rune) (string, error) { + s := make([]rune, count) + for i := range s { + s[i] = chars[Rnd.Intn(len(chars))] + } + return string(s), nil +} + +func filterRange(lower, upper rune) []rune { + out := []rune{} + for r := lower; r <= upper; r++ { + if unicode.IsGraphic(r) { + out = append(out, r) + } + } + return out +} + +func matchChars(match string) ([]rune, error) { + r, err := regexp.Compile(match) + if err != nil { + return nil, err + } + candidates := filterRange(0, unicode.MaxRune) + out := []rune{} + for _, c := range candidates { + if r.MatchString(string(c)) { + out = append(out, c) + } + } + return out, nil +} + +// Item - +func Item(items []interface{}) (interface{}, error) { + if len(items) == 0 { + return nil, errors.Errorf("expected a non-empty array or slice") + } + if len(items) == 1 { + return items[0], nil + } + n := Rnd.Intn(len(items)) + return items[n], nil +} + +// Number - +func Number(min, max int64) (int64, error) { + if min > max { + return 0, errors.Errorf("min must not be greater than max (was %d, %d)", min, max) + } + if min == math.MinInt64 { + min++ + } + if max-min >= (math.MaxInt64 >> 1) { + return 0, errors.Errorf("spread between min and max too high - must not be greater than 63-bit maximum (%d - %d = %d)", max, min, max-min) + } + return Rnd.Int63n(max-min+1) + min, nil +} + +// Float - For now this is really just a wrapper around `rand.Float64` +func Float(min, max float64) (float64, error) { + return min + Rnd.Float64()*(max-min), nil +} |
