Commit 302c79ea authored by Kirill Smelkov's avatar Kirill Smelkov Committed by Kamil Kisiel

fuzz: Hook encoder into the loop

We can enhance our fuzz-testing coverage by hooking Encoder also into
the loop: if input data is suceessfully decoded, we have an object that
can be passed back to Encoder to generate a pickle. We can't tell that
that pickle must be the same as original input data, since pickle
machine allows multiple representations of the same data. However we can
assert that when that pickle is decoded back it should be the same as
encoded object.

This catches several problems:

- marker is currently returned as pickle result (see next patch).
- text-based STRING and UNICODE are not properly decoded (no fix yet).
- self-referencing data structures kill Encoder (no fix yet).
parent 230ffba9
...@@ -7,7 +7,7 @@ ogórek is a Go library for encoding and decoding pickles. ...@@ -7,7 +7,7 @@ ogórek is a Go library for encoding and decoding pickles.
Fuzz Testing Fuzz Testing
------------ ------------
Fuzz testing has been implemented for the decoder. To run fuzz tests do the following: Fuzz testing has been implemented for decoder and encoder. To run fuzz tests do the following:
``` ```
go get github.com/dvyukov/go-fuzz/go-fuzz go get github.com/dvyukov/go-fuzz/go-fuzz
......
...@@ -4,14 +4,52 @@ package ogórek ...@@ -4,14 +4,52 @@ package ogórek
import ( import (
"bytes" "bytes"
"fmt"
"reflect"
) )
func Fuzz(data []byte) int { func Fuzz(data []byte) int {
// obj = decode(data) - this tests things like stack overflow in Decoder
buf := bytes.NewBuffer(data) buf := bytes.NewBuffer(data)
dec := NewDecoder(buf) dec := NewDecoder(buf)
_, err := dec.Decode() obj, err := dec.Decode()
if err != nil { if err != nil {
return 0 return 0
} }
// assert decode(encode(obj)) == obj
//
// this tests that Encoder and Decoder are consistent: sometimes
// Encoder is right and Decoder succeeds, but decodes data incorectly;
// sometimes vice versa. We can be safe to test for idempotency here
// because obj - as we got it as decoding from input - is known not to
// contain arbitrary Go structs.
for proto := 0; proto <= highestProtocol; proto++ {
buf.Reset()
enc := NewEncoderWithConfig(buf, &EncoderConfig{
Protocol: proto,
})
err = enc.Encode(obj)
if err != nil {
// must succeed, as obj was obtained via successful decode
// the only exception is that we cannot encode non-string Ref at proto=0
if proto == 0 && err == errP0PersIDStringLineOnly {
continue
}
panic(err)
}
dec = NewDecoder(buf)
obj2, err := dec.Decode()
if err != nil {
// must succeed, as buf should contain valid pickle from encoder
panic(err)
}
if !reflect.DeepEqual(obj, obj2) {
panic(fmt.Sprintf("protocol %d: decode·encode != identity:\nhave: %#v\nwant: %#v", proto, obj2, obj))
}
}
return 1 return 1
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment