protobuf-go/encoding/prototext/other_test.go
Joe Tsai cdb7773569 encoding: switch ordering of Unmarshal arguments
While it is general convention that the receiver being mutated
is the first argument, the standard library specifically goes against
this convention when it comes to the Unmarshal function.

Switch the ordering of the Unmarshal function to match the Go stdlib.

Change-Id: I893346680233ef9fec7104415a54a0a7ae353378
Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/177258
Reviewed-by: Damien Neil <dneil@google.com>
2019-05-14 23:18:07 +00:00

240 lines
6.2 KiB
Go

package prototext_test
import (
"testing"
protoV1 "github.com/golang/protobuf/proto"
"google.golang.org/protobuf/encoding/prototext"
"google.golang.org/protobuf/internal/impl"
pimpl "google.golang.org/protobuf/internal/impl"
"google.golang.org/protobuf/internal/scalar"
"google.golang.org/protobuf/proto"
preg "google.golang.org/protobuf/reflect/protoregistry"
"google.golang.org/protobuf/encoding/testprotos/pb2"
knownpb "google.golang.org/protobuf/types/known"
)
func TestRoundTrip(t *testing.T) {
tests := []struct {
desc string
resolver *preg.Types
message proto.Message
}{{
desc: "well-known type fields set to empty messages",
message: &pb2.KnownTypes{
OptBool: &knownpb.BoolValue{},
OptInt32: &knownpb.Int32Value{},
OptInt64: &knownpb.Int64Value{},
OptUint32: &knownpb.UInt32Value{},
OptUint64: &knownpb.UInt64Value{},
OptFloat: &knownpb.FloatValue{},
OptDouble: &knownpb.DoubleValue{},
OptString: &knownpb.StringValue{},
OptBytes: &knownpb.BytesValue{},
OptDuration: &knownpb.Duration{},
OptTimestamp: &knownpb.Timestamp{},
OptStruct: &knownpb.Struct{},
OptList: &knownpb.ListValue{},
OptValue: &knownpb.Value{},
OptEmpty: &knownpb.Empty{},
OptAny: &knownpb.Any{},
},
}, {
desc: "well-known type scalar fields",
message: &pb2.KnownTypes{
OptBool: &knownpb.BoolValue{
Value: true,
},
OptInt32: &knownpb.Int32Value{
Value: -42,
},
OptInt64: &knownpb.Int64Value{
Value: -42,
},
OptUint32: &knownpb.UInt32Value{
Value: 0xff,
},
OptUint64: &knownpb.UInt64Value{
Value: 0xffff,
},
OptFloat: &knownpb.FloatValue{
Value: 1.234,
},
OptDouble: &knownpb.DoubleValue{
Value: 1.23e308,
},
OptString: &knownpb.StringValue{
Value: "谷歌",
},
OptBytes: &knownpb.BytesValue{
Value: []byte("\xe8\xb0\xb7\xe6\xad\x8c"),
},
},
}, {
desc: "well-known type time-related fields",
message: &pb2.KnownTypes{
OptDuration: &knownpb.Duration{
Seconds: -3600,
Nanos: -123,
},
OptTimestamp: &knownpb.Timestamp{
Seconds: 1257894000,
Nanos: 123,
},
},
}, {
desc: "Struct field and different Value types",
message: &pb2.KnownTypes{
OptStruct: &knownpb.Struct{
Fields: map[string]*knownpb.Value{
"bool": &knownpb.Value{
Kind: &knownpb.Value_BoolValue{
BoolValue: true,
},
},
"double": &knownpb.Value{
Kind: &knownpb.Value_NumberValue{
NumberValue: 3.1415,
},
},
"null": &knownpb.Value{
Kind: &knownpb.Value_NullValue{
NullValue: knownpb.NullValue_NULL_VALUE,
},
},
"string": &knownpb.Value{
Kind: &knownpb.Value_StringValue{
StringValue: "string",
},
},
"struct": &knownpb.Value{
Kind: &knownpb.Value_StructValue{
StructValue: &knownpb.Struct{
Fields: map[string]*knownpb.Value{
"bool": &knownpb.Value{
Kind: &knownpb.Value_BoolValue{
BoolValue: false,
},
},
},
},
},
},
"list": &knownpb.Value{
Kind: &knownpb.Value_ListValue{
ListValue: &knownpb.ListValue{
Values: []*knownpb.Value{
{
Kind: &knownpb.Value_BoolValue{
BoolValue: false,
},
},
{
Kind: &knownpb.Value_StringValue{
StringValue: "hello",
},
},
},
},
},
},
},
},
},
}, {
desc: "Any field without registered type",
resolver: preg.NewTypes(),
message: func() proto.Message {
m := &pb2.Nested{
OptString: scalar.String("embedded inside Any"),
OptNested: &pb2.Nested{
OptString: scalar.String("inception"),
},
}
b, err := proto.MarshalOptions{Deterministic: true}.Marshal(m)
if err != nil {
t.Fatalf("error in binary marshaling message for Any.value: %v", err)
}
return &pb2.KnownTypes{
OptAny: &knownpb.Any{
TypeUrl: string(m.ProtoReflect().Descriptor().FullName()),
Value: b,
},
}
}(),
}, {
desc: "Any field with registered type",
resolver: preg.NewTypes(pimpl.Export{}.MessageTypeOf(&pb2.Nested{})),
message: func() *pb2.KnownTypes {
m := &pb2.Nested{
OptString: scalar.String("embedded inside Any"),
OptNested: &pb2.Nested{
OptString: scalar.String("inception"),
},
}
b, err := proto.MarshalOptions{Deterministic: true}.Marshal(m)
if err != nil {
t.Fatalf("error in binary marshaling message for Any.value: %v", err)
}
return &pb2.KnownTypes{
OptAny: &knownpb.Any{
TypeUrl: string(m.ProtoReflect().Descriptor().FullName()),
Value: b,
},
}
}(),
}, {
desc: "Any field containing Any message",
resolver: func() *preg.Types {
mt1 := impl.Export{}.MessageTypeOf(&pb2.Nested{})
mt2 := impl.Export{}.MessageTypeOf(&knownpb.Any{})
return preg.NewTypes(mt1, mt2)
}(),
message: func() *pb2.KnownTypes {
m1 := &pb2.Nested{
OptString: scalar.String("message inside Any of another Any field"),
}
b1, err := proto.MarshalOptions{Deterministic: true}.Marshal(m1)
if err != nil {
t.Fatalf("error in binary marshaling message for Any.value: %v", err)
}
m2 := &knownpb.Any{
TypeUrl: "pb2.Nested",
Value: b1,
}
b2, err := proto.MarshalOptions{Deterministic: true}.Marshal(m2)
if err != nil {
t.Fatalf("error in binary marshaling message for Any.value: %v", err)
}
return &pb2.KnownTypes{
OptAny: &knownpb.Any{
TypeUrl: "google.protobuf.Any",
Value: b2,
},
}
}(),
}}
for _, tt := range tests {
tt := tt
t.Run(tt.desc, func(t *testing.T) {
t.Parallel()
b, err := prototext.MarshalOptions{Resolver: tt.resolver}.Marshal(tt.message)
if err != nil {
t.Errorf("Marshal() returned error: %v\n\n", err)
}
gotMessage := new(pb2.KnownTypes)
err = prototext.UnmarshalOptions{Resolver: tt.resolver}.Unmarshal(b, gotMessage)
if err != nil {
t.Errorf("Unmarshal() returned error: %v\n\n", err)
}
if !protoV1.Equal(gotMessage, tt.message.(protoV1.Message)) {
t.Errorf("Unmarshal()\n<got>\n%v\n<want>\n%v\n", gotMessage, tt.message)
}
})
}
}