1
16
17 package fuzz
18
19 import (
20 "math/rand"
21 "reflect"
22 "regexp"
23 "strings"
24 "testing"
25 "time"
26 )
27
28 func TestFuzz_basic(t *testing.T) {
29 obj := &struct {
30 I int
31 I8 int8
32 I16 int16
33 I32 int32
34 I64 int64
35 U uint
36 U8 uint8
37 U16 uint16
38 U32 uint32
39 U64 uint64
40 Uptr uintptr
41 S string
42 B bool
43 T time.Time
44 C64 complex64
45 C128 complex128
46 }{}
47
48 failed := map[string]int{}
49 for i := 0; i < 10; i++ {
50 New().Fuzz(obj)
51
52 if n, v := "i", obj.I; v == 0 {
53 failed[n] = failed[n] + 1
54 }
55 if n, v := "i8", obj.I8; v == 0 {
56 failed[n] = failed[n] + 1
57 }
58 if n, v := "i16", obj.I16; v == 0 {
59 failed[n] = failed[n] + 1
60 }
61 if n, v := "i32", obj.I32; v == 0 {
62 failed[n] = failed[n] + 1
63 }
64 if n, v := "i64", obj.I64; v == 0 {
65 failed[n] = failed[n] + 1
66 }
67 if n, v := "u", obj.U; v == 0 {
68 failed[n] = failed[n] + 1
69 }
70 if n, v := "u8", obj.U8; v == 0 {
71 failed[n] = failed[n] + 1
72 }
73 if n, v := "u16", obj.U16; v == 0 {
74 failed[n] = failed[n] + 1
75 }
76 if n, v := "u32", obj.U32; v == 0 {
77 failed[n] = failed[n] + 1
78 }
79 if n, v := "u64", obj.U64; v == 0 {
80 failed[n] = failed[n] + 1
81 }
82 if n, v := "uptr", obj.Uptr; v == 0 {
83 failed[n] = failed[n] + 1
84 }
85 if n, v := "s", obj.S; v == "" {
86 failed[n] = failed[n] + 1
87 }
88 if n, v := "b", obj.B; v == false {
89 failed[n] = failed[n] + 1
90 }
91 if n, v := "t", obj.T; v.IsZero() {
92 failed[n] = failed[n] + 1
93 }
94 if n, v := "c64", obj.C64; v == 0 {
95 failed[n] = failed[n] + 1
96 }
97 if n, v := "c128", obj.C128; v == 0 {
98 failed[n] = failed[n] + 1
99 }
100 }
101 checkFailed(t, failed)
102 }
103
104 func checkFailed(t *testing.T, failed map[string]int) {
105 for k, v := range failed {
106 if v > 8 {
107 t.Errorf("%v seems to not be getting set, was zero value %v times", k, v)
108 }
109 }
110 }
111
112 func TestFuzz_structptr(t *testing.T) {
113 obj := &struct {
114 A *struct {
115 S string
116 }
117 }{}
118
119 f := New().NilChance(.5)
120 failed := map[string]int{}
121 for i := 0; i < 10; i++ {
122 f.Fuzz(obj)
123
124 if n, v := "a not nil", obj.A; v == nil {
125 failed[n] = failed[n] + 1
126 }
127 if n, v := "a nil", obj.A; v != nil {
128 failed[n] = failed[n] + 1
129 }
130 if n, v := "as", obj.A; v == nil || v.S == "" {
131 failed[n] = failed[n] + 1
132 }
133 }
134 checkFailed(t, failed)
135 }
136
137
138
139 func tryFuzz(t *testing.T, f *Fuzzer, obj interface{}, check func() (stage int, passed bool)) {
140 maxStage := 0
141 for i := 0; i < 20; i++ {
142 f.Fuzz(obj)
143 stage, passed := check()
144 if stage > maxStage {
145 maxStage = stage
146 }
147 if passed {
148 return
149 }
150 }
151 t.Errorf("Only ever got to stage %v", maxStage)
152 }
153
154 func TestFuzz_structmap(t *testing.T) {
155 obj := &struct {
156 A map[struct {
157 S string
158 }]struct {
159 S2 string
160 }
161 B map[string]string
162 }{}
163
164 tryFuzz(t, New(), obj, func() (int, bool) {
165 if obj.A == nil {
166 return 1, false
167 }
168 if len(obj.A) == 0 {
169 return 2, false
170 }
171 for k, v := range obj.A {
172 if k.S == "" {
173 return 3, false
174 }
175 if v.S2 == "" {
176 return 4, false
177 }
178 }
179
180 if obj.B == nil {
181 return 5, false
182 }
183 if len(obj.B) == 0 {
184 return 6, false
185 }
186 for k, v := range obj.B {
187 if k == "" {
188 return 7, false
189 }
190 if v == "" {
191 return 8, false
192 }
193 }
194 return 9, true
195 })
196 }
197
198 func TestFuzz_structslice(t *testing.T) {
199 obj := &struct {
200 A []struct {
201 S string
202 }
203 B []string
204 }{}
205
206 tryFuzz(t, New(), obj, func() (int, bool) {
207 if obj.A == nil {
208 return 1, false
209 }
210 if len(obj.A) == 0 {
211 return 2, false
212 }
213 for _, v := range obj.A {
214 if v.S == "" {
215 return 3, false
216 }
217 }
218
219 if obj.B == nil {
220 return 4, false
221 }
222 if len(obj.B) == 0 {
223 return 5, false
224 }
225 for _, v := range obj.B {
226 if v == "" {
227 return 6, false
228 }
229 }
230 return 7, true
231 })
232 }
233
234 func TestFuzz_structarray(t *testing.T) {
235 obj := &struct {
236 A [3]struct {
237 S string
238 }
239 B [2]int
240 }{}
241
242 tryFuzz(t, New(), obj, func() (int, bool) {
243 for _, v := range obj.A {
244 if v.S == "" {
245 return 1, false
246 }
247 }
248
249 for _, v := range obj.B {
250 if v == 0 {
251 return 2, false
252 }
253 }
254 return 3, true
255 })
256 }
257
258 func TestFuzz_custom(t *testing.T) {
259 obj := &struct {
260 A string
261 B *string
262 C map[string]string
263 D *map[string]string
264 }{}
265
266 testPhrase := "gotcalled"
267 testMap := map[string]string{"C": "D"}
268 f := New().Funcs(
269 func(s *string, c Continue) {
270 *s = testPhrase
271 },
272 func(m map[string]string, c Continue) {
273 m["C"] = "D"
274 },
275 )
276
277 tryFuzz(t, f, obj, func() (int, bool) {
278 if obj.A != testPhrase {
279 return 1, false
280 }
281 if obj.B == nil {
282 return 2, false
283 }
284 if *obj.B != testPhrase {
285 return 3, false
286 }
287 if e, a := testMap, obj.C; !reflect.DeepEqual(e, a) {
288 return 4, false
289 }
290 if obj.D == nil {
291 return 5, false
292 }
293 if e, a := testMap, *obj.D; !reflect.DeepEqual(e, a) {
294 return 6, false
295 }
296 return 7, true
297 })
298 }
299
300 type SelfFuzzer string
301
302
303 func (sf *SelfFuzzer) Fuzz(c Continue) {
304 *sf = selfFuzzerTestPhrase
305 }
306
307 const selfFuzzerTestPhrase = "was fuzzed"
308
309 func TestFuzz_interface(t *testing.T) {
310 f := New()
311
312 var obj1 SelfFuzzer
313 tryFuzz(t, f, &obj1, func() (int, bool) {
314 if obj1 != selfFuzzerTestPhrase {
315 return 1, false
316 }
317 return 1, true
318 })
319
320 var obj2 map[int]SelfFuzzer
321 tryFuzz(t, f, &obj2, func() (int, bool) {
322 for _, v := range obj2 {
323 if v != selfFuzzerTestPhrase {
324 return 1, false
325 }
326 }
327 return 1, true
328 })
329 }
330
331 func TestFuzz_interfaceAndFunc(t *testing.T) {
332 const privateTestPhrase = "private phrase"
333 f := New().Funcs(
334
335 func(s *SelfFuzzer, c Continue) {
336 *s = privateTestPhrase
337 },
338 )
339
340 var obj1 SelfFuzzer
341 tryFuzz(t, f, &obj1, func() (int, bool) {
342 if obj1 != privateTestPhrase {
343 return 1, false
344 }
345 return 1, true
346 })
347
348 var obj2 map[int]SelfFuzzer
349 tryFuzz(t, f, &obj2, func() (int, bool) {
350 for _, v := range obj2 {
351 if v != privateTestPhrase {
352 return 1, false
353 }
354 }
355 return 1, true
356 })
357 }
358
359 func TestFuzz_noCustom(t *testing.T) {
360 type Inner struct {
361 Str string
362 }
363 type Outer struct {
364 Str string
365 In Inner
366 }
367
368 testPhrase := "gotcalled"
369 f := New().Funcs(
370 func(outer *Outer, c Continue) {
371 outer.Str = testPhrase
372 c.Fuzz(&outer.In)
373 },
374 func(inner *Inner, c Continue) {
375 inner.Str = testPhrase
376 },
377 )
378 c := Continue{fc: &fuzzerContext{fuzzer: f}, Rand: f.r}
379
380
381 obj1 := Outer{}
382 f.Fuzz(&obj1)
383 if obj1.Str != testPhrase {
384 t.Errorf("expected Outer custom function to have been called")
385 }
386 if obj1.In.Str != testPhrase {
387 t.Errorf("expected Inner custom function to have been called")
388 }
389
390
391 obj2 := Outer{}
392 c.Fuzz(&obj2)
393 if obj2.Str != testPhrase {
394 t.Errorf("expected Outer custom function to have been called")
395 }
396 if obj2.In.Str != testPhrase {
397 t.Errorf("expected Inner custom function to have been called")
398 }
399
400
401 obj3 := Outer{}
402 f.FuzzNoCustom(&obj3)
403 if obj3.Str == testPhrase {
404 t.Errorf("expected Outer custom function to not have been called")
405 }
406 if obj3.In.Str != testPhrase {
407 t.Errorf("expected Inner custom function to have been called")
408 }
409
410
411 obj4 := Outer{}
412 c.FuzzNoCustom(&obj4)
413 if obj4.Str == testPhrase {
414 t.Errorf("expected Outer custom function to not have been called")
415 }
416 if obj4.In.Str != testPhrase {
417 t.Errorf("expected Inner custom function to have been called")
418 }
419 }
420
421 func TestFuzz_NumElements(t *testing.T) {
422 f := New().NilChance(0).NumElements(0, 1)
423 obj := &struct {
424 A []int
425 }{}
426
427 tryFuzz(t, f, obj, func() (int, bool) {
428 if obj.A == nil {
429 return 1, false
430 }
431 return 2, len(obj.A) == 0
432 })
433 tryFuzz(t, f, obj, func() (int, bool) {
434 if obj.A == nil {
435 return 3, false
436 }
437 return 4, len(obj.A) == 1
438 })
439 }
440
441 func TestFuzz_Maxdepth(t *testing.T) {
442 type S struct {
443 S *S
444 }
445
446 f := New().NilChance(0)
447
448 f.MaxDepth(1)
449 for i := 0; i < 100; i++ {
450 obj := S{}
451 f.Fuzz(&obj)
452
453 if obj.S != nil {
454 t.Errorf("Expected nil")
455 }
456 }
457
458 f.MaxDepth(3)
459 for i := 0; i < 100; i++ {
460 obj := S{}
461 f.Fuzz(&obj)
462
463 if obj.S == nil {
464 t.Errorf("Expected obj.S not nil")
465 } else if obj.S.S != nil {
466 t.Errorf("Expected obj.S.S nil")
467 }
468 }
469
470 f.MaxDepth(5)
471 for i := 0; i < 100; i++ {
472 obj := S{}
473 f.Fuzz(&obj)
474
475 if obj.S == nil {
476 t.Errorf("Expected obj.S not nil")
477 } else if obj.S.S == nil {
478 t.Errorf("Expected obj.S.S not nil")
479 } else if obj.S.S.S != nil {
480 t.Errorf("Expected obj.S.S.S nil")
481 }
482 }
483 }
484
485 func TestFuzz_SkipPattern(t *testing.T) {
486 obj := &struct {
487 S1 string
488 S2 string
489 XXX_S string
490 S_XXX string
491 In struct {
492 Str string
493 XXX_S1 string
494 S2_XXX string
495 }
496 }{}
497
498 f := New().NilChance(0).SkipFieldsWithPattern(regexp.MustCompile(`^XXX_`))
499 f.Fuzz(obj)
500
501 tryFuzz(t, f, obj, func() (int, bool) {
502 if obj.XXX_S != "" {
503 return 1, false
504 }
505 if obj.S_XXX == "" {
506 return 2, false
507 }
508 if obj.In.XXX_S1 != "" {
509 return 3, false
510 }
511 if obj.In.S2_XXX == "" {
512 return 4, false
513 }
514 return 5, true
515 })
516 }
517
518 func TestFuzz_NilChanceZero(t *testing.T) {
519
520
521
522 data := []byte("H0000000\x00")
523 f := NewFromGoFuzz(data).NilChance(0)
524
525 var fancyStruct struct {
526 A, B, C, D *string
527 }
528 f.Fuzz(&fancyStruct)
529
530 if fancyStruct.A == nil {
531 t.Error("First value in struct was nil")
532 }
533
534 if fancyStruct.B == nil {
535 t.Error("Second value in struct was nil")
536 }
537
538 if fancyStruct.C == nil {
539 t.Error("Third value in struct was nil")
540 }
541
542 if fancyStruct.D == nil {
543 t.Error("Fourth value in struct was nil")
544 }
545 }
546
547 type int63mode int
548
549 const (
550 modeRandom int63mode = iota
551 modeFirst
552 modeLast
553 )
554
555 type customInt63 struct {
556 mode int63mode
557 }
558
559 func (c customInt63) Int63n(n int64) int64 {
560 switch c.mode {
561 case modeFirst:
562 return 0
563 case modeLast:
564 return n - 1
565 default:
566 return rand.Int63n(n)
567 }
568 }
569
570 func Test_charRange_choose(t *testing.T) {
571 lowercaseLetters := UnicodeRange{'a', 'z'}
572
573 t.Run("Picks first", func(t *testing.T) {
574 r := customInt63{mode: modeFirst}
575 letter := lowercaseLetters.choose(r)
576 if letter != 'a' {
577 t.Errorf("Expected a, got %v", letter)
578 }
579 })
580
581 t.Run("Picks last", func(t *testing.T) {
582 r := customInt63{mode: modeLast}
583 letter := lowercaseLetters.choose(r)
584 if letter != 'z' {
585 t.Errorf("Expected z, got %v", letter)
586 }
587 })
588 }
589
590 func Test_UnicodeRange_CustomStringFuzzFunc(t *testing.T) {
591 a2z := "abcdefghijklmnopqrstuvwxyz"
592
593 unicodeRange := UnicodeRange{'a', 'z'}
594 f := New().Funcs(unicodeRange.CustomStringFuzzFunc())
595 var myString string
596 f.Fuzz(&myString)
597
598 t.Run("Picks a-z string", func(t *testing.T) {
599 for i := range myString {
600 if !strings.ContainsRune(a2z, rune(myString[i])) {
601 t.Errorf("Expected a-z, got %v", string(myString[i]))
602 }
603 }
604 })
605 }
606
607 func Test_UnicodeRange_Check(t *testing.T) {
608 unicodeRange := UnicodeRange{'a', 'z'}
609
610 unicodeRange.check()
611 }
612
613 func Test_UnicodeRanges_CustomStringFuzzFunc(t *testing.T) {
614 a2z0to9 := "abcdefghijklmnopqrstuvwxyz0123456789"
615
616 unicodeRanges := UnicodeRanges{
617 {'a', 'z'},
618 {'0', '9'},
619 }
620 f := New().Funcs(unicodeRanges.CustomStringFuzzFunc())
621 var myString string
622 f.Fuzz(&myString)
623
624 t.Run("Picks a-z0-9 string", func(t *testing.T) {
625 for i := range myString {
626 if !strings.ContainsRune(a2z0to9, rune(myString[i])) {
627 t.Errorf("Expected a-z0-9, got %v", string(myString[i]))
628 }
629 }
630 })
631 }
632
633 func TestNewFromGoFuzz(t *testing.T) {
634 t.Parallel()
635
636 input := []byte{1, 2, 3}
637
638 var got int
639 NewFromGoFuzz(input).Fuzz(&got)
640
641 if want := 5563767293437588600; want != got {
642 t.Errorf("Fuzz(%q) = %d, want: %d", input, got, want)
643 }
644 }
645
646 func BenchmarkRandBool(b *testing.B) {
647 rs := rand.New(rand.NewSource(123))
648
649 for i := 0; i < b.N; i++ {
650 randBool(rs)
651 }
652 }
653
654 func BenchmarkRandString(b *testing.B) {
655 rs := rand.New(rand.NewSource(123))
656
657 for i := 0; i < b.N; i++ {
658 randString(rs)
659 }
660 }
661
662 func BenchmarkUnicodeRangeRandString(b *testing.B) {
663 unicodeRange := UnicodeRange{'a', 'z'}
664
665 rs := rand.New(rand.NewSource(123))
666
667 for i := 0; i < b.N; i++ {
668 unicodeRange.randString(rs)
669 }
670 }
671
672 func BenchmarkUnicodeRangesRandString(b *testing.B) {
673 unicodeRanges := UnicodeRanges{
674 {'a', 'z'},
675 {'0', '9'},
676 }
677
678 rs := rand.New(rand.NewSource(123))
679
680 for i := 0; i < b.N; i++ {
681 unicodeRanges.randString(rs)
682 }
683 }
684
View as plain text