Swap ext for pbutil because old name was bad.
The original package name never conveyed the purpose very clearly.
We can stand on the shoulder of established convention and make this
anonymous utility package better by following the example of io/ioutil.
Doing so makes it compliant with the new conventions set forth here:
http://goo.gl/K3u9aj.
diff --git a/README.md b/README.md
index 8f4f4df..751ee69 100644
--- a/README.md
+++ b/README.md
@@ -3,10 +3,10 @@
language (golang), namely support for record length-delimited message
streaming.
-| Java | Go |
-| ------------------------------ | ------------------ |
-| MessageLite#parseDelimitedFrom | ext.ReadDelimited |
-| MessageLite#writeDelimitedTo | ext.WriteDelimited |
+| Java | Go |
+| ------------------------------ | --------------------- |
+| MessageLite#parseDelimitedFrom | pbutil.ReadDelimited |
+| MessageLite#writeDelimitedTo | pbutil.WriteDelimited |
Because [Code Review 9102043](https://codereview.appspot.com/9102043/) is
destined to never be merged into mainline (i.e., never be promoted to formal
@@ -14,7 +14,7 @@
will live here in the wild.
# Documentation
-We have [generated Go Doc documentation](http://godoc.org/github.com/matttproud/golang_protobuf_extensions/ext) here.
+We have [generated Go Doc documentation](http://godoc.org/github.com/matttproud/golang_protobuf_extensions/pbutil) here.
# Testing
[](https://travis-ci.org/matttproud/golang_protobuf_extensions)
diff --git a/ext/moved.go b/ext/moved.go
new file mode 100644
index 0000000..f31a0f0
--- /dev/null
+++ b/ext/moved.go
@@ -0,0 +1,2 @@
+// Package ext moved to a new location: github.com/matttproud/golang_protobuf_extensions/pbutil.
+package ext
diff --git a/ext/doc.go b/pbtest/doc.go
similarity index 80%
copy from ext/doc.go
copy to pbtest/doc.go
index 652907b..ff7820b 100644
--- a/ext/doc.go
+++ b/pbtest/doc.go
@@ -1,4 +1,4 @@
-// Copyright 2013 Matt T. Proud
+// 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.
@@ -12,5 +12,5 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-// Package ext enables record length-delimited Protocol Buffer streaming.
-package ext
+// 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
new file mode 100644
index 0000000..6e4d880
--- /dev/null
+++ b/pbtest/example_test.go
@@ -0,0 +1,64 @@
+// 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
new file mode 100644
index 0000000..6c12f28
--- /dev/null
+++ b/pbtest/quick.go
@@ -0,0 +1,78 @@
+// 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/ext/all_test.go b/pbutil/all_test.go
similarity index 86%
rename from ext/all_test.go
rename to pbutil/all_test.go
index 7270b67..de1f9eb 100644
--- a/ext/all_test.go
+++ b/pbutil/all_test.go
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-package ext
+package pbutil
import (
"bytes"
@@ -21,6 +21,8 @@
"testing"
"testing/quick"
+ "github.com/matttproud/golang_protobuf_extensions/pbtest"
+
. "github.com/golang/protobuf/proto"
. "github.com/golang/protobuf/proto/testdata"
)
@@ -138,10 +140,10 @@
func TestEndToEndValid(t *testing.T) {
for _, test := range [][]Message{
- []Message{&Empty{}},
- []Message{&GoEnum{Foo: FOO_FOO1.Enum()}, &Empty{}, &GoEnum{Foo: FOO_FOO1.Enum()}},
- []Message{&GoEnum{Foo: FOO_FOO1.Enum()}},
- []Message{&Strings{
+ {&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.
@@ -176,45 +178,6 @@
}
}
-// visitMessage empties the private state fields of the quick.Value()-generated
-// Protocol Buffer messages, for they cause an inordinate amount of problems.
-// This is because we are using an automated fuzz generator on a type with
-// private fields.
-func visitMessage(m Message) {
- t := reflect.TypeOf(m)
- if t.Kind() != reflect.Ptr {
- return
- }
- derefed := t.Elem()
- if derefed.Kind() != reflect.Struct {
- return
- }
- v := reflect.ValueOf(m)
- elem := v.Elem()
- for i := 0; i < elem.NumField(); i++ {
- field := elem.FieldByIndex([]int{i})
- fieldType := field.Type()
- if fieldType.Implements(reflect.TypeOf((*Message)(nil)).Elem()) {
- visitMessage(field.Interface().(Message))
- }
- if field.Kind() == reflect.Slice {
- for i := 0; i < field.Len(); i++ {
- elem := field.Index(i)
- elemType := elem.Type()
- if elemType.Implements(reflect.TypeOf((*Message)(nil)).Elem()) {
- visitMessage(elem.Interface().(Message))
- }
- }
- }
- }
- 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))
- }
-}
-
// rndMessage generates a random valid Protocol Buffer message.
func rndMessage(r *rand.Rand) Message {
var t reflect.Type
@@ -307,7 +270,9 @@
if !ok {
panic("attempt to generate illegal item; consult item 11")
}
- visitMessage(v.Interface().(Message))
+ if err := pbtest.SanitizeGenerated(v.Interface().(Message)); err != nil {
+ panic(err)
+ }
return v.Interface().(Message)
}
@@ -325,8 +290,10 @@
rnd := rand.New(rand.NewSource(42))
check := func() bool {
messages := rndMessages(rnd)
- var buf bytes.Buffer
- var written int
+ var (
+ buf bytes.Buffer
+ written int
+ )
for i, msg := range messages {
n, err := WriteDelimited(&buf, msg)
if err != nil {
diff --git a/ext/decode.go b/pbutil/decode.go
similarity index 99%
rename from ext/decode.go
rename to pbutil/decode.go
index 28b520e..66d9b54 100644
--- a/ext/decode.go
+++ b/pbutil/decode.go
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-package ext
+package pbutil
import (
"encoding/binary"
diff --git a/ext/doc.go b/pbutil/doc.go
similarity index 86%
rename from ext/doc.go
rename to pbutil/doc.go
index 652907b..c318385 100644
--- a/ext/doc.go
+++ b/pbutil/doc.go
@@ -12,5 +12,5 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-// Package ext enables record length-delimited Protocol Buffer streaming.
-package ext
+// Package pbutil provides record length-delimited Protocol Buffer streaming.
+package pbutil
diff --git a/ext/encode.go b/pbutil/encode.go
similarity index 98%
rename from ext/encode.go
rename to pbutil/encode.go
index 473b31d..4b76ea9 100644
--- a/ext/encode.go
+++ b/pbutil/encode.go
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-package ext
+package pbutil
import (
"encoding/binary"
diff --git a/ext/fixtures_test.go b/pbutil/fixtures_test.go
similarity index 99%
rename from ext/fixtures_test.go
rename to pbutil/fixtures_test.go
index 07e75c5..d6d9b25 100644
--- a/ext/fixtures_test.go
+++ b/pbutil/fixtures_test.go
@@ -27,7 +27,7 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-package ext
+package pbutil
import (
. "github.com/golang/protobuf/proto"