Skip to content

Commit

Permalink
Feat: Add function WithCharRange to generate different encoding strin…
Browse files Browse the repository at this point in the history
…g, low and high encoding of unicode should be input if you want different encoding string.
  • Loading branch information
kwongtailau committed Jul 7, 2020
1 parent a364796 commit d5dcf20
Show file tree
Hide file tree
Showing 2 changed files with 21 additions and 55 deletions.
8 changes: 4 additions & 4 deletions README.md
Expand Up @@ -20,13 +20,13 @@ var myInt int
f.Fuzz(&myInt) // myInt gets a random value.
```

You can use it on string with different character, like ASCII, MultiByte,
CommonCJK, Chinese, Japanese, Number, Lower-Case, Upper-Case or
Random(each rune will be one of the above character).
If you want to use it on string with different character like Chinese or Number,
you can get Unicode range from [Unicode](https://en.wikipedia.org/wiki/Plane_(Unicode)#Basic_Multilingual_Plane),
and parse the low and high encoding into function `WithCharRange`. For example Chinese:
```go
f := fuzz.New()
var myString string
f.WithStringGenMode(fuzz.Chinese).Fuzz(&myString)
f.WithCharRange('\u4e00', '\u9fa5').Fuzz(&myString)
```

You can use it on maps:
Expand Down
68 changes: 17 additions & 51 deletions fuzz.go
Expand Up @@ -40,7 +40,7 @@ type Fuzzer struct {
maxElements int
maxDepth int
skipFieldPatterns []*regexp.Regexp
stringGenMode int
characterRange *charRange
}

// New returns a new Fuzzer. Customize your Fuzzer further by calling Funcs,
Expand All @@ -61,8 +61,8 @@ func NewWithSeed(seed int64) *Fuzzer {
minElements: 1,
maxElements: 10,
maxDepth: 100,
// random mode as default mode to gen string
stringGenMode: Random,
// characterRange will be nil if you not set the encoding range
characterRange: nil,
}
return f
}
Expand Down Expand Up @@ -193,11 +193,12 @@ func (f *Fuzzer) SkipFieldsWithPattern(pattern *regexp.Regexp) *Fuzzer {
return f
}

// WithStringGenMode is used to set the string generation mode. Mode includes ASCII,
// MultiByte, CommonCJK, Chinese, Japanese, Number, Lower case, Upper case or
// random mode(each rune will use one character.).
func (f *Fuzzer) WithStringGenMode(mode int) *Fuzzer {
f.stringGenMode = mode
// WithCharRange is used to set the Unicode encoding range of the string.
func (f *Fuzzer) WithCharRange(first, last rune) *Fuzzer {
f.characterRange = &charRange{
first: first,
last: last,
}
return f
}

Expand Down Expand Up @@ -285,9 +286,9 @@ func (fc *fuzzerContext) doFuzz(v reflect.Value, flags uint64) {

switch v.Kind() {
// String is common data struct but handle it with function randString
// randString should input string generation mode.
// randString should input character range although it is nil
case reflect.String:
v.SetString(randString(fc.fuzzer.r, fc.fuzzer.stringGenMode))
v.SetString(randString(fc.fuzzer.r, fc.fuzzer.characterRange))

case reflect.Map:
if fc.fuzzer.genShouldFill() {
Expand Down Expand Up @@ -445,13 +446,7 @@ func (c Continue) FuzzNoCustom(obj interface{}) {
// RandString makes a random string up to 20 characters long. The returned string
// may include a variety of (valid) UTF-8 encodings.
func (c Continue) RandString() string {
return randString(c.Rand, c.fc.fuzzer.stringGenMode)
}

// RandChineseString makes a random string up to 20 characters long. The returned string
// may include a variety of (valid) UTF-8 encodings. Rand unicode: \u4e00 - \u9fa5
func (c Continue) RandChinesesString() string {
return randChineseString(c.Rand)
return randString(c.Rand, c.fc.fuzzer.characterRange)
}

// RandUint64 makes random 64 bit numbers.
Expand Down Expand Up @@ -538,49 +533,20 @@ var unicodeRanges = []charRange{
{' ', '~'}, // ASCII characters
{'\u00a0', '\u02af'}, // Multi-byte encoded characters
{'\u4e00', '\u9fff'}, // Common CJK (even longer encodings)
{'\u4e00', '\u9fa5'}, // Chinese
{'\u0800', '\u4e00'}, // Japanese
{'\u0030', '\u0039'}, // number
{'\u0061', '\u007a'}, // lower case
{'\u0041', '\u005a'}, // upper case
}

const (
ASCII = iota
MultiByte
CommonCJK
Chinese
Japanese
Number
LowerCase
UpperCase

Random = 10000
)

// randChineseString makes a random string up to 20 characters long. The returned string
// may include a variety of (valid) UTF-8 encodings. Rand unicode: \u4e00 - \u9fa5
func randChineseString(r *rand.Rand) string {
n := r.Intn(20)
sb := strings.Builder{}
sb.Grow(n)
for i := 0; i < n; i++ {
sb.WriteRune(unicodeRanges[3].choose(r))
}
return sb.String()
}

// randString makes a random string up to 20 characters long. The returned string
// may include a variety of (valid) UTF-8 encodings.
func randString(r *rand.Rand, genMode int) string {
// may include a variety of (valid) UTF-8 encodings. If wants specific encoding
// string, it should input character range.
func randString(r *rand.Rand, characterRange *charRange) string {
n := r.Intn(20)
sb := strings.Builder{}
sb.Grow(n)
for i := 0; i < n; i++ {
if genMode == Random {
if characterRange == nil {
sb.WriteRune(unicodeRanges[r.Intn(len(unicodeRanges))].choose(r))
} else {
sb.WriteRune(unicodeRanges[genMode].choose(r))
sb.WriteRune(characterRange.choose(r))
}
}
return sb.String()
Expand Down

0 comments on commit d5dcf20

Please sign in to comment.