package faker // Faker is a simple fake data generator for your own struct. // Save your time, and Fake your data for your testing now. import ( cryptorand "crypto/rand" "errors" "fmt" mathrand "math/rand" "reflect" "regexp" "strconv" "strings" "sync" "time" "github.com/bxcodec/faker/v3/support/slice" ) var ( mu = &sync.Mutex{} // Sets nil if the value type is struct or map and the size of it equals to zero. shouldSetNil = false //Sets random integer generation to zero for slice and maps testRandZero = false //Sets the default number of string when it is created randomly. randomStringLen = 25 //Sets the boundary for random integer value generation. Boundaries can not exceed integer(4 byte...) iBoundary = intBoundary{start: 0, end: 100} //Sets the boundary for random float value generation. Boundaries should comply with float values constraints (IEEE 754) fBoundary = floatBoundary{start: 0, end: 100} //Sets the random max size for slices and maps. randomMaxSize = 100 //Sets the random min size for slices and maps. randomMinSize = 0 // Sets the single fake data generator to generate unique values generateUniqueValues = false // Sets whether interface{}s should be ignored. ignoreInterface = false // Unique values are kept in memory so the generator retries if the value already exists uniqueValues = map[string][]interface{}{} // Lang is selected language for random string generator lang = LangENG // How much tries for generating random string maxGenerateStringRetries = 1000000 ) type intBoundary struct { start int end int } type floatBoundary struct { start float64 end float64 } type langRuneBoundary struct { start rune end rune exclude []rune } // Language rune boundaries here var ( // LangENG is for english language LangENG = langRuneBoundary{65, 122, []rune{91, 92, 93, 94, 95, 96}} // LangCHI is for chinese language LangCHI = langRuneBoundary{19968, 40869, nil} // LangRUS is for russian language LangRUS = langRuneBoundary{1025, 1105, nil} // LangJPN is for japanese Hiragana Katakana language LangJPN = langRuneBoundary{12353, 12534, []rune{12436, 12437, 12438, 12439, 12440, 12441, 12442, 12443, 12444, 12445, 12446, 12447, 12448}} // LangKOR is for korean Hangul language LangKOR = langRuneBoundary{44032, 55203, nil} // EmotEMJ is for emoticons EmotEMJ = langRuneBoundary{126976, 129535, nil} ) // Supported tags const ( letterIdxBits = 6 // 6 bits to represent a letter index letterIdxMask = 1< end { return errors.New(ErrStartValueBiggerThanEnd) } iBoundary = intBoundary{start: start, end: end} return nil } // FakeData is the main function. Will generate a fake data based on your struct. You can use this for automation testing, or anything that need automated data. // You don't need to Create your own data for your testing. func FakeData(a interface{}) error { reflectType := reflect.TypeOf(a) if reflectType.Kind() != reflect.Ptr { return errors.New(ErrValueNotPtr) } if reflect.ValueOf(a).IsNil() { return fmt.Errorf(ErrNotSupportedPointer, reflectType.Elem().String()) } rval := reflect.ValueOf(a) finalValue, err := getValue(a) if err != nil { return err } rval.Elem().Set(finalValue.Elem().Convert(reflectType.Elem())) return nil } // AddProvider extend faker with tag to generate fake data with specified custom algorithm // Example: // type Gondoruwo struct { // Name string // Locatadata int // } // // type Sample struct { // ID int64 `faker:"customIdFaker"` // Gondoruwo Gondoruwo `faker:"gondoruwo"` // Danger string `faker:"danger"` // } // // func CustomGenerator() { // // explicit // faker.AddProvider("customIdFaker", func(v reflect.Value) (interface{}, error) { // return int64(43), nil // }) // // functional // faker.AddProvider("danger", func() faker.TaggedFunction { // return func(v reflect.Value) (interface{}, error) { // return "danger-ranger", nil // } // }()) // faker.AddProvider("gondoruwo", func(v reflect.Value) (interface{}, error) { // obj := Gondoruwo{ // Name: "Power", // Locatadata: 324, // } // return obj, nil // }) // } // // func main() { // CustomGenerator() // var sample Sample // faker.FakeData(&sample) // fmt.Printf("%+v", sample) // } // // Will print // {ID:43 Gondoruwo:{Name:Power Locatadata:324} Danger:danger-ranger} // Notes: when using a custom provider make sure to return the same type as the field func AddProvider(tag string, provider TaggedFunction) error { if _, ok := mapperTag[tag]; ok { return errors.New(ErrTagAlreadyExists) } PriorityTags = append(PriorityTags, tag) mapperTag[tag] = provider return nil } // RemoveProvider removes existing customization added with AddProvider func RemoveProvider(tag string) error { if _, ok := mapperTag[tag]; !ok { return errors.New(ErrTagDoesNotExist) } delete(mapperTag, tag) return nil } func getValue(a interface{}) (reflect.Value, error) { t := reflect.TypeOf(a) if t == nil { if ignoreInterface { return reflect.New(reflect.TypeOf(reflect.Struct)), nil } return reflect.Value{}, fmt.Errorf("interface{} not allowed") } k := t.Kind() switch k { case reflect.Ptr: v := reflect.New(t.Elem()) var val reflect.Value var err error if a != reflect.Zero(reflect.TypeOf(a)).Interface() { val, err = getValue(reflect.ValueOf(a).Elem().Interface()) if err != nil { return reflect.Value{}, err } } else { val, err = getValue(v.Elem().Interface()) if err != nil { return reflect.Value{}, err } } v.Elem().Set(val.Convert(t.Elem())) return v, nil case reflect.Struct: switch t.String() { case "time.Time": ft := time.Now().Add(time.Duration(rand.Int63())) return reflect.ValueOf(ft), nil default: originalDataVal := reflect.ValueOf(a) v := reflect.New(t).Elem() retry := 0 // error if cannot generate unique value after maxRetry tries for i := 0; i < v.NumField(); i++ { if !v.Field(i).CanSet() { continue // to avoid panic to set on unexported field in struct } tags := decodeTags(t, i) switch { case tags.keepOriginal: zero, err := isZero(reflect.ValueOf(a).Field(i)) if err != nil { return reflect.Value{}, err } if zero { err := setDataWithTag(v.Field(i).Addr(), tags.fieldType) if err != nil { return reflect.Value{}, err } continue } v.Field(i).Set(reflect.ValueOf(a).Field(i)) case tags.fieldType == "": val, err := getValue(v.Field(i).Interface()) if err != nil { return reflect.Value{}, err } val = val.Convert(v.Field(i).Type()) v.Field(i).Set(val) case tags.fieldType == SKIP: item := originalDataVal.Field(i).Interface() if v.CanSet() && item != nil { v.Field(i).Set(reflect.ValueOf(item)) } default: err := setDataWithTag(v.Field(i).Addr(), tags.fieldType) if err != nil { return reflect.Value{}, err } } if tags.unique { if retry >= maxRetry { return reflect.Value{}, fmt.Errorf(ErrUniqueFailure, reflect.TypeOf(a).Field(i).Name) } value := v.Field(i).Interface() if slice.ContainsValue(uniqueValues[tags.fieldType], value) { // Retry if unique value already found i-- retry++ continue } retry = 0 uniqueValues[tags.fieldType] = append(uniqueValues[tags.fieldType], value) } else { retry = 0 } } return v, nil } case reflect.String: res, err := randomString(randomStringLen, &lang) return reflect.ValueOf(res), err case reflect.Slice: len := randomSliceAndMapSize() if shouldSetNil && len == 0 { return reflect.Zero(t), nil } v := reflect.MakeSlice(t, len, len) for i := 0; i < v.Len(); i++ { val, err := getValue(v.Index(i).Interface()) if err != nil { return reflect.Value{}, err } val = val.Convert(v.Index(i).Type()) v.Index(i).Set(val) } return v, nil case reflect.Array: v := reflect.New(t).Elem() for i := 0; i < v.Len(); i++ { val, err := getValue(v.Index(i).Interface()) if err != nil { return reflect.Value{}, err } val = val.Convert(v.Index(i).Type()) v.Index(i).Set(val) } return v, nil case reflect.Int: return reflect.ValueOf(randomInteger()), nil case reflect.Int8: return reflect.ValueOf(int8(randomInteger())), nil case reflect.Int16: return reflect.ValueOf(int16(randomInteger())), nil case reflect.Int32: return reflect.ValueOf(int32(randomInteger())), nil case reflect.Int64: return reflect.ValueOf(int64(randomInteger())), nil case reflect.Float32: return reflect.ValueOf(float32(randomFloat())), nil case reflect.Float64: return reflect.ValueOf(randomFloat()), nil case reflect.Bool: val := rand.Intn(2) > 0 return reflect.ValueOf(val), nil case reflect.Uint: return reflect.ValueOf(uint(randomInteger())), nil case reflect.Uint8: return reflect.ValueOf(uint8(randomInteger())), nil case reflect.Uint16: return reflect.ValueOf(uint16(randomInteger())), nil case reflect.Uint32: return reflect.ValueOf(uint32(randomInteger())), nil case reflect.Uint64: return reflect.ValueOf(uint64(randomInteger())), nil case reflect.Map: len := randomSliceAndMapSize() if shouldSetNil && len == 0 { return reflect.Zero(t), nil } v := reflect.MakeMap(t) for i := 0; i < len; i++ { keyInstance := reflect.New(t.Key()).Elem().Interface() key, err := getValue(keyInstance) if err != nil { return reflect.Value{}, err } valueInstance := reflect.New(t.Elem()).Elem().Interface() val, err := getValue(valueInstance) if err != nil { return reflect.Value{}, err } v.SetMapIndex(key, val) } return v, nil default: err := fmt.Errorf("no support for kind %+v", t) return reflect.Value{}, err } } func isZero(field reflect.Value) (bool, error) { if field.Kind() == reflect.Map { return field.Len() == 0, nil } for _, kind := range []reflect.Kind{reflect.Struct, reflect.Slice, reflect.Array} { if kind == field.Kind() { return false, fmt.Errorf("keep not allowed on struct") } } return reflect.Zero(field.Type()).Interface() == field.Interface(), nil } func decodeTags(typ reflect.Type, i int) structTag { tagField := typ.Field(i).Tag.Get(tagName) tags := strings.Split(tagField, ",") keepOriginal := false uni := false res := make([]string, 0) pMap := make(map[string]string) for _, tag := range tags { if tag == keep { keepOriginal = true continue } else if tag == unique { uni = true continue } // res = append(res, tag) ptag := strings.ToLower(strings.Trim(strings.Split(tag, "=")[0], " ")) pMap[ptag] = tag ptag = strings.ToLower(strings.Trim(strings.Split(tag, ":")[0], " ")) pMap[ptag] = tag } // Priority for _, ptag := range PriorityTags { if tag, ok := pMap[ptag]; ok { if ptag == ONEOF { res = append(res, tags...) } else { res = append(res, tag) } delete(pMap, ptag) } } // custom,keep,unique if len(res) < 1 { if !keepOriginal && !uni { res = append(res, tags...) } } return structTag{ fieldType: strings.Join(res, ","), unique: uni, keepOriginal: keepOriginal, } } type structTag struct { fieldType string unique bool keepOriginal bool } func setDataWithTag(v reflect.Value, tag string) error { if v.Kind() != reflect.Ptr { return errors.New(ErrValueNotPtr) } v = reflect.Indirect(v) switch v.Kind() { case reflect.Ptr: if _, exist := mapperTag[tag]; !exist { return fmt.Errorf(ErrTagNotSupported, tag) } if _, def := defaultTag[tag]; !def { res, err := mapperTag[tag](v) if err != nil { return err } v.Set(reflect.ValueOf(res)) return nil } t := v.Type() newv := reflect.New(t.Elem()) res, err := mapperTag[tag](newv.Elem()) if err != nil { return err } rval := reflect.ValueOf(res) newv.Elem().Set(rval) v.Set(newv) return nil case reflect.String: return userDefinedString(v, tag) case reflect.Int, reflect.Int32, reflect.Int64, reflect.Int8, reflect.Int16, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Float32, reflect.Float64: return userDefinedNumber(v, tag) case reflect.Slice, reflect.Array: return userDefinedArray(v, tag) case reflect.Map: return userDefinedMap(v, tag) default: if _, exist := mapperTag[tag]; !exist { return fmt.Errorf(ErrTagNotSupported, tag) } res, err := mapperTag[tag](v) if err != nil { return err } v.Set(reflect.ValueOf(res)) } return nil } func userDefinedMap(v reflect.Value, tag string) error { if tagFunc, ok := mapperTag[tag]; ok { res, err := tagFunc(v) if err != nil { return err } v.Set(reflect.ValueOf(res)) return nil } len := randomSliceAndMapSize() if shouldSetNil && len == 0 { v.Set(reflect.Zero(v.Type())) return nil } definedMap := reflect.MakeMap(v.Type()) for i := 0; i < len; i++ { key, err := getValueWithTag(v.Type().Key(), tag) if err != nil { return err } val, err := getValueWithTag(v.Type().Elem(), tag) if err != nil { return err } definedMap.SetMapIndex(reflect.ValueOf(key), reflect.ValueOf(val)) } v.Set(definedMap) return nil } func getValueWithTag(t reflect.Type, tag string) (interface{}, error) { switch t.Kind() { case reflect.Int, reflect.Int32, reflect.Int64, reflect.Int8, reflect.Int16, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Float32, reflect.Float64: res, err := extractNumberFromTag(tag, t) if err != nil { return nil, err } return res, nil case reflect.String: res, err := extractStringFromTag(tag) if err != nil { return nil, err } return res, nil default: return 0, errors.New(ErrUnknownType) } } func userDefinedArray(v reflect.Value, tag string) error { _, tagExists := mapperTag[tag] if tagExists { res, err := mapperTag[tag](v) if err != nil { return err } v.Set(reflect.ValueOf(res)) return nil } sliceLen, err := extractSliceLengthFromTag(tag) if err != nil { return err } if shouldSetNil && sliceLen == 0 { v.Set(reflect.Zero(v.Type())) return nil } array := reflect.MakeSlice(v.Type(), sliceLen, sliceLen) for i := 0; i < sliceLen; i++ { res, err := getValueWithTag(v.Type().Elem(), tag) if err != nil { return err } array.Index(i).Set(reflect.ValueOf(res)) } v.Set(array) return nil } func userDefinedString(v reflect.Value, tag string) error { var res interface{} var err error if tagFunc, ok := mapperTag[tag]; ok { res, err = tagFunc(v) if err != nil { return err } } else { res, err = extractStringFromTag(tag) if err != nil { return err } } if res == nil { return fmt.Errorf(ErrTagNotSupported, tag) } val, _ := res.(string) v.SetString(val) return nil } func userDefinedNumber(v reflect.Value, tag string) error { var res interface{} var err error if tagFunc, ok := mapperTag[tag]; ok { res, err = tagFunc(v) if err != nil { return err } } else { res, err = extractNumberFromTag(tag, v.Type()) if err != nil { return err } } if res == nil { return fmt.Errorf(ErrTagNotSupported, tag) } v.Set(reflect.ValueOf(res)) return nil } //extractSliceLengthFromTag checks if the sliceLength tag 'slice_len' is set, if so, returns its value, else return a random length func extractSliceLengthFromTag(tag string) (int, error) { if strings.Contains(tag, SliceLength) { lenParts := strings.SplitN(findSliceLenReg.FindString(tag), Equals, -1) if len(lenParts) != 2 { return 0, fmt.Errorf(ErrWrongFormattedTag, tag) } sliceLen, err := strconv.Atoi(lenParts[1]) if err != nil { return 0, fmt.Errorf("the given sliceLength has to be numeric, tag: %s", tag) } if sliceLen < 0 { return 0, fmt.Errorf("slice length can not be negative, tag: %s", tag) } return sliceLen, nil } return randomSliceAndMapSize(), nil //Returns random slice length if the sliceLength tag isn't set } func extractStringFromTag(tag string) (interface{}, error) { var err error strlen := randomStringLen strlng := &lang isOneOfTag := strings.Contains(tag, ONEOF) if !strings.Contains(tag, Length) && !strings.Contains(tag, Language) && !isOneOfTag { return nil, fmt.Errorf(ErrTagNotSupported, tag) } if strings.Contains(tag, Length) { lenParts := strings.SplitN(findLenReg.FindString(tag), Equals, -1) if len(lenParts) != 2 { return nil, fmt.Errorf(ErrWrongFormattedTag, tag) } strlen, _ = strconv.Atoi(lenParts[1]) } if strings.Contains(tag, Language) { strlng, err = extractLangFromTag(tag) if err != nil { return nil, fmt.Errorf(ErrWrongFormattedTag, tag) } } if isOneOfTag { var args []string args, err = fetchOneOfArgsFromTag(tag) if err != nil { return nil, err } toRet := args[rand.Intn(len(args))] return strings.TrimSpace(toRet), nil } res, err := randomString(strlen, strlng) return res, err } func extractLangFromTag(tag string) (*langRuneBoundary, error) { text := findLangReg.FindString(tag) texts := strings.SplitN(text, Equals, -1) if len(texts) != 2 { return nil, fmt.Errorf(ErrWrongFormattedTag, text) } switch strings.ToLower(texts[1]) { case "eng": return &LangENG, nil case "rus": return &LangRUS, nil case "chi": return &LangCHI, nil case "jpn": return &LangJPN, nil case "kor": return &LangKOR, nil case "emj": return &EmotEMJ, nil default: return &LangENG, nil } } func extractNumberFromTag(tag string, t reflect.Type) (interface{}, error) { hasOneOf := strings.Contains(tag, ONEOF) hasBoundaryStart := strings.Contains(tag, BoundaryStart) hasBoundaryEnd := strings.Contains(tag, BoundaryEnd) usingOneOfTag := hasOneOf && (!hasBoundaryStart && !hasBoundaryEnd) usingBoundariesTags := !hasOneOf && (hasBoundaryStart && hasBoundaryEnd) if !usingOneOfTag && !usingBoundariesTags { return nil, fmt.Errorf(ErrTagNotSupported, tag) } // handling oneof tag if usingOneOfTag { args, err := fetchOneOfArgsFromTag(tag) if err != nil { return nil, err } switch t.Kind() { case reflect.Float64: { toRet, err := extractFloat64FromTagArgs(args) if err != nil { return nil, err } return toRet.(float64), nil } case reflect.Float32: { toRet, err := extractFloat32FromTagArgs(args) if err != nil { return nil, err } return toRet.(float32), nil } case reflect.Int64: { toRet, err := extractInt64FromTagArgs(args) if err != nil { return nil, err } return toRet.(int64), nil } case reflect.Int32: { toRet, err := extractInt32FromTagArgs(args) if err != nil { return nil, err } return toRet.(int32), nil } case reflect.Int16: { toRet, err := extractInt16FromTagArgs(args) if err != nil { return nil, err } return toRet.(int16), nil } case reflect.Int8: { toRet, err := extractInt8FromTagArgs(args) if err != nil { return nil, err } return toRet.(int8), nil } case reflect.Int: { toRet, err := extractIntFromTagArgs(args) if err != nil { return nil, err } return toRet.(int), nil } case reflect.Uint64: { toRet, err := extractUint64FromTagArgs(args) if err != nil { return nil, err } return toRet.(uint64), nil } case reflect.Uint32: { toRet, err := extractUint32FromTagArgs(args) if err != nil { return nil, err } return toRet.(uint32), nil } case reflect.Uint16: { toRet, err := extractUint16FromTagArgs(args) if err != nil { return nil, err } return toRet.(uint16), nil } case reflect.Uint8: { toRet, err := extractUint8FromTagArgs(args) if err != nil { return nil, err } return toRet.(uint8), nil } case reflect.Uint: { toRet, err := extractUintFromTagArgs(args) if err != nil { return nil, err } return toRet.(uint), nil } default: { return nil, fmt.Errorf(ErrUnsupportedNumberType) } } } // handling boundary tags valuesStr := strings.SplitN(tag, comma, -1) if len(valuesStr) != 2 { return nil, fmt.Errorf(ErrWrongFormattedTag, tag) } // TODO(Xaspy): When Golang provides generics, we will be able to make this method simpler and more beautiful. if t.Kind() == reflect.Float64 || t.Kind() == reflect.Float32 { startBoundary, err := extractFloatFromText(valuesStr[0]) if err != nil { return nil, err } endBoundary, err := extractFloatFromText(valuesStr[1]) if err != nil { return nil, err } boundary := floatBoundary{start: startBoundary, end: endBoundary} switch t.Kind() { case reflect.Float32: return float32(randomFloatWithBoundary(boundary)), nil case reflect.Float64: return randomFloatWithBoundary(boundary), nil } } startBoundary, err := extractIntFromText(valuesStr[0]) if err != nil { return nil, err } endBoundary, err := extractIntFromText(valuesStr[1]) if err != nil { return nil, err } boundary := intBoundary{start: startBoundary, end: endBoundary} switch t.Kind() { case reflect.Uint: return uint(randomIntegerWithBoundary(boundary)), nil case reflect.Uint8: return uint8(randomIntegerWithBoundary(boundary)), nil case reflect.Uint16: return uint16(randomIntegerWithBoundary(boundary)), nil case reflect.Uint32: return uint32(randomIntegerWithBoundary(boundary)), nil case reflect.Uint64: return uint64(randomIntegerWithBoundary(boundary)), nil case reflect.Int: return randomIntegerWithBoundary(boundary), nil case reflect.Int8: return int8(randomIntegerWithBoundary(boundary)), nil case reflect.Int16: return int16(randomIntegerWithBoundary(boundary)), nil case reflect.Int32: return int32(randomIntegerWithBoundary(boundary)), nil case reflect.Int64: return int64(randomIntegerWithBoundary(boundary)), nil default: return nil, errors.New(ErrNotSupportedTypeForTag) } } func extractIntFromText(text string) (int, error) { text = strings.TrimSpace(text) texts := strings.SplitN(text, Equals, -1) if len(texts) != 2 { return 0, fmt.Errorf(ErrWrongFormattedTag, text) } return strconv.Atoi(texts[1]) } func extractFloatFromText(text string) (float64, error) { text = strings.TrimSpace(text) texts := strings.SplitN(text, Equals, -1) if len(texts) != 2 { return 0, fmt.Errorf(ErrWrongFormattedTag, text) } return strconv.ParseFloat(texts[1], 64) } func fetchOneOfArgsFromTag(tag string) ([]string, error) { items := strings.Split(tag, colon) argsList := items[1:] if len(argsList) != 1 { return nil, fmt.Errorf(ErrUnsupportedTagArguments) } if strings.Contains(argsList[0], ",,") { return nil, fmt.Errorf(ErrDuplicateSeparator) } if argsList[0] == "" { return nil, fmt.Errorf(ErrNotEnoughTagArguments) } args := strings.Split(argsList[0], comma) if len(args) < 1 { return nil, fmt.Errorf(ErrNotEnoughTagArguments) } return args, nil } func randomString(n int, lang *langRuneBoundary) (string, error) { b := make([]rune, 0) set := make(map[rune]struct{}) if lang.exclude != nil { for _, s := range lang.exclude { set[s] = struct{}{} } } counter := 0 for i := 0; i < n; { randRune := rune(rand.Intn(int(lang.end-lang.start)) + int(lang.start)) for slice.ContainsRune(set, randRune) { if counter++; counter >= maxGenerateStringRetries { return "", errors.New("Max number of string generation retries exhausted") } randRune = rune(rand.Intn(int(lang.end-lang.start)) + int(lang.start)) _, ok := set[randRune] if !ok { break } } b = append(b, randRune) i++ } k := string(b) return k, nil } // randomIntegerWithBoundary returns a random integer between input start and end boundary. [start, end) func randomIntegerWithBoundary(boundary intBoundary) int { span := boundary.end - boundary.start if span <= 0 { return boundary.start } return rand.Intn(span) + boundary.start } // randomFloatWithBoundary returns a random float between input start and end boundary. [start, end) func randomFloatWithBoundary(boundary floatBoundary) float64 { span := boundary.end - boundary.start if span <= 0 { return boundary.start } return boundary.start + rand.Float64()*span } // randomInteger returns a random integer between start and end boundary. [start, end) func randomInteger() int { return randomIntegerWithBoundary(iBoundary) } // randomFloat returns a random float between start and end boundary. [start, end) func randomFloat() float64 { return randomFloatWithBoundary(fBoundary) } // randomSliceAndMapSize returns a random integer between [0,randomSliceAndMapSize). If the testRandZero is set, returns 0 // Written for test purposes for shouldSetNil func randomSliceAndMapSize() int { if testRandZero { return 0 } r := randomMaxSize - randomMinSize if r < 1 { r = 1 } return randomMinSize + rand.Intn(r) } func randomElementFromSliceString(s []string) string { return s[rand.Int()%len(s)] } func randomStringNumber(n int) string { b := make([]byte, n) for i, cache, remain := n-1, rand.Int63(), letterIdxMax; i >= 0; { if remain == 0 { cache, remain = rand.Int63(), letterIdxMax } if idx := int(cache & letterIdxMask); idx < len(numberBytes) { b[i] = numberBytes[idx] i-- } cache >>= letterIdxBits remain-- } return string(b) } // RandomInt Get three parameters , only first mandatory and the rest are optional // (minimum_int, maximum_int, count) // If only set one parameter : An integer greater than minimum_int will be returned // If only set two parameters : All integers between minimum_int and maximum_int will be returned, in a random order. // If three parameters: `count` integers between minimum_int and maximum_int will be returned. func RandomInt(parameters ...int) (p []int, err error) { switch len(parameters) { case 1: minInt := parameters[0] p = rand.Perm(minInt) for i := range p { p[i] += minInt } case 2: minInt, maxInt := parameters[0], parameters[1] p = rand.Perm(maxInt - minInt + 1) for i := range p { p[i] += minInt } case 3: minInt, maxInt := parameters[0], parameters[1] count := parameters[2] p = rand.Perm(maxInt - minInt + 1) for i := range p { p[i] += minInt } p = p[0:count] default: err = fmt.Errorf(ErrMoreArguments, len(parameters)) } return p, err } func generateUnique(dataType string, fn func() interface{}) (interface{}, error) { for i := 0; i < maxRetry; i++ { value := fn() if !slice.ContainsValue(uniqueValues[dataType], value) { // Retry if unique value already found uniqueValues[dataType] = append(uniqueValues[dataType], value) return value, nil } } return reflect.Value{}, fmt.Errorf(ErrUniqueFailure, dataType) } func singleFakeData(dataType string, fn func() interface{}) interface{} { if generateUniqueValues { v, err := generateUnique(dataType, fn) if err != nil { panic(err) } return v } return fn() }