blob: de1f9eb53b87f84e91e36ef5fae192618d8071ac [file] [log] [blame]
// Copyright 2013 Matt T. Proud
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package pbutil
import (
"bytes"
"math/rand"
"reflect"
"testing"
"testing/quick"
"github.com/matttproud/golang_protobuf_extensions/pbtest"
. "github.com/golang/protobuf/proto"
. "github.com/golang/protobuf/proto/testdata"
)
func TestWriteDelimited(t *testing.T) {
for _, test := range []struct {
msg Message
buf []byte
n int
err error
}{
{
msg: &Empty{},
n: 1,
buf: []byte{0},
},
{
msg: &GoEnum{Foo: FOO_FOO1.Enum()},
n: 3,
buf: []byte{2, 8, 1},
},
{
msg: &Strings{
StringField: String(`This is my gigantic, unhappy string. It exceeds
the encoding size of a single byte varint. We are using it to fuzz test the
correctness of the header decoding mechanisms, which may prove problematic.
I expect it may. Let's hope you enjoy testing as much as we do.`),
},
n: 271,
buf: []byte{141, 2, 10, 138, 2, 84, 104, 105, 115, 32, 105, 115, 32, 109,
121, 32, 103, 105, 103, 97, 110, 116, 105, 99, 44, 32, 117, 110, 104,
97, 112, 112, 121, 32, 115, 116, 114, 105, 110, 103, 46, 32, 32, 73,
116, 32, 101, 120, 99, 101, 101, 100, 115, 10, 116, 104, 101, 32, 101,
110, 99, 111, 100, 105, 110, 103, 32, 115, 105, 122, 101, 32, 111, 102,
32, 97, 32, 115, 105, 110, 103, 108, 101, 32, 98, 121, 116, 101, 32,
118, 97, 114, 105, 110, 116, 46, 32, 32, 87, 101, 32, 97, 114, 101, 32,
117, 115, 105, 110, 103, 32, 105, 116, 32, 116, 111, 32, 102, 117, 122,
122, 32, 116, 101, 115, 116, 32, 116, 104, 101, 10, 99, 111, 114, 114,
101, 99, 116, 110, 101, 115, 115, 32, 111, 102, 32, 116, 104, 101, 32,
104, 101, 97, 100, 101, 114, 32, 100, 101, 99, 111, 100, 105, 110, 103,
32, 109, 101, 99, 104, 97, 110, 105, 115, 109, 115, 44, 32, 119, 104,
105, 99, 104, 32, 109, 97, 121, 32, 112, 114, 111, 118, 101, 32, 112,
114, 111, 98, 108, 101, 109, 97, 116, 105, 99, 46, 10, 73, 32, 101, 120,
112, 101, 99, 116, 32, 105, 116, 32, 109, 97, 121, 46, 32, 32, 76, 101,
116, 39, 115, 32, 104, 111, 112, 101, 32, 121, 111, 117, 32, 101, 110,
106, 111, 121, 32, 116, 101, 115, 116, 105, 110, 103, 32, 97, 115, 32,
109, 117, 99, 104, 32, 97, 115, 32, 119, 101, 32, 100, 111, 46},
},
} {
var buf bytes.Buffer
if n, err := WriteDelimited(&buf, test.msg); n != test.n || err != test.err {
t.Fatalf("WriteDelimited(buf, %#v) = %v, %v; want %v, %v", test.msg, n, err, test.n, test.err)
}
if out := buf.Bytes(); !bytes.Equal(out, test.buf) {
t.Fatalf("WriteDelimited(buf, %#v); buf = %v; want %v", test.msg, out, test.buf)
}
}
}
func TestReadDelimited(t *testing.T) {
for _, test := range []struct {
buf []byte
msg Message
n int
err error
}{
{
buf: []byte{0},
msg: &Empty{},
n: 1,
},
{
n: 3,
buf: []byte{2, 8, 1},
msg: &GoEnum{Foo: FOO_FOO1.Enum()},
},
{
buf: []byte{141, 2, 10, 138, 2, 84, 104, 105, 115, 32, 105, 115, 32, 109,
121, 32, 103, 105, 103, 97, 110, 116, 105, 99, 44, 32, 117, 110, 104,
97, 112, 112, 121, 32, 115, 116, 114, 105, 110, 103, 46, 32, 32, 73,
116, 32, 101, 120, 99, 101, 101, 100, 115, 10, 116, 104, 101, 32, 101,
110, 99, 111, 100, 105, 110, 103, 32, 115, 105, 122, 101, 32, 111, 102,
32, 97, 32, 115, 105, 110, 103, 108, 101, 32, 98, 121, 116, 101, 32,
118, 97, 114, 105, 110, 116, 46, 32, 32, 87, 101, 32, 97, 114, 101, 32,
117, 115, 105, 110, 103, 32, 105, 116, 32, 116, 111, 32, 102, 117, 122,
122, 32, 116, 101, 115, 116, 32, 116, 104, 101, 10, 99, 111, 114, 114,
101, 99, 116, 110, 101, 115, 115, 32, 111, 102, 32, 116, 104, 101, 32,
104, 101, 97, 100, 101, 114, 32, 100, 101, 99, 111, 100, 105, 110, 103,
32, 109, 101, 99, 104, 97, 110, 105, 115, 109, 115, 44, 32, 119, 104,
105, 99, 104, 32, 109, 97, 121, 32, 112, 114, 111, 118, 101, 32, 112,
114, 111, 98, 108, 101, 109, 97, 116, 105, 99, 46, 10, 73, 32, 101, 120,
112, 101, 99, 116, 32, 105, 116, 32, 109, 97, 121, 46, 32, 32, 76, 101,
116, 39, 115, 32, 104, 111, 112, 101, 32, 121, 111, 117, 32, 101, 110,
106, 111, 121, 32, 116, 101, 115, 116, 105, 110, 103, 32, 97, 115, 32,
109, 117, 99, 104, 32, 97, 115, 32, 119, 101, 32, 100, 111, 46},
msg: &Strings{
StringField: String(`This is my gigantic, unhappy string. It exceeds
the encoding size of a single byte varint. We are using it to fuzz test the
correctness of the header decoding mechanisms, which may prove problematic.
I expect it may. Let's hope you enjoy testing as much as we do.`),
},
n: 271,
},
} {
msg := Clone(test.msg)
msg.Reset()
if n, err := ReadDelimited(bytes.NewBuffer(test.buf), msg); n != test.n || err != test.err {
t.Fatalf("ReadDelimited(%v, msg) = %v, %v; want %v, %v", test.buf, n, err, test.n, test.err)
}
if !Equal(msg, test.msg) {
t.Fatalf("ReadDelimited(%v, msg); msg = %v; want %v", test.buf, msg, test.msg)
}
}
}
func TestEndToEndValid(t *testing.T) {
for _, test := range [][]Message{
{&Empty{}},
{&GoEnum{Foo: FOO_FOO1.Enum()}, &Empty{}, &GoEnum{Foo: FOO_FOO1.Enum()}},
{&GoEnum{Foo: FOO_FOO1.Enum()}},
{&Strings{
StringField: String(`This is my gigantic, unhappy string. It exceeds
the encoding size of a single byte varint. We are using it to fuzz test the
correctness of the header decoding mechanisms, which may prove problematic.
I expect it may. Let's hope you enjoy testing as much as we do.`),
}},
} {
var buf bytes.Buffer
var written int
for i, msg := range test {
n, err := WriteDelimited(&buf, msg)
if err != nil {
// Assumption: TestReadDelimited and TestWriteDelimited are sufficient
// and inputs for this test are explicitly exercised there.
t.Fatalf("WriteDelimited(buf, %v[%d]) = ?, %v; wanted ?, nil", test, i, err)
}
written += n
}
var read int
for i, msg := range test {
out := Clone(msg)
out.Reset()
n, _ := ReadDelimited(&buf, out)
// Decide to do EOF checking?
read += n
if !Equal(out, msg) {
t.Fatalf("out = %v; want %v[%d] = %#v", out, test, i, msg)
}
}
if read != written {
t.Fatalf("%v read = %d; want %d", test, read, written)
}
}
}
// rndMessage generates a random valid Protocol Buffer message.
func rndMessage(r *rand.Rand) Message {
var t reflect.Type
switch v := rand.Intn(23); v {
// TODO(br): Uncomment the elements below once fix is incorporated, except
// for the elements marked as patently incompatible.
// case 0:
// t = reflect.TypeOf(&GoEnum{})
// break
// case 1:
// t = reflect.TypeOf(&GoTestField{})
// break
case 2:
t = reflect.TypeOf(&GoTest{})
break
// case 3:
// t = reflect.TypeOf(&GoSkipTest{})
// break
// case 4:
// t = reflect.TypeOf(&NonPackedTest{})
// break
// case 5:
// t = reflect.TypeOf(&PackedTest{})
// break
case 6:
t = reflect.TypeOf(&MaxTag{})
break
case 7:
t = reflect.TypeOf(&OldMessage{})
break
case 8:
t = reflect.TypeOf(&NewMessage{})
break
case 9:
t = reflect.TypeOf(&InnerMessage{})
break
case 10:
t = reflect.TypeOf(&OtherMessage{})
break
case 11:
// PATENTLY INVALID FOR FUZZ GENERATION
// t = reflect.TypeOf(&MyMessage{})
break
// case 12:
// t = reflect.TypeOf(&Ext{})
// break
case 13:
// PATENTLY INVALID FOR FUZZ GENERATION
// t = reflect.TypeOf(&MyMessageSet{})
break
// case 14:
// t = reflect.TypeOf(&Empty{})
// break
// case 15:
// t = reflect.TypeOf(&MessageList{})
// break
// case 16:
// t = reflect.TypeOf(&Strings{})
// break
// case 17:
// t = reflect.TypeOf(&Defaults{})
// break
// case 17:
// t = reflect.TypeOf(&SubDefaults{})
// break
// case 18:
// t = reflect.TypeOf(&RepeatedEnum{})
// break
case 19:
t = reflect.TypeOf(&MoreRepeated{})
break
// case 20:
// t = reflect.TypeOf(&GroupOld{})
// break
// case 21:
// t = reflect.TypeOf(&GroupNew{})
// break
case 22:
t = reflect.TypeOf(&FloatingPoint{})
break
default:
// TODO(br): Replace with an unreachable once fixed.
t = reflect.TypeOf(&GoTest{})
break
}
if t == nil {
t = reflect.TypeOf(&GoTest{})
}
v, ok := quick.Value(t, r)
if !ok {
panic("attempt to generate illegal item; consult item 11")
}
if err := pbtest.SanitizeGenerated(v.Interface().(Message)); err != nil {
panic(err)
}
return v.Interface().(Message)
}
// rndMessages generates several random Protocol Buffer messages.
func rndMessages(r *rand.Rand) []Message {
n := r.Intn(128)
out := make([]Message, 0, n)
for i := 0; i < n; i++ {
out = append(out, rndMessage(r))
}
return out
}
func TestFuzz(t *testing.T) {
rnd := rand.New(rand.NewSource(42))
check := func() bool {
messages := rndMessages(rnd)
var (
buf bytes.Buffer
written int
)
for i, msg := range messages {
n, err := WriteDelimited(&buf, msg)
if err != nil {
t.Fatalf("WriteDelimited(buf, %v[%d]) = ?, %v; wanted ?, nil", messages, i, err)
}
written += n
}
var read int
for i, msg := range messages {
out := Clone(msg)
out.Reset()
n, _ := ReadDelimited(&buf, out)
read += n
if !Equal(out, msg) {
t.Fatalf("out = %v; want %v[%d] = %#v", out, messages, i, msg)
}
}
if read != written {
t.Fatalf("%v read = %d; want %d", messages, read, written)
}
return true
}
if err := quick.Check(check, nil); err != nil {
t.Fatal(err)
}
}