blob: 80babd2ebef2755eb22970327561b3df862d3257 [file] [log] [blame]
Herbie Ong800c9902018-12-06 15:28:53 -08001package textpb_test
2
3import (
4 "testing"
5
6 protoV1 "github.com/golang/protobuf/proto"
7 "github.com/golang/protobuf/v2/encoding/textpb"
Herbie Ong8170d692019-02-13 14:13:21 -08008 "github.com/golang/protobuf/v2/internal/impl"
9 "github.com/golang/protobuf/v2/internal/scalar"
Herbie Ong70651952018-12-13 14:19:50 -080010 "github.com/golang/protobuf/v2/proto"
Herbie Ong66c365c2019-01-04 14:08:41 -080011 preg "github.com/golang/protobuf/v2/reflect/protoregistry"
Herbie Ong800c9902018-12-06 15:28:53 -080012
13 // The legacy package must be imported prior to use of any legacy messages.
14 // TODO: Remove this when protoV1 registers these hooks for you.
15 _ "github.com/golang/protobuf/v2/internal/legacy"
16
17 anypb "github.com/golang/protobuf/ptypes/any"
18 durpb "github.com/golang/protobuf/ptypes/duration"
19 emptypb "github.com/golang/protobuf/ptypes/empty"
20 stpb "github.com/golang/protobuf/ptypes/struct"
21 tspb "github.com/golang/protobuf/ptypes/timestamp"
22 wpb "github.com/golang/protobuf/ptypes/wrappers"
Herbie Ong8170d692019-02-13 14:13:21 -080023 "github.com/golang/protobuf/v2/encoding/testprotos/pb2"
Herbie Ong800c9902018-12-06 15:28:53 -080024)
25
26func TestRoundTrip(t *testing.T) {
27 tests := []struct {
Herbie Ong66c365c2019-01-04 14:08:41 -080028 desc string
29 resolver *preg.Types
30 message proto.Message
Herbie Ong800c9902018-12-06 15:28:53 -080031 }{{
32 desc: "well-known type fields set to empty messages",
33 message: &pb2.KnownTypes{
34 OptBool: &wpb.BoolValue{},
35 OptInt32: &wpb.Int32Value{},
36 OptInt64: &wpb.Int64Value{},
37 OptUint32: &wpb.UInt32Value{},
38 OptUint64: &wpb.UInt64Value{},
39 OptFloat: &wpb.FloatValue{},
40 OptDouble: &wpb.DoubleValue{},
41 OptString: &wpb.StringValue{},
42 OptBytes: &wpb.BytesValue{},
43 OptDuration: &durpb.Duration{},
44 OptTimestamp: &tspb.Timestamp{},
45 OptStruct: &stpb.Struct{},
46 OptList: &stpb.ListValue{},
47 OptValue: &stpb.Value{},
48 OptEmpty: &emptypb.Empty{},
49 OptAny: &anypb.Any{},
50 },
51 }, {
52 desc: "well-known type scalar fields",
53 message: &pb2.KnownTypes{
54 OptBool: &wpb.BoolValue{
55 Value: true,
56 },
57 OptInt32: &wpb.Int32Value{
58 Value: -42,
59 },
60 OptInt64: &wpb.Int64Value{
61 Value: -42,
62 },
63 OptUint32: &wpb.UInt32Value{
64 Value: 0xff,
65 },
66 OptUint64: &wpb.UInt64Value{
67 Value: 0xffff,
68 },
69 OptFloat: &wpb.FloatValue{
70 Value: 1.234,
71 },
72 OptDouble: &wpb.DoubleValue{
73 Value: 1.23e308,
74 },
75 OptString: &wpb.StringValue{
76 Value: "谷歌",
77 },
78 OptBytes: &wpb.BytesValue{
79 Value: []byte("\xe8\xb0\xb7\xe6\xad\x8c"),
80 },
81 },
82 }, {
83 desc: "well-known type time-related fields",
84 message: &pb2.KnownTypes{
85 OptDuration: &durpb.Duration{
86 Seconds: -3600,
87 Nanos: -123,
88 },
89 OptTimestamp: &tspb.Timestamp{
90 Seconds: 1257894000,
91 Nanos: 123,
92 },
93 },
94 }, {
Herbie Ong66c365c2019-01-04 14:08:41 -080095 desc: "Struct field and different Value types",
Herbie Ong800c9902018-12-06 15:28:53 -080096 message: &pb2.KnownTypes{
97 OptStruct: &stpb.Struct{
98 Fields: map[string]*stpb.Value{
99 "bool": &stpb.Value{
100 Kind: &stpb.Value_BoolValue{
101 BoolValue: true,
102 },
103 },
104 "double": &stpb.Value{
105 Kind: &stpb.Value_NumberValue{
106 NumberValue: 3.1415,
107 },
108 },
109 "null": &stpb.Value{
110 Kind: &stpb.Value_NullValue{
111 NullValue: stpb.NullValue_NULL_VALUE,
112 },
113 },
114 "string": &stpb.Value{
115 Kind: &stpb.Value_StringValue{
116 StringValue: "string",
117 },
118 },
119 "struct": &stpb.Value{
120 Kind: &stpb.Value_StructValue{
121 StructValue: &stpb.Struct{
122 Fields: map[string]*stpb.Value{
123 "bool": &stpb.Value{
124 Kind: &stpb.Value_BoolValue{
125 BoolValue: false,
126 },
127 },
128 },
129 },
130 },
131 },
132 "list": &stpb.Value{
133 Kind: &stpb.Value_ListValue{
134 ListValue: &stpb.ListValue{
135 Values: []*stpb.Value{
136 {
137 Kind: &stpb.Value_BoolValue{
138 BoolValue: false,
139 },
140 },
141 {
142 Kind: &stpb.Value_StringValue{
143 StringValue: "hello",
144 },
145 },
146 },
147 },
148 },
149 },
150 },
151 },
152 },
Herbie Ong66c365c2019-01-04 14:08:41 -0800153 }, {
154 desc: "Any field without registered type",
155 resolver: preg.NewTypes(),
156 message: func() proto.Message {
157 m := &pb2.Nested{
158 OptString: scalar.String("embedded inside Any"),
159 OptNested: &pb2.Nested{
160 OptString: scalar.String("inception"),
161 },
162 }
163 // TODO: Switch to V2 marshal when ready.
164 b, err := protoV1.Marshal(m)
165 if err != nil {
166 t.Fatalf("error in binary marshaling message for Any.value: %v", err)
167 }
168 return &pb2.KnownTypes{
169 OptAny: &anypb.Any{
170 TypeUrl: string(m.ProtoReflect().Type().FullName()),
171 Value: b,
172 },
173 }
174 }(),
175 }, {
176 desc: "Any field with registered type",
177 resolver: preg.NewTypes((&pb2.Nested{}).ProtoReflect().Type()),
178 message: func() proto.Message {
179 m := &pb2.Nested{
180 OptString: scalar.String("embedded inside Any"),
181 OptNested: &pb2.Nested{
182 OptString: scalar.String("inception"),
183 },
184 }
185 // TODO: Switch to V2 marshal when ready.
186 b, err := protoV1.Marshal(m)
187 if err != nil {
188 t.Fatalf("error in binary marshaling message for Any.value: %v", err)
189 }
190 return &pb2.KnownTypes{
191 OptAny: &anypb.Any{
192 TypeUrl: string(m.ProtoReflect().Type().FullName()),
193 Value: b,
194 },
195 }
196 }(),
197 }, {
198 desc: "Any field containing Any message",
199 resolver: func() *preg.Types {
200 mt1 := (&pb2.Nested{}).ProtoReflect().Type()
201 mt2 := impl.Export{}.MessageTypeOf(&anypb.Any{})
202 return preg.NewTypes(mt1, mt2)
203 }(),
204 message: func() proto.Message {
205 m1 := &pb2.Nested{
206 OptString: scalar.String("message inside Any of another Any field"),
207 }
208 // TODO: Switch to V2 marshal when ready.
209 b1, err := protoV1.Marshal(m1)
210 if err != nil {
211 t.Fatalf("error in binary marshaling message for Any.value: %v", err)
212 }
213 m2 := &anypb.Any{
214 TypeUrl: "pb2.Nested",
215 Value: b1,
216 }
217 // TODO: Switch to V2 marshal when ready.
218 b2, err := protoV1.Marshal(m2)
219 if err != nil {
220 t.Fatalf("error in binary marshaling message for Any.value: %v", err)
221 }
222 return &pb2.KnownTypes{
223 OptAny: &anypb.Any{
224 TypeUrl: "google.protobuf.Any",
225 Value: b2,
226 },
227 }
228 }(),
Herbie Ong800c9902018-12-06 15:28:53 -0800229 }}
230
231 for _, tt := range tests {
232 tt := tt
233 t.Run(tt.desc, func(t *testing.T) {
234 t.Parallel()
Herbie Ong66c365c2019-01-04 14:08:41 -0800235 mo := textpb.MarshalOptions{Resolver: tt.resolver}
236 umo := textpb.UnmarshalOptions{Resolver: tt.resolver}
237
238 b, err := mo.Marshal(tt.message)
Herbie Ong800c9902018-12-06 15:28:53 -0800239 if err != nil {
240 t.Errorf("Marshal() returned error: %v\n\n", err)
241 }
Joe Tsai3bc7d6f2019-01-09 02:57:13 -0800242 gotMessage := tt.message.ProtoReflect().Type().New().Interface()
Herbie Ong66c365c2019-01-04 14:08:41 -0800243 err = umo.Unmarshal(gotMessage, b)
Herbie Ong800c9902018-12-06 15:28:53 -0800244 if err != nil {
245 t.Errorf("Unmarshal() returned error: %v\n\n", err)
246 }
Herbie Ong66c365c2019-01-04 14:08:41 -0800247
Herbie Ong70651952018-12-13 14:19:50 -0800248 if !protoV1.Equal(gotMessage.(protoV1.Message), tt.message.(protoV1.Message)) {
249 t.Errorf("Unmarshal()\n<got>\n%v\n<want>\n%v\n", gotMessage, tt.message)
250 }
Herbie Ong800c9902018-12-06 15:28:53 -0800251 })
252 }
253}