encoding/textpb: initial textproto unmarshaling
This initial textproto unmarshaling implementation covers messages
without the use of extensions, Any expansion, nor weak.
Updated encoding tests. Split some testcases to keep each simpler.
Added TestRoundTrip for example messages like the well-known types.
Change-Id: Icffab02834aa004fa8409a9da70624f687f604fb
Reviewed-on: https://go-review.googlesource.com/c/153020
Reviewed-by: Joe Tsai <thebrokentoaster@gmail.com>
diff --git a/encoding/textpb/other_test.go b/encoding/textpb/other_test.go
new file mode 100644
index 0000000..4dc79cb
--- /dev/null
+++ b/encoding/textpb/other_test.go
@@ -0,0 +1,166 @@
+package textpb_test
+
+import (
+ "testing"
+
+ protoV1 "github.com/golang/protobuf/proto"
+ "github.com/golang/protobuf/v2/encoding/textpb"
+ "github.com/golang/protobuf/v2/encoding/textpb/testprotos/pb2"
+
+ // The legacy package must be imported prior to use of any legacy messages.
+ // TODO: Remove this when protoV1 registers these hooks for you.
+ _ "github.com/golang/protobuf/v2/internal/legacy"
+
+ anypb "github.com/golang/protobuf/ptypes/any"
+ durpb "github.com/golang/protobuf/ptypes/duration"
+ emptypb "github.com/golang/protobuf/ptypes/empty"
+ stpb "github.com/golang/protobuf/ptypes/struct"
+ tspb "github.com/golang/protobuf/ptypes/timestamp"
+ wpb "github.com/golang/protobuf/ptypes/wrappers"
+)
+
+func TestRoundTrip(t *testing.T) {
+ tests := []struct {
+ desc string
+ message protoV1.Message
+ }{{
+ desc: "well-known type fields set to empty messages",
+ message: &pb2.KnownTypes{
+ OptBool: &wpb.BoolValue{},
+ OptInt32: &wpb.Int32Value{},
+ OptInt64: &wpb.Int64Value{},
+ OptUint32: &wpb.UInt32Value{},
+ OptUint64: &wpb.UInt64Value{},
+ OptFloat: &wpb.FloatValue{},
+ OptDouble: &wpb.DoubleValue{},
+ OptString: &wpb.StringValue{},
+ OptBytes: &wpb.BytesValue{},
+ OptDuration: &durpb.Duration{},
+ OptTimestamp: &tspb.Timestamp{},
+ OptStruct: &stpb.Struct{},
+ OptList: &stpb.ListValue{},
+ OptValue: &stpb.Value{},
+ OptEmpty: &emptypb.Empty{},
+ OptAny: &anypb.Any{},
+ },
+ }, {
+ desc: "well-known type scalar fields",
+ message: &pb2.KnownTypes{
+ OptBool: &wpb.BoolValue{
+ Value: true,
+ },
+ OptInt32: &wpb.Int32Value{
+ Value: -42,
+ },
+ OptInt64: &wpb.Int64Value{
+ Value: -42,
+ },
+ OptUint32: &wpb.UInt32Value{
+ Value: 0xff,
+ },
+ OptUint64: &wpb.UInt64Value{
+ Value: 0xffff,
+ },
+ OptFloat: &wpb.FloatValue{
+ Value: 1.234,
+ },
+ OptDouble: &wpb.DoubleValue{
+ Value: 1.23e308,
+ },
+ OptString: &wpb.StringValue{
+ Value: "谷歌",
+ },
+ OptBytes: &wpb.BytesValue{
+ Value: []byte("\xe8\xb0\xb7\xe6\xad\x8c"),
+ },
+ },
+ }, {
+ desc: "well-known type time-related fields",
+ message: &pb2.KnownTypes{
+ OptDuration: &durpb.Duration{
+ Seconds: -3600,
+ Nanos: -123,
+ },
+ OptTimestamp: &tspb.Timestamp{
+ Seconds: 1257894000,
+ Nanos: 123,
+ },
+ },
+ }, {
+ desc: "well-known type struct field and different Value types",
+ message: &pb2.KnownTypes{
+ OptStruct: &stpb.Struct{
+ Fields: map[string]*stpb.Value{
+ "bool": &stpb.Value{
+ Kind: &stpb.Value_BoolValue{
+ BoolValue: true,
+ },
+ },
+ "double": &stpb.Value{
+ Kind: &stpb.Value_NumberValue{
+ NumberValue: 3.1415,
+ },
+ },
+ "null": &stpb.Value{
+ Kind: &stpb.Value_NullValue{
+ NullValue: stpb.NullValue_NULL_VALUE,
+ },
+ },
+ "string": &stpb.Value{
+ Kind: &stpb.Value_StringValue{
+ StringValue: "string",
+ },
+ },
+ "struct": &stpb.Value{
+ Kind: &stpb.Value_StructValue{
+ StructValue: &stpb.Struct{
+ Fields: map[string]*stpb.Value{
+ "bool": &stpb.Value{
+ Kind: &stpb.Value_BoolValue{
+ BoolValue: false,
+ },
+ },
+ },
+ },
+ },
+ },
+ "list": &stpb.Value{
+ Kind: &stpb.Value_ListValue{
+ ListValue: &stpb.ListValue{
+ Values: []*stpb.Value{
+ {
+ Kind: &stpb.Value_BoolValue{
+ BoolValue: false,
+ },
+ },
+ {
+ Kind: &stpb.Value_StringValue{
+ StringValue: "hello",
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ }}
+
+ for _, tt := range tests {
+ tt := tt
+ t.Run(tt.desc, func(t *testing.T) {
+ t.Parallel()
+ b, err := textpb.Marshal(M(tt.message))
+ if err != nil {
+ t.Errorf("Marshal() returned error: %v\n\n", err)
+ }
+ want := protoV1.Clone(tt.message)
+ want.Reset()
+ err = textpb.Unmarshal(M(want), b)
+ if err != nil {
+ t.Errorf("Unmarshal() returned error: %v\n\n", err)
+ }
+ })
+ }
+}