github.com/hairyhenderson/gomplate/v3@v3.11.7/random/random.go (about) 1 // Package random contains functions for generating random values 2 package random 3 4 import ( 5 "fmt" 6 "math" 7 "math/rand" 8 "regexp" 9 "time" 10 "unicode" 11 ) 12 13 func init() { 14 rand.Seed(time.Now().UnixNano()) 15 } 16 17 // Default set, matches "[a-zA-Z0-9_.-]" 18 const defaultSet = "-.0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz" 19 20 // StringRE - Generate a random string that matches a given regular 21 // expression. Defaults to "[a-zA-Z0-9_.-]" 22 func StringRE(count int, match string) (r string, err error) { 23 chars := []rune(defaultSet) 24 if match != "" { 25 chars, err = matchChars(match) 26 if err != nil { 27 return "", err 28 } 29 } 30 31 return rndString(count, chars) 32 } 33 34 // StringBounds returns a random string of characters with a codepoint 35 // between the lower and upper bounds. Only valid characters are returned 36 // and if a range is given where no valid characters can be found, an error 37 // will be returned. 38 func StringBounds(count int, lower, upper rune) (r string, err error) { 39 chars := filterRange(lower, upper) 40 if len(chars) == 0 { 41 return "", fmt.Errorf("no printable codepoints found between U%#q and U%#q", lower, upper) 42 } 43 return rndString(count, chars) 44 } 45 46 // produce a string containing a random selection of given characters 47 func rndString(count int, chars []rune) (string, error) { 48 s := make([]rune, count) 49 for i := range s { 50 //nolint:gosec 51 s[i] = chars[rand.Intn(len(chars))] 52 } 53 return string(s), nil 54 } 55 56 func filterRange(lower, upper rune) []rune { 57 out := []rune{} 58 for r := lower; r <= upper; r++ { 59 if unicode.IsGraphic(r) { 60 out = append(out, r) 61 } 62 } 63 return out 64 } 65 66 func matchChars(match string) ([]rune, error) { 67 r, err := regexp.Compile(match) 68 if err != nil { 69 return nil, err 70 } 71 candidates := filterRange(0, unicode.MaxRune) 72 out := []rune{} 73 for _, c := range candidates { 74 if r.MatchString(string(c)) { 75 out = append(out, c) 76 } 77 } 78 return out, nil 79 } 80 81 // Item - 82 func Item(items []interface{}) (interface{}, error) { 83 if len(items) == 0 { 84 return nil, fmt.Errorf("expected a non-empty array or slice") 85 } 86 if len(items) == 1 { 87 return items[0], nil 88 } 89 90 //nolint:gosec 91 n := rand.Intn(len(items)) 92 return items[n], nil 93 } 94 95 // Number - 96 func Number(min, max int64) (int64, error) { 97 if min > max { 98 return 0, fmt.Errorf("min must not be greater than max (was %d, %d)", min, max) 99 } 100 if min == math.MinInt64 { 101 min++ 102 } 103 if max-min >= (math.MaxInt64 >> 1) { 104 return 0, fmt.Errorf("spread between min and max too high - must not be greater than 63-bit maximum (%d - %d = %d)", max, min, max-min) 105 } 106 107 //nolint:gosec 108 return rand.Int63n(max-min+1) + min, nil 109 } 110 111 // Float - For now this is really just a wrapper around `rand.Float64` 112 func Float(min, max float64) (float64, error) { 113 //nolint:gosec 114 return min + rand.Float64()*(max-min), nil 115 }