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" "github.com/golang/protobuf/v2/proto" // 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 proto.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(tt.message) if err != nil { t.Errorf("Marshal() returned error: %v\n\n", err) } gotMessage := tt.message.ProtoReflect().Type().New() err = textpb.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\n%v\n\n%v\n", gotMessage, tt.message) } }) } }