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
|
package pkglint
import (
"gopkg.in/check.v1"
"math/rand"
"time"
)
// Fuzzer generates random strings.
// The structure of the strings is configurable.
type Fuzzer struct {
seed int64
rnd *rand.Rand
stock []struct {
r rune
weight int
}
total int // The sum of all stock weights
last string //
ok bool // Whether the last string was processed correctly
}
// NewFuzzer returns a fuzzer.
// If no seed is passed, a random seed is chosen.
// To reproduce a previous run, pass the seed from that run as the parameter.
func NewFuzzer(seed ...int64) *Fuzzer {
var actualSeed int64
if len(seed) > 0 {
actualSeed = seed[0]
} else {
actualSeed = time.Now().UnixNano()
}
return &Fuzzer{seed: actualSeed, rnd: rand.New(rand.NewSource(actualSeed))}
}
// Char randomly generates a character from the given set.
// Each character has the given weight.
func (f *Fuzzer) Char(set string, weight int) {
for _, r := range set {
f.addChar(r, weight)
}
}
// Range randomly generates a character from the given range.
// Each character has the given weight.
func (f *Fuzzer) Range(minIncl, maxIncl rune, weight int) {
for r := minIncl; r <= maxIncl; r++ {
f.addChar(r, weight)
}
}
func (f *Fuzzer) addChar(r rune, weight int) {
f.stock = append(f.stock, struct {
r rune
weight int
}{r, weight})
f.total += weight
}
func (f *Fuzzer) Generate(length int) string {
rs := make([]rune, length)
for i := 0; i < length; i++ {
rs[i] = f.randomChar()
}
f.last = string(rs)
return f.last
}
func (f *Fuzzer) randomChar() rune {
i := int(f.rnd.Int31n(int32(f.total)))
for _, entry := range f.stock {
i -= entry.weight
if i < 0 {
return entry.r
}
}
panic("Out of stock")
}
// CheckOk is typically used in a defer statement and is run after all
// the tests to check whether they have been marked as ok.
func (f *Fuzzer) CheckOk() {
if !f.ok {
panic(sprintf("Fuzzing failed with seed %d, last generated value: %s", f.seed, f.last))
}
}
// Ok marks the current string as processed correctly.
func (f *Fuzzer) Ok() { f.ok = true }
func (s *Suite) Test_Fuzzer__out_of_stock(c *check.C) {
fuzzer := NewFuzzer(0)
fuzzer.total = 1 // Intentionally damage the fuzzer to achieve full code coverage.
c.Check(
func() { fuzzer.Generate(1) },
check.Panics,
"Out of stock")
}
|