1*1c12ee1eSDan Willemsen// Copyright 2019 The Go Authors. All rights reserved. 2*1c12ee1eSDan Willemsen// Use of this source code is governed by a BSD-style 3*1c12ee1eSDan Willemsen// license that can be found in the LICENSE file. 4*1c12ee1eSDan Willemsen 5*1c12ee1eSDan Willemsenpackage prototext_test 6*1c12ee1eSDan Willemsen 7*1c12ee1eSDan Willemsenimport ( 8*1c12ee1eSDan Willemsen "testing" 9*1c12ee1eSDan Willemsen 10*1c12ee1eSDan Willemsen "google.golang.org/protobuf/encoding/prototext" 11*1c12ee1eSDan Willemsen "google.golang.org/protobuf/proto" 12*1c12ee1eSDan Willemsen "google.golang.org/protobuf/reflect/protoregistry" 13*1c12ee1eSDan Willemsen 14*1c12ee1eSDan Willemsen pb2 "google.golang.org/protobuf/internal/testprotos/textpb2" 15*1c12ee1eSDan Willemsen "google.golang.org/protobuf/types/known/anypb" 16*1c12ee1eSDan Willemsen "google.golang.org/protobuf/types/known/durationpb" 17*1c12ee1eSDan Willemsen "google.golang.org/protobuf/types/known/emptypb" 18*1c12ee1eSDan Willemsen "google.golang.org/protobuf/types/known/structpb" 19*1c12ee1eSDan Willemsen "google.golang.org/protobuf/types/known/timestamppb" 20*1c12ee1eSDan Willemsen "google.golang.org/protobuf/types/known/wrapperspb" 21*1c12ee1eSDan Willemsen) 22*1c12ee1eSDan Willemsen 23*1c12ee1eSDan Willemsenfunc TestRoundTrip(t *testing.T) { 24*1c12ee1eSDan Willemsen tests := []struct { 25*1c12ee1eSDan Willemsen desc string 26*1c12ee1eSDan Willemsen resolver *protoregistry.Types 27*1c12ee1eSDan Willemsen message proto.Message 28*1c12ee1eSDan Willemsen }{{ 29*1c12ee1eSDan Willemsen desc: "well-known type fields set to empty messages", 30*1c12ee1eSDan Willemsen message: &pb2.KnownTypes{ 31*1c12ee1eSDan Willemsen OptBool: &wrapperspb.BoolValue{}, 32*1c12ee1eSDan Willemsen OptInt32: &wrapperspb.Int32Value{}, 33*1c12ee1eSDan Willemsen OptInt64: &wrapperspb.Int64Value{}, 34*1c12ee1eSDan Willemsen OptUint32: &wrapperspb.UInt32Value{}, 35*1c12ee1eSDan Willemsen OptUint64: &wrapperspb.UInt64Value{}, 36*1c12ee1eSDan Willemsen OptFloat: &wrapperspb.FloatValue{}, 37*1c12ee1eSDan Willemsen OptDouble: &wrapperspb.DoubleValue{}, 38*1c12ee1eSDan Willemsen OptString: &wrapperspb.StringValue{}, 39*1c12ee1eSDan Willemsen OptBytes: &wrapperspb.BytesValue{}, 40*1c12ee1eSDan Willemsen OptDuration: &durationpb.Duration{}, 41*1c12ee1eSDan Willemsen OptTimestamp: ×tamppb.Timestamp{}, 42*1c12ee1eSDan Willemsen OptStruct: &structpb.Struct{}, 43*1c12ee1eSDan Willemsen OptList: &structpb.ListValue{}, 44*1c12ee1eSDan Willemsen OptValue: &structpb.Value{}, 45*1c12ee1eSDan Willemsen OptEmpty: &emptypb.Empty{}, 46*1c12ee1eSDan Willemsen OptAny: &anypb.Any{}, 47*1c12ee1eSDan Willemsen }, 48*1c12ee1eSDan Willemsen }, { 49*1c12ee1eSDan Willemsen desc: "well-known type scalar fields", 50*1c12ee1eSDan Willemsen message: &pb2.KnownTypes{ 51*1c12ee1eSDan Willemsen OptBool: &wrapperspb.BoolValue{ 52*1c12ee1eSDan Willemsen Value: true, 53*1c12ee1eSDan Willemsen }, 54*1c12ee1eSDan Willemsen OptInt32: &wrapperspb.Int32Value{ 55*1c12ee1eSDan Willemsen Value: -42, 56*1c12ee1eSDan Willemsen }, 57*1c12ee1eSDan Willemsen OptInt64: &wrapperspb.Int64Value{ 58*1c12ee1eSDan Willemsen Value: -42, 59*1c12ee1eSDan Willemsen }, 60*1c12ee1eSDan Willemsen OptUint32: &wrapperspb.UInt32Value{ 61*1c12ee1eSDan Willemsen Value: 0xff, 62*1c12ee1eSDan Willemsen }, 63*1c12ee1eSDan Willemsen OptUint64: &wrapperspb.UInt64Value{ 64*1c12ee1eSDan Willemsen Value: 0xffff, 65*1c12ee1eSDan Willemsen }, 66*1c12ee1eSDan Willemsen OptFloat: &wrapperspb.FloatValue{ 67*1c12ee1eSDan Willemsen Value: 1.234, 68*1c12ee1eSDan Willemsen }, 69*1c12ee1eSDan Willemsen OptDouble: &wrapperspb.DoubleValue{ 70*1c12ee1eSDan Willemsen Value: 1.23e308, 71*1c12ee1eSDan Willemsen }, 72*1c12ee1eSDan Willemsen OptString: &wrapperspb.StringValue{ 73*1c12ee1eSDan Willemsen Value: "谷歌", 74*1c12ee1eSDan Willemsen }, 75*1c12ee1eSDan Willemsen OptBytes: &wrapperspb.BytesValue{ 76*1c12ee1eSDan Willemsen Value: []byte("\xe8\xb0\xb7\xe6\xad\x8c"), 77*1c12ee1eSDan Willemsen }, 78*1c12ee1eSDan Willemsen }, 79*1c12ee1eSDan Willemsen }, { 80*1c12ee1eSDan Willemsen desc: "well-known type time-related fields", 81*1c12ee1eSDan Willemsen message: &pb2.KnownTypes{ 82*1c12ee1eSDan Willemsen OptDuration: &durationpb.Duration{ 83*1c12ee1eSDan Willemsen Seconds: -3600, 84*1c12ee1eSDan Willemsen Nanos: -123, 85*1c12ee1eSDan Willemsen }, 86*1c12ee1eSDan Willemsen OptTimestamp: ×tamppb.Timestamp{ 87*1c12ee1eSDan Willemsen Seconds: 1257894000, 88*1c12ee1eSDan Willemsen Nanos: 123, 89*1c12ee1eSDan Willemsen }, 90*1c12ee1eSDan Willemsen }, 91*1c12ee1eSDan Willemsen }, { 92*1c12ee1eSDan Willemsen desc: "Struct field and different Value types", 93*1c12ee1eSDan Willemsen message: &pb2.KnownTypes{ 94*1c12ee1eSDan Willemsen OptStruct: &structpb.Struct{ 95*1c12ee1eSDan Willemsen Fields: map[string]*structpb.Value{ 96*1c12ee1eSDan Willemsen "bool": &structpb.Value{ 97*1c12ee1eSDan Willemsen Kind: &structpb.Value_BoolValue{ 98*1c12ee1eSDan Willemsen BoolValue: true, 99*1c12ee1eSDan Willemsen }, 100*1c12ee1eSDan Willemsen }, 101*1c12ee1eSDan Willemsen "double": &structpb.Value{ 102*1c12ee1eSDan Willemsen Kind: &structpb.Value_NumberValue{ 103*1c12ee1eSDan Willemsen NumberValue: 3.1415, 104*1c12ee1eSDan Willemsen }, 105*1c12ee1eSDan Willemsen }, 106*1c12ee1eSDan Willemsen "null": &structpb.Value{ 107*1c12ee1eSDan Willemsen Kind: &structpb.Value_NullValue{ 108*1c12ee1eSDan Willemsen NullValue: structpb.NullValue_NULL_VALUE, 109*1c12ee1eSDan Willemsen }, 110*1c12ee1eSDan Willemsen }, 111*1c12ee1eSDan Willemsen "string": &structpb.Value{ 112*1c12ee1eSDan Willemsen Kind: &structpb.Value_StringValue{ 113*1c12ee1eSDan Willemsen StringValue: "string", 114*1c12ee1eSDan Willemsen }, 115*1c12ee1eSDan Willemsen }, 116*1c12ee1eSDan Willemsen "struct": &structpb.Value{ 117*1c12ee1eSDan Willemsen Kind: &structpb.Value_StructValue{ 118*1c12ee1eSDan Willemsen StructValue: &structpb.Struct{ 119*1c12ee1eSDan Willemsen Fields: map[string]*structpb.Value{ 120*1c12ee1eSDan Willemsen "bool": &structpb.Value{ 121*1c12ee1eSDan Willemsen Kind: &structpb.Value_BoolValue{ 122*1c12ee1eSDan Willemsen BoolValue: false, 123*1c12ee1eSDan Willemsen }, 124*1c12ee1eSDan Willemsen }, 125*1c12ee1eSDan Willemsen }, 126*1c12ee1eSDan Willemsen }, 127*1c12ee1eSDan Willemsen }, 128*1c12ee1eSDan Willemsen }, 129*1c12ee1eSDan Willemsen "list": &structpb.Value{ 130*1c12ee1eSDan Willemsen Kind: &structpb.Value_ListValue{ 131*1c12ee1eSDan Willemsen ListValue: &structpb.ListValue{ 132*1c12ee1eSDan Willemsen Values: []*structpb.Value{ 133*1c12ee1eSDan Willemsen { 134*1c12ee1eSDan Willemsen Kind: &structpb.Value_BoolValue{ 135*1c12ee1eSDan Willemsen BoolValue: false, 136*1c12ee1eSDan Willemsen }, 137*1c12ee1eSDan Willemsen }, 138*1c12ee1eSDan Willemsen { 139*1c12ee1eSDan Willemsen Kind: &structpb.Value_StringValue{ 140*1c12ee1eSDan Willemsen StringValue: "hello", 141*1c12ee1eSDan Willemsen }, 142*1c12ee1eSDan Willemsen }, 143*1c12ee1eSDan Willemsen }, 144*1c12ee1eSDan Willemsen }, 145*1c12ee1eSDan Willemsen }, 146*1c12ee1eSDan Willemsen }, 147*1c12ee1eSDan Willemsen }, 148*1c12ee1eSDan Willemsen }, 149*1c12ee1eSDan Willemsen }, 150*1c12ee1eSDan Willemsen }, { 151*1c12ee1eSDan Willemsen desc: "Any field without registered type", 152*1c12ee1eSDan Willemsen resolver: new(protoregistry.Types), 153*1c12ee1eSDan Willemsen message: func() proto.Message { 154*1c12ee1eSDan Willemsen m := &pb2.Nested{ 155*1c12ee1eSDan Willemsen OptString: proto.String("embedded inside Any"), 156*1c12ee1eSDan Willemsen OptNested: &pb2.Nested{ 157*1c12ee1eSDan Willemsen OptString: proto.String("inception"), 158*1c12ee1eSDan Willemsen }, 159*1c12ee1eSDan Willemsen } 160*1c12ee1eSDan Willemsen b, err := proto.MarshalOptions{Deterministic: true}.Marshal(m) 161*1c12ee1eSDan Willemsen if err != nil { 162*1c12ee1eSDan Willemsen t.Fatalf("error in binary marshaling message for Any.value: %v", err) 163*1c12ee1eSDan Willemsen } 164*1c12ee1eSDan Willemsen return &pb2.KnownTypes{ 165*1c12ee1eSDan Willemsen OptAny: &anypb.Any{ 166*1c12ee1eSDan Willemsen TypeUrl: string(m.ProtoReflect().Descriptor().FullName()), 167*1c12ee1eSDan Willemsen Value: b, 168*1c12ee1eSDan Willemsen }, 169*1c12ee1eSDan Willemsen } 170*1c12ee1eSDan Willemsen }(), 171*1c12ee1eSDan Willemsen }, { 172*1c12ee1eSDan Willemsen desc: "Any field with registered type", 173*1c12ee1eSDan Willemsen message: func() *pb2.KnownTypes { 174*1c12ee1eSDan Willemsen m := &pb2.Nested{ 175*1c12ee1eSDan Willemsen OptString: proto.String("embedded inside Any"), 176*1c12ee1eSDan Willemsen OptNested: &pb2.Nested{ 177*1c12ee1eSDan Willemsen OptString: proto.String("inception"), 178*1c12ee1eSDan Willemsen }, 179*1c12ee1eSDan Willemsen } 180*1c12ee1eSDan Willemsen b, err := proto.MarshalOptions{Deterministic: true}.Marshal(m) 181*1c12ee1eSDan Willemsen if err != nil { 182*1c12ee1eSDan Willemsen t.Fatalf("error in binary marshaling message for Any.value: %v", err) 183*1c12ee1eSDan Willemsen } 184*1c12ee1eSDan Willemsen return &pb2.KnownTypes{ 185*1c12ee1eSDan Willemsen OptAny: &anypb.Any{ 186*1c12ee1eSDan Willemsen TypeUrl: string(m.ProtoReflect().Descriptor().FullName()), 187*1c12ee1eSDan Willemsen Value: b, 188*1c12ee1eSDan Willemsen }, 189*1c12ee1eSDan Willemsen } 190*1c12ee1eSDan Willemsen }(), 191*1c12ee1eSDan Willemsen }, { 192*1c12ee1eSDan Willemsen desc: "Any field containing Any message", 193*1c12ee1eSDan Willemsen message: func() *pb2.KnownTypes { 194*1c12ee1eSDan Willemsen m1 := &pb2.Nested{ 195*1c12ee1eSDan Willemsen OptString: proto.String("message inside Any of another Any field"), 196*1c12ee1eSDan Willemsen } 197*1c12ee1eSDan Willemsen b1, err := proto.MarshalOptions{Deterministic: true}.Marshal(m1) 198*1c12ee1eSDan Willemsen if err != nil { 199*1c12ee1eSDan Willemsen t.Fatalf("error in binary marshaling message for Any.value: %v", err) 200*1c12ee1eSDan Willemsen } 201*1c12ee1eSDan Willemsen m2 := &anypb.Any{ 202*1c12ee1eSDan Willemsen TypeUrl: "pb2.Nested", 203*1c12ee1eSDan Willemsen Value: b1, 204*1c12ee1eSDan Willemsen } 205*1c12ee1eSDan Willemsen b2, err := proto.MarshalOptions{Deterministic: true}.Marshal(m2) 206*1c12ee1eSDan Willemsen if err != nil { 207*1c12ee1eSDan Willemsen t.Fatalf("error in binary marshaling message for Any.value: %v", err) 208*1c12ee1eSDan Willemsen } 209*1c12ee1eSDan Willemsen return &pb2.KnownTypes{ 210*1c12ee1eSDan Willemsen OptAny: &anypb.Any{ 211*1c12ee1eSDan Willemsen TypeUrl: "google.protobuf.Any", 212*1c12ee1eSDan Willemsen Value: b2, 213*1c12ee1eSDan Willemsen }, 214*1c12ee1eSDan Willemsen } 215*1c12ee1eSDan Willemsen }(), 216*1c12ee1eSDan Willemsen }} 217*1c12ee1eSDan Willemsen 218*1c12ee1eSDan Willemsen for _, tt := range tests { 219*1c12ee1eSDan Willemsen tt := tt 220*1c12ee1eSDan Willemsen t.Run(tt.desc, func(t *testing.T) { 221*1c12ee1eSDan Willemsen t.Parallel() 222*1c12ee1eSDan Willemsen b, err := prototext.MarshalOptions{Resolver: tt.resolver}.Marshal(tt.message) 223*1c12ee1eSDan Willemsen if err != nil { 224*1c12ee1eSDan Willemsen t.Errorf("Marshal() returned error: %v\n\n", err) 225*1c12ee1eSDan Willemsen } 226*1c12ee1eSDan Willemsen 227*1c12ee1eSDan Willemsen gotMessage := new(pb2.KnownTypes) 228*1c12ee1eSDan Willemsen err = prototext.UnmarshalOptions{Resolver: tt.resolver}.Unmarshal(b, gotMessage) 229*1c12ee1eSDan Willemsen if err != nil { 230*1c12ee1eSDan Willemsen t.Errorf("Unmarshal() returned error: %v\n\n", err) 231*1c12ee1eSDan Willemsen } 232*1c12ee1eSDan Willemsen 233*1c12ee1eSDan Willemsen if !proto.Equal(gotMessage, tt.message) { 234*1c12ee1eSDan Willemsen t.Errorf("Unmarshal()\n<got>\n%v\n<want>\n%v\n", gotMessage, tt.message) 235*1c12ee1eSDan Willemsen } 236*1c12ee1eSDan Willemsen }) 237*1c12ee1eSDan Willemsen } 238*1c12ee1eSDan Willemsen} 239