pbtest: delete pkg because upstream IDL changes.
This commit deletes the blackbox end-to-end tests associated with
`testing/quick`, because several incompatible upstream changes broke
them, and it is difficult to tease apart where the fault lies for now.
It fixes #9.
The core of this is code is small and well tested. At the very worst,
integrators can inform us quickly about breakages.
diff --git a/pbtest/deleted.go b/pbtest/deleted.go
new file mode 100644
index 0000000..73efcb1
--- /dev/null
+++ b/pbtest/deleted.go
@@ -0,0 +1,2 @@
+// Package pbtest is deleted for the time being, because upstream Protocol Buffer 3 may have rendered quick.Value-based blackbox generation impossible.
+package pbtest
diff --git a/pbtest/doc.go b/pbtest/doc.go
deleted file mode 100644
index ff7820b..0000000
--- a/pbtest/doc.go
+++ /dev/null
@@ -1,16 +0,0 @@
-// Copyright 2015 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 pbtest provides mechanisms to assist with testing of Protocol Buffer messages.
-package pbtest
diff --git a/pbtest/example_test.go b/pbtest/example_test.go
deleted file mode 100644
index 6e4d880..0000000
--- a/pbtest/example_test.go
+++ /dev/null
@@ -1,64 +0,0 @@
-// Copyright 2015 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 pbtest
-
-import (
- "testing"
- "testing/quick"
-
- "github.com/golang/protobuf/proto"
-)
-
-func Example() {
- // You would place this in a top-level function, like TestDatastore(t *testing.T).
- var (
- datastore Datastore
- t *testing.T
- )
- if err := quick.Check(func(rec *CustomerRecord) bool {
- // testing/quick generated rec using quick.Value. We want to ensure that
- // semi-internal struct fields are recursively reset to a known value.
- SanitizeGenerated(rec)
- // Ensure that any record can be stored, no matter what!
- if err := datastore.Store(rec); err != nil {
- return false
- }
- return true
- }, nil); err != nil {
- t.Fatal(err)
- }
-}
-
-// Datastore models some system under test.
-type Datastore struct{}
-
-// Store stores a customer record.
-func (Datastore) Store(*CustomerRecord) error { return nil }
-
-// Types below are generated from protoc --go_out=. example.proto, where
-// example.proto contains
-// """
-// syntax = "proto2";
-// message CustomerRecord {
-// }
-// """
-
-type CustomerRecord struct {
- XXX_unrecognized []byte `json:"-"`
-}
-
-func (m *CustomerRecord) Reset() { *m = CustomerRecord{} }
-func (m *CustomerRecord) String() string { return proto.CompactTextString(m) }
-func (*CustomerRecord) ProtoMessage() {}
diff --git a/pbtest/quick.go b/pbtest/quick.go
deleted file mode 100644
index 6c12f28..0000000
--- a/pbtest/quick.go
+++ /dev/null
@@ -1,78 +0,0 @@
-// Copyright 2015 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 pbtest
-
-import (
- "errors"
- "reflect"
-
- "github.com/golang/protobuf/proto"
-)
-
-var (
- errNotPointer = errors.New("pbtest: cannot sanitize non-pointer message")
- errNotStruct = errors.New("pbtest: cannot sanitize non-struct message")
-)
-
-// SanitizeGenerated empties the private state fields of Protocol Buffer
-// messages that have been generated by the testing/quick package or returns
-// an error indicating a problem it encountered.
-func SanitizeGenerated(m proto.Message) error {
- return sanitizeGenerated(m, 0)
-}
-
-func sanitizeGenerated(m proto.Message, l int) error {
- typ := reflect.TypeOf(m)
- if typ.Kind() != reflect.Ptr {
- if l == 0 {
- // Changes cannot be applied to non-pointers.
- return errNotPointer
- }
- return nil
- }
- if elemTyp := typ.Elem(); elemTyp.Kind() != reflect.Struct {
- if l == 0 {
- // Protocol Buffer messages are structures; only they can be cleaned.
- return errNotStruct
- }
- return nil
- }
- elem := reflect.ValueOf(m).Elem()
- for i := 0; i < elem.NumField(); i++ {
- field := elem.Field(i)
- if field.Type().Implements(reflect.TypeOf((*proto.Message)(nil)).Elem()) {
- if err := sanitizeGenerated(field.Interface().(proto.Message), l+1); err != nil {
- return err
- }
- }
- if field.Kind() == reflect.Slice {
- for i := 0; i < field.Len(); i++ {
- elem := field.Index(i)
- if elem.Type().Implements(reflect.TypeOf((*proto.Message)(nil)).Elem()) {
- if err := sanitizeGenerated(elem.Interface().(proto.Message), l+1); err != nil {
- return err
- }
- }
- }
- }
- }
- if field := elem.FieldByName("XXX_unrecognized"); field.IsValid() {
- field.Set(reflect.ValueOf([]byte{}))
- }
- if field := elem.FieldByName("XXX_extensions"); field.IsValid() {
- field.Set(reflect.ValueOf(nil))
- }
- return nil
-}
diff --git a/pbutil/all_test.go b/pbutil/all_test.go
index 094156e..5c46372 100644
--- a/pbutil/all_test.go
+++ b/pbutil/all_test.go
@@ -16,18 +16,14 @@
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) {
+ t.Parallel()
for _, test := range []struct {
msg Message
buf []byte
@@ -83,6 +79,7 @@
}
func TestReadDelimited(t *testing.T) {
+ t.Parallel()
for _, test := range []struct {
buf []byte
msg Message
@@ -139,6 +136,7 @@
}
func TestEndToEndValid(t *testing.T) {
+ t.Parallel()
for _, test := range [][]Message{
{&Empty{}},
{&GoEnum{Foo: FOO_FOO1.Enum()}, &Empty{}, &GoEnum{Foo: FOO_FOO1.Enum()}},
@@ -177,144 +175,3 @@
}
}
}
-
-// 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
- var 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)
- }
-}
diff --git a/pbutil/decode.go b/pbutil/decode.go
index 66d9b54..258c063 100644
--- a/pbutil/decode.go
+++ b/pbutil/decode.go
@@ -38,7 +38,7 @@
func ReadDelimited(r io.Reader, m proto.Message) (n int, err error) {
// Per AbstractParser#parsePartialDelimitedFrom with
// CodedInputStream#readRawVarint32.
- headerBuf := make([]byte, binary.MaxVarintLen32)
+ var headerBuf [binary.MaxVarintLen32]byte
var bytesRead, varIntBytes int
var messageLength uint64
for varIntBytes == 0 { // i.e. no varint has been decoded yet.
diff --git a/pbutil/decode_test.go b/pbutil/decode_test.go
new file mode 100644
index 0000000..364a7b7
--- /dev/null
+++ b/pbutil/decode_test.go
@@ -0,0 +1,99 @@
+// Copyright 2016 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"
+ "io"
+ "testing"
+ "testing/iotest"
+)
+
+func TestReadDelimitedIllegalVarint(t *testing.T) {
+ t.Parallel()
+ var tests = []struct {
+ in []byte
+ n int
+ err error
+ }{
+ {
+ in: []byte{255, 255, 255, 255, 255},
+ n: 5,
+ err: errInvalidVarint,
+ },
+ {
+ in: []byte{255, 255, 255, 255, 255, 255},
+ n: 5,
+ err: errInvalidVarint,
+ },
+ }
+ for _, test := range tests {
+ n, err := ReadDelimited(bytes.NewReader(test.in), nil)
+ if got, want := n, test.n; got != want {
+ t.Errorf("ReadDelimited(%#v, nil) = %#v, ?; want = %v#, ?", test.in, got, want)
+ }
+ if got, want := err, test.err; got != want {
+ t.Errorf("ReadDelimited(%#v, nil) = ?, %#v; want = ?, %#v", test.in, got, want)
+ }
+ }
+}
+
+func TestReadDelimitedPrematureHeader(t *testing.T) {
+ t.Parallel()
+ var data = []byte{128, 5} // 256 + 256 + 128
+ n, err := ReadDelimited(bytes.NewReader(data[0:1]), nil)
+ if got, want := n, 1; got != want {
+ t.Errorf("ReadDelimited(%#v, nil) = %#v, ?; want = %v#, ?", data[0:1], got, want)
+ }
+ if got, want := err, io.EOF; got != want {
+ t.Errorf("ReadDelimited(%#v, nil) = ?, %#v; want = ?, %#v", data[0:1], got, want)
+ }
+}
+
+func TestReadDelimitedPrematureBody(t *testing.T) {
+ t.Parallel()
+ var data = []byte{128, 5, 0, 0, 0} // 256 + 256 + 128
+ n, err := ReadDelimited(bytes.NewReader(data[:]), nil)
+ if got, want := n, 5; got != want {
+ t.Errorf("ReadDelimited(%#v, nil) = %#v, ?; want = %v#, ?", data, got, want)
+ }
+ if got, want := err, io.ErrUnexpectedEOF; got != want {
+ t.Errorf("ReadDelimited(%#v, nil) = ?, %#v; want = ?, %#v", data, got, want)
+ }
+}
+
+func TestReadDelimitedPrematureHeaderIncremental(t *testing.T) {
+ t.Parallel()
+ var data = []byte{128, 5} // 256 + 256 + 128
+ n, err := ReadDelimited(iotest.OneByteReader(bytes.NewReader(data[0:1])), nil)
+ if got, want := n, 1; got != want {
+ t.Errorf("ReadDelimited(%#v, nil) = %#v, ?; want = %v#, ?", data[0:1], got, want)
+ }
+ if got, want := err, io.EOF; got != want {
+ t.Errorf("ReadDelimited(%#v, nil) = ?, %#v; want = ?, %#v", data[0:1], got, want)
+ }
+}
+
+func TestReadDelimitedPrematureBodyIncremental(t *testing.T) {
+ t.Parallel()
+ var data = []byte{128, 5, 0, 0, 0} // 256 + 256 + 128
+ n, err := ReadDelimited(iotest.OneByteReader(bytes.NewReader(data[:])), nil)
+ if got, want := n, 5; got != want {
+ t.Errorf("ReadDelimited(%#v, nil) = %#v, ?; want = %v#, ?", data, got, want)
+ }
+ if got, want := err, io.ErrUnexpectedEOF; got != want {
+ t.Errorf("ReadDelimited(%#v, nil) = ?, %#v; want = ?, %#v", data, got, want)
+ }
+}
diff --git a/pbutil/encode.go b/pbutil/encode.go
index 4b76ea9..8fb59ad 100644
--- a/pbutil/encode.go
+++ b/pbutil/encode.go
@@ -33,8 +33,8 @@
return 0, err
}
- buf := make([]byte, binary.MaxVarintLen32)
- encodedLength := binary.PutUvarint(buf, uint64(len(buffer)))
+ var buf [binary.MaxVarintLen32]byte
+ encodedLength := binary.PutUvarint(buf[:], uint64(len(buffer)))
sync, err := w.Write(buf[:encodedLength])
if err != nil {
diff --git a/pbutil/encode_test.go b/pbutil/encode_test.go
new file mode 100644
index 0000000..f92632b
--- /dev/null
+++ b/pbutil/encode_test.go
@@ -0,0 +1,67 @@
+// Copyright 2016 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"
+ "errors"
+ "testing"
+
+ "github.com/golang/protobuf/proto"
+)
+
+var errMarshal = errors.New("pbutil: can't marshal")
+
+type cantMarshal struct{ proto.Message }
+
+func (cantMarshal) Marshal() ([]byte, error) { return nil, errMarshal }
+
+var _ proto.Message = cantMarshal{}
+
+func TestWriteDelimitedMarshalErr(t *testing.T) {
+ t.Parallel()
+ var data cantMarshal
+ var buf bytes.Buffer
+ n, err := WriteDelimited(&buf, data)
+ if got, want := n, 0; got != want {
+ t.Errorf("WriteDelimited(buf, %#v) = %#v, ?; want = %v#, ?", data, got, want)
+ }
+ if got, want := err, errMarshal; got != want {
+ t.Errorf("WriteDelimited(buf, %#v) = ?, %#v; want = ?, %#v", data, got, want)
+ }
+}
+
+type canMarshal struct{ proto.Message }
+
+func (canMarshal) Marshal() ([]byte, error) { return []byte{0, 1, 2, 3, 4, 5}, nil }
+
+var errWrite = errors.New("pbutil: can't write")
+
+type cantWrite struct{}
+
+func (cantWrite) Write([]byte) (int, error) { return 0, errWrite }
+
+func TestWriteDelimitedWriteErr(t *testing.T) {
+ t.Parallel()
+ var data canMarshal
+ var buf cantWrite
+ n, err := WriteDelimited(buf, data)
+ if got, want := n, 0; got != want {
+ t.Errorf("WriteDelimited(buf, %#v) = %#v, ?; want = %v#, ?", data, got, want)
+ }
+ if got, want := err, errWrite; got != want {
+ t.Errorf("WriteDelimited(buf, %#v) = ?, %#v; want = ?, %#v", data, got, want)
+ }
+}