Skip to content

Commit

Permalink
Integrated fuzzing support
Browse files Browse the repository at this point in the history
Fixes #32.
  • Loading branch information
flyingmutant committed Aug 29, 2022
1 parent ae12a36 commit d965f9f
Show file tree
Hide file tree
Showing 3 changed files with 98 additions and 1 deletion.
1 change: 0 additions & 1 deletion TODO.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

- explicit examples support (based on `refDraws` shrink test machinery)
- explicit settings support (to not depend on global environment)
- [go-fuzz](https://github.com/golang/proposal/blob/master/design/draft-fuzzing.md) integration

## Generators

Expand Down
47 changes: 47 additions & 0 deletions engine.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ package rapid

import (
"bytes"
"encoding/binary"
"flag"
"fmt"
"log"
Expand Down Expand Up @@ -113,6 +114,46 @@ func MakeCheck(prop func(*T)) func(*testing.T) {
}
}

// MakeFuzz creates a fuzz target for [*testing.F.Fuzz]:
//
// func FuzzFoo(f *testing.F) {
// f.Fuzz(rapid.MakeFuzz(func(t *rapid.T) {
// // test code
// }))
// }
func MakeFuzz(prop func(*T)) func(*testing.T, []byte) {
return func(t *testing.T, input []byte) {
t.Helper()
checkFuzz(t, prop, input)
}
}

func checkFuzz(tb tb, prop func(*T), input []byte) {
tb.Helper()

var buf []uint64
for len(input) > 0 {
var tmp [8]byte
n := copy(tmp[:], input)
buf = append(buf, binary.LittleEndian.Uint64(tmp[:]))
input = input[n:]
}

t := newT(tb, newBufBitStream(buf, false), flags.verbose, nil)
err := checkOnce(t, prop)

switch {
case err == nil:
// do nothing
case err.isInvalidData():
tb.SkipNow()
case err.isStopTest():
tb.Fatalf("[rapid] failed: %v", err)
default:
tb.Fatalf("[rapid] panic: %v\nTraceback:\n%v", err, traceback(err))
}
}

func checkTB(tb tb, prop func(*T)) {
tb.Helper()

Expand Down Expand Up @@ -373,6 +414,9 @@ type TB interface {
Name() string
Logf(format string, args ...any)
Log(args ...any)
Skipf(format string, args ...any)
Skip(args ...any)
SkipNow()
Errorf(format string, args ...any)
Error(args ...any)
Fatalf(format string, args ...any)
Expand All @@ -388,6 +432,9 @@ type tb interface {
Name() string
Logf(format string, args ...any)
Log(args ...any)
Skipf(format string, args ...any)
Skip(args ...any)
SkipNow()
Errorf(format string, args ...any)
Error(args ...any)
Fatalf(format string, args ...any)
Expand Down
51 changes: 51 additions & 0 deletions engine_fuzz_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// Copyright 2022 Gregory Petrosyan <gregory.petrosyan@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.

package rapid_test

import (
"testing"

. "pgregory.net/rapid"
)

func checkInt(t *T) {
answer := Int().Draw(t, "answer")
if answer == 42 {
t.Fatalf("fuzzing works")
}
}

func checkSlice(t *T) {
slice := SliceOfN(Int(), 5, 5).Draw(t, "slice")
if slice[0] < slice[1] && slice[1] < slice[2] && slice[2] < slice[3] && slice[3] < slice[4] {
t.Fatalf("fuzzing works")
}
}

func checkString(t *T) {
hello := String().Draw(t, "hello")
if hello == "world" {
t.Fatalf("fuzzing works")
}
}

func TestRapidInt(t *testing.T) {
t.Skip()
Check(t, checkInt)
}
func TestRapidSlice(t *testing.T) {
t.Skip()
Check(t, checkSlice)
}
func TestRapidString(t *testing.T) {
t.Skip()
Check(t, checkString)
}

func FuzzInt(f *testing.F) { f.Fuzz(MakeFuzz(checkInt)) }
func FuzzSlice(f *testing.F) { f.Fuzz(MakeFuzz(checkSlice)) }
func FuzzString(f *testing.F) { f.Fuzz(MakeFuzz(checkString)) }

0 comments on commit d965f9f

Please sign in to comment.