| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240 |
- package textpb_test
- import (
- "testing"
- protoV1 "github.com/golang/protobuf/proto"
- "github.com/golang/protobuf/v2/encoding/textpb"
- "github.com/golang/protobuf/v2/internal/impl"
- "github.com/golang/protobuf/v2/internal/scalar"
- "github.com/golang/protobuf/v2/proto"
- preg "github.com/golang/protobuf/v2/reflect/protoregistry"
- "github.com/golang/protobuf/v2/encoding/testprotos/pb2"
- knownpb "github.com/golang/protobuf/v2/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().Type().FullName()),
- Value: b,
- },
- }
- }(),
- }, {
- desc: "Any field with registered type",
- resolver: preg.NewTypes((&pb2.Nested{}).ProtoReflect().Type()),
- 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().Type().FullName()),
- Value: b,
- },
- }
- }(),
- }, {
- desc: "Any field containing Any message",
- resolver: func() *preg.Types {
- mt1 := (&pb2.Nested{}).ProtoReflect().Type()
- mt2 := impl.Export{}.MessageTypeOf(&knownpb.Any{})
- return preg.NewTypes(mt1, mt2)
- }(),
- message: func() proto.Message {
- 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()
- mo := textpb.MarshalOptions{Resolver: tt.resolver}
- umo := textpb.UnmarshalOptions{Resolver: tt.resolver}
- b, err := mo.Marshal(tt.message)
- if err != nil {
- t.Errorf("Marshal() returned error: %v\n\n", err)
- }
- gotMessage := tt.message.ProtoReflect().Type().New().Interface()
- err = umo.Unmarshal(gotMessage, b)
- if err != nil {
- t.Errorf("Unmarshal() returned error: %v\n\n", err)
- }
- if !protoV1.Equal(gotMessage.(protoV1.Message), tt.message.(protoV1.Message)) {
- t.Errorf("Unmarshal()\n<got>\n%v\n<want>\n%v\n", gotMessage, tt.message)
- }
- })
- }
- }
|