Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: matttproud/golang_protobuf_extensions
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: v1.0.4
Choose a base ref
...
head repository: matttproud/golang_protobuf_extensions
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: v2.0.0
Choose a head ref
  • 3 commits
  • 13 files changed
  • 1 contributor

Commits on Oct 23, 2022

  1. pbutil: modernize the package for 2022.

    This commit modernizes the package along several dimensions:
    
    * Rebasing on Protocol Buffers using native reflection API.
    * Refactoring tests to use `errors.Is` and `cmp` and subtests.
    * 100% test coverage, which is not a useful measure in and of
      itself.
    
    This version has been tested solely on Go 1.19, though I expect
    that Go 1.13 would work.
    matttproud committed Oct 23, 2022
    Copy the full SHA
    c5a68ec View commit details

Commits on Oct 25, 2022

  1. Merge pull request #18 from matttproud/refactor/modernize-to-go1.19

    Modernize the package for 2022.
    matttproud authored Oct 25, 2022

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    d8e45f2 View commit details
  2. pbutil: publish major version 2 of this module.

    This commit provides a touch-up of v1.0.3.  Since it introduces a new
    major version, several steps to upgrade will need to be followed as
    described in the CHANGELOG.md file.  Users of major version 1 can continue
    using that version until they are ready to transition.
    matttproud committed Oct 25, 2022
    Copy the full SHA
    5a0f916 View commit details
Showing with 466 additions and 4,646 deletions.
  1. +1 −3 .travis.yml
  2. +66 −0 CHANGELOG.md
  3. +3 −3 README.md
  4. +4 −4 go.mod
  5. +8 −4 go.sum
  6. +109 −76 pbutil/all_test.go
  7. +11 −5 pbutil/decode.go
  8. +53 −20 pbutil/decode_test.go
  9. +4 −1 pbutil/encode.go
  10. +14 −23 pbutil/encode_test.go
  11. +0 −4 testdata/README.THIRD_PARTY
  12. +176 −3,975 testdata/test.pb.go
  13. +17 −528 testdata/test.proto
4 changes: 1 addition & 3 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
language: go

go:
- 1.9.x
- 1.10.x
- 1.11.x
- 1.19.x
- tip

script: make -f Makefile.TRAVIS
66 changes: 66 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# Changelog

## v2.0.0

**Summary**: Modernization of this package to Go standards in 2022, mostly
through internal cleanups.

**New Features**: None

The last time this package was significantly modified was 2016, which predates
`cmp`, subtests, the modern Protocol Buffer implementation, and numerous Go
practices that emerged in the intervening years. The new release is tested
against Go 1.19, though I expect it would work with Go 1.13 just fine.

Finally, I declared bankruptcy on the vendored test fixtures and opted for
creating my own. This is due to the underlying implementation of the generated
code in conjunction with working with a moving target that is an external data
model representation.

**Upgrade Notes**: This is the aborted v1.0.3 release repackaged as a new
major version 2. To use this, you will need to do or check the following:

1. The Protocol Buffer messages you provide to this API are from the
`google.golang.org/protobuf` module. Take special care to audit any
generated or checked-in Protocol Buffer message file assets. They may need
to be regenerated.

2. Your code should presumably use the `google.golang.org/protobuf` module for
Protocol Buffers.

3. This is a new major version of the module, so you will need to transition
from module `github.com/matttproud/golang_protobuf_extensions` to
`github.com/matttproud/golang_protobuf_extensions/v2`.

## v1.0.4

**Summary**: This is an emergency re-tag of v1.0.2 since v1.0.3 broke API
compatibility for legacy users. See the description of v1.0.2 for details.

## v1.0.3

**DO NOT USE**: Use v1.0.4 instead. What is described in v1.0.3 will be
transitioned to a new major version.

**Summary**: Modernization of this package to Go standards in 2022, mostly
through internal cleanups.

**New Features**: None

The last time this package was significantly modified was 2016, which predates
`cmp`, subtests, the modern Protocol Buffer implementation, and numerous Go
practices that emerged in the intervening years. The new release is tested
against Go 1.19, though I expect it would work with Go 1.13 just fine.

Finally, I declared bankruptcy on the vendored test fixtures and opted for
creating my own. This is due to the underlying implementation of the generated
code in conjunction with working with a moving target that is an external data
model representation.

## v1.0.2

**Summary**: Tagged version with Go module support.

**New Features**: None

End-users wanted a tagged release that includes Go module support.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Overview
This repository provides various Protocol Buffer extensions for the Go
language (golang), namely support for record length-delimited message
streaming.
This repository provides various Protocol Buffer feature extensions for the Go
programming language (golang), namely support for record length-delimited
message streaming.

| Java | Go |
| ------------------------------ | --------------------- |
8 changes: 4 additions & 4 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
module github.com/matttproud/golang_protobuf_extensions
module github.com/matttproud/golang_protobuf_extensions/v2

go 1.9
go 1.19

require (
github.com/golang/protobuf v1.2.0
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 // indirect
github.com/google/go-cmp v0.5.9
google.golang.org/protobuf v1.28.1
)
12 changes: 8 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 h1:YUO/7uOKsKeq9UokNS62b8FYywz3ker1l1vDZRCRefw=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
185 changes: 109 additions & 76 deletions pbutil/all_test.go
Original file line number Diff line number Diff line change
@@ -16,40 +16,46 @@ package pbutil

import (
"bytes"
"errors"
"testing"

"github.com/golang/protobuf/proto"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/testing/protocmp"

. "github.com/matttproud/golang_protobuf_extensions/testdata"
"github.com/google/go-cmp/cmp"
"github.com/matttproud/golang_protobuf_extensions/v2/testdata"
)

func TestWriteDelimited(t *testing.T) {
t.Parallel()
for _, test := range []struct {
msg proto.Message
buf []byte
n int
err error
name string
msg proto.Message
buf []byte
n int
err error
}{
{
msg: &Empty{},
n: 1,
buf: []byte{0},
name: "empty",
msg: new(testdata.Record),
n: 1,
buf: []byte{0},
},
{
msg: &GoEnum{Foo: FOO_FOO1.Enum()},
n: 3,
buf: []byte{2, 8, 1},
name: "firstfield",
msg: &testdata.Record{First: proto.Uint64(1)},
n: 3,
buf: []byte{2, 8, 1},
},
{
msg: &Strings{
StringField: proto.String(`This is my gigantic, unhappy string. It exceeds
name: "thirdfield",
msg: &testdata.Record{
Third: proto.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,
buf: []byte{141, 2, 26, 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,
@@ -69,36 +75,42 @@ I expect it may. Let's hope you enjoy testing as much as we do.`),
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)
}
t.Run(test.name, func(t *testing.T) {
var buf bytes.Buffer
// TODO: Split out error arm in next patch version.
if n, err := WriteDelimited(&buf, test.msg); !cmp.Equal(n, test.n) || !errors.Is(err, test.err) {
t.Errorf("WriteDelimited(buf, %#v) = %v, %v; want %v, %v", test.msg, n, err, test.n, test.err)
}
if out := buf.Bytes(); !cmp.Equal(out, test.buf) {
t.Errorf("WriteDelimited(buf, %#v); buf = %v; want %v", test.msg, out, test.buf)
}
})
}
}

func TestReadDelimited(t *testing.T) {
t.Parallel()
for _, test := range []struct {
buf []byte
msg proto.Message
n int
err error
name string
buf []byte
msg proto.Message
n int
err error
}{
{
buf: []byte{0},
msg: &Empty{},
n: 1,
name: "empty",
buf: []byte{0},
msg: new(testdata.Record),
n: 1,
},
{
n: 3,
buf: []byte{2, 8, 1},
msg: &GoEnum{Foo: FOO_FOO1.Enum()},
name: "firstfield",
n: 3,
buf: []byte{2, 8, 1},
msg: &testdata.Record{First: proto.Uint64(1)},
},
{
buf: []byte{141, 2, 10, 138, 2, 84, 104, 105, 115, 32, 105, 115, 32, 109,
name: "thirdfield",
buf: []byte{141, 2, 26, 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,
@@ -116,63 +128,84 @@ func TestReadDelimited(t *testing.T) {
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: proto.String(`This is my gigantic, unhappy string. It exceeds
msg: &testdata.Record{
Third: proto.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 := proto.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 !proto.Equal(msg, test.msg) {
t.Fatalf("ReadDelimited(%v, msg); msg = %v; want %v", test.buf, msg, test.msg)
}
t.Run(test.name, func(t *testing.T) {
msg := proto.Clone(test.msg)
proto.Reset(msg)
// TODO: Split out error arm in next patch version.
if n, err := ReadDelimited(bytes.NewBuffer(test.buf), msg); !cmp.Equal(n, test.n) || !errors.Is(err, test.err) {
t.Errorf("ReadDelimited(%v, msg) = %v, %v; want %v, %v", test.buf, n, err, test.n, test.err)
}
if !cmp.Equal(msg, test.msg, protocmp.Transform()) {
t.Errorf("ReadDelimited(%v, msg); msg = %v; want %v", test.buf, msg, test.msg)
}
})
}
}

func TestEndToEndValid(t *testing.T) {
t.Parallel()
for _, test := range [][]proto.Message{
{&Empty{}},
{&GoEnum{Foo: FOO_FOO1.Enum()}, &Empty{}, &GoEnum{Foo: FOO_FOO1.Enum()}},
{&GoEnum{Foo: FOO_FOO1.Enum()}},
{&Strings{
StringField: proto.String(`This is my gigantic, unhappy string. It exceeds
for _, test := range []struct {
name string
data []proto.Message
}{
{
name: "empty",
data: []proto.Message{new(testdata.Record)},
},
{
name: "simpleseq",
data: []proto.Message{&testdata.Record{First: proto.Uint64(1)}, new(testdata.Record), &testdata.Record{First: proto.Uint64(1)}},
},
{
name: "singleton",
data: []proto.Message{&testdata.Record{First: proto.Uint64(1)}},
},
{
name: "headerlength",
data: []proto.Message{&testdata.Record{
Third: proto.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)
t.Run(test.name, func(t *testing.T) {
var buf bytes.Buffer
var written int
for i, msg := range test.data {
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.data, i, err)
}
written += n
}
var read int
for i, msg := range test.data {
out := proto.Clone(msg)
proto.Reset(out)
n, err := ReadDelimited(&buf, out)
read += n
if !cmp.Equal(out, msg, protocmp.Transform()) {
t.Errorf("out = %v; want %v[%d] = %#v", out, test, i, msg)
}
if got, want := err, error(nil); !errors.Is(got, want) {
t.Errorf("err = %v, want %v", got, want)
}
}
written += n
}
var read int
for i, msg := range test {
out := proto.Clone(msg)
out.Reset()
n, _ := ReadDelimited(&buf, out)
// Decide to do EOF checking?
read += n
if !proto.Equal(out, msg) {
t.Fatalf("out = %v; want %v[%d] = %#v", out, test, i, msg)
if read != written {
t.Errorf("%v read = %d; want %d", test, read, written)
}
}
if read != written {
t.Fatalf("%v read = %d; want %d", test, read, written)
}
})
}
}
Loading