Skip to content
This repository was archived by the owner on Dec 8, 2022. It is now read-only.

Commit 02fc1b2

Browse files
Olego.musin
Oleg
and
o.musin
authored
fix: exluded characters in random string generator (#111)
* exluded characters in random string generator * randomString returning error * add panic in case of string generation failture * fix panic for Username Co-authored-by: o.musin <[email protected]>
1 parent 3f13091 commit 02fc1b2

File tree

4 files changed

+106
-37
lines changed

4 files changed

+106
-37
lines changed

faker.go

+38-15
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,10 @@ var (
3232
generateUniqueValues = false
3333
// Unique values are kept in memory so the generator retries if the value already exists
3434
uniqueValues = map[string][]interface{}{}
35-
lang = LangENG
35+
// Lang is selected language for random string generator
36+
lang = LangENG
37+
// How much tries for generating random string
38+
maxGenerateStringRetries = 1000000
3639
)
3740

3841
type numberBoundary struct {
@@ -41,18 +44,19 @@ type numberBoundary struct {
4144
}
4245

4346
type langRuneBoundary struct {
44-
start rune
45-
end rune
47+
start rune
48+
end rune
49+
exclude []rune
4650
}
4751

4852
// Language rune boundaries here
4953
var (
5054
// LangENG is for english language
51-
LangENG = langRuneBoundary{65, 122}
55+
LangENG = langRuneBoundary{65, 122, []rune{91, 92, 93, 94, 95, 96}}
5256
// LangCHI is for chinese language
53-
LangCHI = langRuneBoundary{19968, 40869}
57+
LangCHI = langRuneBoundary{19968, 40869, nil}
5458
// LangRUS is for russian language
55-
LangRUS = langRuneBoundary{1025, 1105}
59+
LangRUS = langRuneBoundary{1025, 1105, nil}
5660
)
5761

5862
// Supported tags
@@ -246,9 +250,9 @@ var (
246250

247251
// Compiled regexp
248252
var (
249-
findLangReg *regexp.Regexp
250-
findLenReg *regexp.Regexp
251-
findSliceLenReg *regexp.Regexp
253+
findLangReg *regexp.Regexp
254+
findLenReg *regexp.Regexp
255+
findSliceLenReg *regexp.Regexp
252256
)
253257

254258
func init() {
@@ -479,8 +483,8 @@ func getValue(a interface{}) (reflect.Value, error) {
479483
}
480484

481485
case reflect.String:
482-
res := randomString(randomStringLen, &lang)
483-
return reflect.ValueOf(res), nil
486+
res, err := randomString(randomStringLen, &lang)
487+
return reflect.ValueOf(res), err
484488
case reflect.Slice:
485489
len := randomSliceAndMapSize()
486490
if shouldSetNil && len == 0 {
@@ -848,8 +852,8 @@ func extractStringFromTag(tag string) (interface{}, error) {
848852
toRet := args[rand.Intn(len(args))]
849853
return strings.TrimSpace(toRet), nil
850854
}
851-
res := randomString(strlen, strlng)
852-
return res, nil
855+
res, err := randomString(strlen, strlng)
856+
return res, err
853857
}
854858

855859
func extractLangFromTag(tag string) (*langRuneBoundary, error) {
@@ -1046,15 +1050,34 @@ func extractNumberFromText(text string) (int, error) {
10461050
return strconv.Atoi(texts[1])
10471051
}
10481052

1049-
func randomString(n int, lang *langRuneBoundary) string {
1053+
func randomString(n int, lang *langRuneBoundary) (string, error) {
10501054
b := make([]rune, 0)
1055+
set := make(map[rune]struct{})
1056+
if lang.exclude != nil {
1057+
for _, s := range lang.exclude {
1058+
set[s] = struct{}{}
1059+
}
1060+
}
1061+
1062+
counter := 0
10511063
for i := 0; i < n; {
10521064
randRune := rune(rand.Intn(int(lang.end-lang.start)) + int(lang.start))
1065+
for slice.ContainsRune(set, randRune) {
1066+
if counter++; counter >= maxGenerateStringRetries {
1067+
return "", errors.New("Max number of string generation retries exhausted")
1068+
}
1069+
randRune = rune(rand.Intn(int(lang.end-lang.start)) + int(lang.start))
1070+
_, ok := set[randRune]
1071+
if !ok {
1072+
break
1073+
}
1074+
}
10531075
b = append(b, randRune)
10541076
i++
10551077
}
10561078

1057-
return string(b)
1079+
k := string(b)
1080+
return k, nil
10581081
}
10591082

10601083
// randomIntegerWithBoundary returns a random integer between input start and end boundary. [start, end)

faker_test.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ const (
2121
)
2222

2323
var (
24-
langCorrectTagsMap = map[langRuneBoundary]string{LangENG: "lang=eng", LangCHI: "lang=chi", LangRUS: "lang=rus"}
24+
langCorrectTagsMap = map[string]langRuneBoundary{"lang=eng": LangENG, "lang=chi": LangCHI, "lang=rus": LangRUS}
2525
langUncorrectTags = [3]string{"lang=", "lang", "lng=eng"}
2626

2727
lenCorrectTags = [3]string{"len=4", "len=5", "len=10"}
@@ -597,10 +597,10 @@ func TestExtractingLangFromTag(t *testing.T) {
597597
var err error
598598
var lng *langRuneBoundary
599599
for k, v := range langCorrectTagsMap {
600-
if lng, err = extractLangFromTag(v); err != nil {
600+
if lng, err = extractLangFromTag(k); err != nil {
601601
t.Error(err.Error())
602602
}
603-
if k != *lng {
603+
if !reflect.DeepEqual(v, *lng) {
604604
t.Errorf("Got %v lang rune range, but expected %v", lng, k)
605605
}
606606
}

internet.go

+59-19
Original file line numberDiff line numberDiff line change
@@ -56,20 +56,32 @@ type Networker interface {
5656
// Internet struct
5757
type Internet struct{}
5858

59-
func (internet Internet) email() string {
60-
return randomString(7, &LangENG) + "@" + randomString(5, &LangENG) + "." + randomElementFromSliceString(tld)
59+
func (internet Internet) email() (string, error) {
60+
var err error
61+
var emailName, emailDomain string
62+
if emailName, err = randomString(7, &LangENG); err != nil {
63+
return "", err
64+
}
65+
if emailDomain, err = randomString(7, &LangENG); err != nil {
66+
return "", err
67+
}
68+
return (emailName + "@" + emailDomain + "." + randomElementFromSliceString(tld)), nil
6169
}
6270

6371
// Email generates random email id
6472
func (internet Internet) Email(v reflect.Value) (interface{}, error) {
65-
return internet.email(), nil
73+
return internet.email()
6674
}
6775

6876
// Email get email randomly in string
6977
func Email() string {
7078
return singleFakeData(EmailTag, func() interface{} {
7179
i := Internet{}
72-
return i.email()
80+
r, err := i.email()
81+
if err != nil {
82+
panic(err.Error())
83+
}
84+
return r
7385
}).(string)
7486
}
7587

@@ -94,59 +106,83 @@ func MacAddress() string {
94106
}).(string)
95107
}
96108

97-
func (internet Internet) domainName() string {
98-
return randomString(7, &LangENG) + "." + randomElementFromSliceString(tld)
109+
func (internet Internet) domainName() (string, error) {
110+
domainPart, err := randomString(7, &LangENG)
111+
if err != nil {
112+
return "", err
113+
}
114+
return (domainPart + "." + randomElementFromSliceString(tld)), nil
99115
}
100116

101117
// DomainName generates random domain name
102118
func (internet Internet) DomainName(v reflect.Value) (interface{}, error) {
103-
return internet.domainName(), nil
119+
return internet.domainName()
104120
}
105121

106122
// DomainName get email domain name in string
107123
func DomainName() string {
108124
return singleFakeData(DomainNameTag, func() interface{} {
109125
i := Internet{}
110-
return i.domainName()
126+
d, err := i.domainName()
127+
if err != nil {
128+
panic(err.Error())
129+
}
130+
return d
111131
}).(string)
112132
}
113133

114-
func (internet Internet) url() string {
134+
func (internet Internet) url() (string, error) {
115135
format := randomElementFromSliceString(urlFormats)
116136
countVerbs := strings.Count(format, "%s")
137+
d, err := internet.domainName()
138+
if err != nil {
139+
return "", nil
140+
}
117141
if countVerbs == 1 {
118-
return fmt.Sprintf(format, internet.domainName())
142+
return fmt.Sprintf(format, d), nil
143+
}
144+
u, err := internet.username()
145+
if err != nil {
146+
return "", err
119147
}
120-
return fmt.Sprintf(format, internet.domainName(), internet.username())
148+
return fmt.Sprintf(format, d, u), nil
121149
}
122150

123151
// URL generates random URL standardized in urlFormats const
124152
func (internet Internet) URL(v reflect.Value) (interface{}, error) {
125-
return internet.url(), nil
153+
return internet.url()
126154
}
127155

128156
// URL get Url randomly in string
129157
func URL() string {
130158
return singleFakeData(URLTag, func() interface{} {
131159
i := Internet{}
132-
return i.url()
160+
u, err := i.url()
161+
if err != nil {
162+
panic(err.Error())
163+
}
164+
return u
133165
}).(string)
134166
}
135167

136-
func (internet Internet) username() string {
168+
func (internet Internet) username() (string, error) {
137169
return randomString(7, &LangENG)
138170
}
139171

140172
// UserName generates random username
141173
func (internet Internet) UserName(v reflect.Value) (interface{}, error) {
142-
return internet.username(), nil
174+
return internet.username()
143175
}
144176

145177
// Username get username randomly in string
146178
func Username() string {
147179
return singleFakeData(UserNameTag, func() interface{} {
148180
i := Internet{}
149-
return i.username()
181+
u, err := i.username()
182+
if err != nil {
183+
panic(err.Error())
184+
}
185+
return u
150186
}).(string)
151187
}
152188

@@ -194,19 +230,23 @@ func IPv6() string {
194230
}).(string)
195231
}
196232

197-
func (internet Internet) password() string {
233+
func (internet Internet) password() (string, error) {
198234
return randomString(50, &LangENG)
199235
}
200236

201237
// Password returns a hashed password
202238
func (internet Internet) Password(v reflect.Value) (interface{}, error) {
203-
return internet.password(), nil
239+
return internet.password()
204240
}
205241

206242
// Password get password randomly in string
207243
func Password() string {
208244
return singleFakeData(PASSWORD, func() interface{} {
209245
i := Internet{}
210-
return i.password()
246+
p, err := i.password()
247+
if err != nil {
248+
panic(err.Error())
249+
}
250+
return p
211251
}).(string)
212252
}

support/slice/helpers.go

+6
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,12 @@ func Contains(slice []string, item string) bool {
1515
return ok
1616
}
1717

18+
// ContainsRune Check item in map rune type
19+
func ContainsRune(set map[rune]struct{}, item rune) bool {
20+
_, ok := set[item]
21+
return ok
22+
}
23+
1824
// ContainsValue check if value exists in slice, no matter its type
1925
func ContainsValue(slice []interface{}, value interface{}) bool {
2026
for _, v := range slice {

0 commit comments

Comments
 (0)