forked from leanovate/gopter
/
strings.go
158 lines (138 loc) · 4.26 KB
/
strings.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
package gen
import (
"reflect"
"unicode"
"unicode/utf8"
"github.com/leanovate/gopter"
)
// RuneRange generates runes within a given range
func RuneRange(min, max rune) gopter.Gen {
return genRune(Int64Range(int64(min), int64(max)))
}
// Rune generates an arbitrary character rune
func Rune() gopter.Gen {
return genRune(Frequency(map[int]gopter.Gen{
0xD800: Int64Range(0, 0xD800),
utf8.MaxRune - 0xDFFF: Int64Range(0xDFFF, int64(utf8.MaxRune)),
}))
}
// RuneNoControl generates an arbitrary character rune that is not a control character
func RuneNoControl() gopter.Gen {
return genRune(Frequency(map[int]gopter.Gen{
0xD800: Int64Range(32, 0xD800),
utf8.MaxRune - 0xDFFF: Int64Range(0xDFFF, int64(utf8.MaxRune)),
}))
}
func genRune(int64Gen gopter.Gen) gopter.Gen {
return int64Gen.Map(func(value int64) rune {
return rune(value)
}).SuchThat(func(v rune) bool {
return utf8.ValidRune(v)
})
}
// NumChar generates arbitrary numberic character runes
func NumChar() gopter.Gen {
return RuneRange('0', '9')
}
// AlphaUpperChar generates arbitrary uppercase alpha character runes
func AlphaUpperChar() gopter.Gen {
return RuneRange('A', 'Z')
}
// AlphaLowerChar generates arbitrary lowercase alpha character runes
func AlphaLowerChar() gopter.Gen {
return RuneRange('a', 'z')
}
// AlphaChar generates arbitrary character runes (upper- and lowercase)
func AlphaChar() gopter.Gen {
return Frequency(map[int]gopter.Gen{
0: AlphaUpperChar(),
9: AlphaLowerChar(),
})
}
// AlphaNumChar generates arbitrary alpha-numeric character runes
func AlphaNumChar() gopter.Gen {
return Frequency(map[int]gopter.Gen{
0: NumChar(),
9: AlphaChar(),
})
}
// UnicodeChar generates arbitrary character runes with a given unicode table
func UnicodeChar(table *unicode.RangeTable) gopter.Gen {
if table == nil || len(table.R16)+len(table.R32) == 0 {
return Fail(reflect.TypeOf(rune('a')))
}
return func(genParams *gopter.GenParameters) *gopter.GenResult {
tableIdx := genParams.Rng.Intn(len(table.R16) + len(table.R32))
var selectedRune rune
if tableIdx < len(table.R16) {
r := table.R16[tableIdx]
runeOffset := uint16(genParams.Rng.Int63n(int64((r.Hi-r.Lo+1)/r.Stride))) * r.Stride
selectedRune = rune(runeOffset + r.Lo)
} else {
r := table.R32[tableIdx-len(table.R16)]
runeOffset := uint32(genParams.Rng.Int63n(int64((r.Hi-r.Lo+1)/r.Stride))) * r.Stride
selectedRune = rune(runeOffset + r.Lo)
}
genResult := gopter.NewGenResult(selectedRune, gopter.NoShrinker)
genResult.Sieve = func(v interface{}) bool {
return unicode.Is(table, v.(rune))
}
return genResult
}
}
// AnyString generates an arbitrary string
func AnyString() gopter.Gen {
return genString(Rune(), utf8.ValidRune)
}
// AlphaString generates an arbitrary string with letters
func AlphaString() gopter.Gen {
return genString(AlphaChar(), unicode.IsLetter)
}
// NumString generates an arbitrary string with digits
func NumString() gopter.Gen {
return genString(NumChar(), unicode.IsDigit)
}
// Identifier generates an arbitrary identifier string
// Identitiers are supporsed to start with a lowercase letter and contain only
// letters and digits
func Identifier() gopter.Gen {
return gopter.CombineGens(
AlphaLowerChar(),
SliceOf(AlphaNumChar()),
).Map(func(values []interface{}) string {
first := values[0].(rune)
tail := values[1].([]rune)
result := make([]rune, 0, len(tail)+1)
return string(append(append(result, first), tail...))
}).SuchThat(func(str string) bool {
if len(str) < 1 || !unicode.IsLower(([]rune(str))[0]) {
return false
}
for _, ch := range str {
if !unicode.IsLetter(ch) && !unicode.IsDigit(ch) {
return false
}
}
return true
}).WithShrinker(StringShrinker)
}
// UnicodeString generates an arbitrary string from a given
// unicode table.
func UnicodeString(table *unicode.RangeTable) gopter.Gen {
return genString(UnicodeChar(table), func(ch rune) bool {
return unicode.Is(table, ch)
})
}
func genString(runeGen gopter.Gen, runeSieve func(ch rune) bool) gopter.Gen {
return SliceOf(runeGen).Map(runesToString).SuchThat(func(v string) bool {
for _, ch := range v {
if !runeSieve(ch) {
return false
}
}
return true
}).WithShrinker(StringShrinker)
}
func runesToString(v []rune) string {
return string(v)
}