1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32 package jsonpb
33
34 import (
35 "bytes"
36 "encoding/json"
37 "io"
38 "math"
39 "reflect"
40 "strings"
41 "testing"
42
43 pb "github.com/gogo/protobuf/jsonpb/jsonpb_test_proto"
44 "github.com/gogo/protobuf/proto"
45 proto3pb "github.com/gogo/protobuf/proto/proto3_proto"
46 "github.com/gogo/protobuf/types"
47 )
48
49 var (
50 marshaler = Marshaler{}
51
52 marshalerAllOptions = Marshaler{
53 Indent: " ",
54 }
55
56 simpleObject = &pb.Simple{
57 OInt32: proto.Int32(-32),
58 OInt32Str: proto.Int32(-32),
59 OInt64: proto.Int64(-6400000000),
60 OInt64Str: proto.Int64(-6400000000),
61 OUint32: proto.Uint32(32),
62 OUint32Str: proto.Uint32(32),
63 OUint64: proto.Uint64(6400000000),
64 OUint64Str: proto.Uint64(6400000000),
65 OSint32: proto.Int32(-13),
66 OSint32Str: proto.Int32(-13),
67 OSint64: proto.Int64(-2600000000),
68 OSint64Str: proto.Int64(-2600000000),
69 OFloat: proto.Float32(3.14),
70 OFloatStr: proto.Float32(3.14),
71 ODouble: proto.Float64(6.02214179e23),
72 ODoubleStr: proto.Float64(6.02214179e23),
73 OBool: proto.Bool(true),
74 OString: proto.String("hello \"there\""),
75 OBytes: []byte("beep boop"),
76 OCastBytes: pb.Bytes("wow"),
77 }
78
79 simpleObjectInputJSON = `{` +
80 `"oBool":true,` +
81 `"oInt32":-32,` +
82 `"oInt32Str":"-32",` +
83 `"oInt64":-6400000000,` +
84 `"oInt64Str":"-6400000000",` +
85 `"oUint32":32,` +
86 `"oUint32Str":"32",` +
87 `"oUint64":6400000000,` +
88 `"oUint64Str":"6400000000",` +
89 `"oSint32":-13,` +
90 `"oSint32Str":"-13",` +
91 `"oSint64":-2600000000,` +
92 `"oSint64Str":"-2600000000",` +
93 `"oFloat":3.14,` +
94 `"oFloatStr":"3.14",` +
95 `"oDouble":6.02214179e+23,` +
96 `"oDoubleStr":"6.02214179e+23",` +
97 `"oString":"hello \"there\"",` +
98 `"oBytes":"YmVlcCBib29w",` +
99 `"oCastBytes":"d293"` +
100 `}`
101
102 simpleObjectOutputJSON = `{` +
103 `"oBool":true,` +
104 `"oInt32":-32,` +
105 `"oInt32Str":-32,` +
106 `"oInt64":"-6400000000",` +
107 `"oInt64Str":"-6400000000",` +
108 `"oUint32":32,` +
109 `"oUint32Str":32,` +
110 `"oUint64":"6400000000",` +
111 `"oUint64Str":"6400000000",` +
112 `"oSint32":-13,` +
113 `"oSint32Str":-13,` +
114 `"oSint64":"-2600000000",` +
115 `"oSint64Str":"-2600000000",` +
116 `"oFloat":3.14,` +
117 `"oFloatStr":3.14,` +
118 `"oDouble":6.02214179e+23,` +
119 `"oDoubleStr":6.02214179e+23,` +
120 `"oString":"hello \"there\"",` +
121 `"oBytes":"YmVlcCBib29w",` +
122 `"oCastBytes":"d293"` +
123 `}`
124
125 simpleObjectInputPrettyJSON = `{
126 "oBool": true,
127 "oInt32": -32,
128 "oInt32Str": "-32",
129 "oInt64": -6400000000,
130 "oInt64Str": "-6400000000",
131 "oUint32": 32,
132 "oUint32Str": "32",
133 "oUint64": 6400000000,
134 "oUint64Str": "6400000000",
135 "oSint32": -13,
136 "oSint32Str": "-13",
137 "oSint64": -2600000000,
138 "oSint64Str": "-2600000000",
139 "oFloat": 3.14,
140 "oFloatStr": "3.14",
141 "oDouble": 6.02214179e+23,
142 "oDoubleStr": "6.02214179e+23",
143 "oString": "hello \"there\"",
144 "oBytes": "YmVlcCBib29w",
145 "oCastBytes": "d293"
146 }`
147
148 simpleObjectOutputPrettyJSON = `{
149 "oBool": true,
150 "oInt32": -32,
151 "oInt32Str": -32,
152 "oInt64": "-6400000000",
153 "oInt64Str": "-6400000000",
154 "oUint32": 32,
155 "oUint32Str": 32,
156 "oUint64": "6400000000",
157 "oUint64Str": "6400000000",
158 "oSint32": -13,
159 "oSint32Str": -13,
160 "oSint64": "-2600000000",
161 "oSint64Str": "-2600000000",
162 "oFloat": 3.14,
163 "oFloatStr": 3.14,
164 "oDouble": 6.02214179e+23,
165 "oDoubleStr": 6.02214179e+23,
166 "oString": "hello \"there\"",
167 "oBytes": "YmVlcCBib29w",
168 "oCastBytes": "d293"
169 }`
170
171 repeatsObject = &pb.Repeats{
172 RBool: []bool{true, false, true},
173 RInt32: []int32{-3, -4, -5},
174 RInt64: []int64{-123456789, -987654321},
175 RUint32: []uint32{1, 2, 3},
176 RUint64: []uint64{6789012345, 3456789012},
177 RSint32: []int32{-1, -2, -3},
178 RSint64: []int64{-6789012345, -3456789012},
179 RFloat: []float32{3.14, 6.28},
180 RDouble: []float64{299792458 * 1e20, 6.62606957e-34},
181 RString: []string{"happy", "days"},
182 RBytes: [][]byte{[]byte("skittles"), []byte("m&m's")},
183 }
184
185 repeatsObjectJSON = `{` +
186 `"rBool":[true,false,true],` +
187 `"rInt32":[-3,-4,-5],` +
188 `"rInt64":["-123456789","-987654321"],` +
189 `"rUint32":[1,2,3],` +
190 `"rUint64":["6789012345","3456789012"],` +
191 `"rSint32":[-1,-2,-3],` +
192 `"rSint64":["-6789012345","-3456789012"],` +
193 `"rFloat":[3.14,6.28],` +
194 `"rDouble":[2.99792458e+28,6.62606957e-34],` +
195 `"rString":["happy","days"],` +
196 `"rBytes":["c2tpdHRsZXM=","bSZtJ3M="]` +
197 `}`
198
199 repeatsObjectPrettyJSON = `{
200 "rBool": [
201 true,
202 false,
203 true
204 ],
205 "rInt32": [
206 -3,
207 -4,
208 -5
209 ],
210 "rInt64": [
211 "-123456789",
212 "-987654321"
213 ],
214 "rUint32": [
215 1,
216 2,
217 3
218 ],
219 "rUint64": [
220 "6789012345",
221 "3456789012"
222 ],
223 "rSint32": [
224 -1,
225 -2,
226 -3
227 ],
228 "rSint64": [
229 "-6789012345",
230 "-3456789012"
231 ],
232 "rFloat": [
233 3.14,
234 6.28
235 ],
236 "rDouble": [
237 2.99792458e+28,
238 6.62606957e-34
239 ],
240 "rString": [
241 "happy",
242 "days"
243 ],
244 "rBytes": [
245 "c2tpdHRsZXM=",
246 "bSZtJ3M="
247 ]
248 }`
249
250 innerSimple = &pb.Simple{OInt32: proto.Int32(-32)}
251 innerSimple2 = &pb.Simple{OInt64: proto.Int64(25)}
252 innerRepeats = &pb.Repeats{RString: []string{"roses", "red"}}
253 innerRepeats2 = &pb.Repeats{RString: []string{"violets", "blue"}}
254 complexObject = &pb.Widget{
255 Color: pb.Widget_GREEN.Enum(),
256 RColor: []pb.Widget_Color{pb.Widget_RED, pb.Widget_GREEN, pb.Widget_BLUE},
257 Simple: innerSimple,
258 RSimple: []*pb.Simple{innerSimple, innerSimple2},
259 Repeats: innerRepeats,
260 RRepeats: []*pb.Repeats{innerRepeats, innerRepeats2},
261 }
262
263 complexObjectJSON = `{"color":"GREEN",` +
264 `"rColor":["RED","GREEN","BLUE"],` +
265 `"simple":{"oInt32":-32},` +
266 `"rSimple":[{"oInt32":-32},{"oInt64":"25"}],` +
267 `"repeats":{"rString":["roses","red"]},` +
268 `"rRepeats":[{"rString":["roses","red"]},{"rString":["violets","blue"]}]` +
269 `}`
270
271 complexObjectPrettyJSON = `{
272 "color": "GREEN",
273 "rColor": [
274 "RED",
275 "GREEN",
276 "BLUE"
277 ],
278 "simple": {
279 "oInt32": -32
280 },
281 "rSimple": [
282 {
283 "oInt32": -32
284 },
285 {
286 "oInt64": "25"
287 }
288 ],
289 "repeats": {
290 "rString": [
291 "roses",
292 "red"
293 ]
294 },
295 "rRepeats": [
296 {
297 "rString": [
298 "roses",
299 "red"
300 ]
301 },
302 {
303 "rString": [
304 "violets",
305 "blue"
306 ]
307 }
308 ]
309 }`
310
311 colorPrettyJSON = `{
312 "color": 2
313 }`
314
315 colorListPrettyJSON = `{
316 "color": 1000,
317 "rColor": [
318 "RED"
319 ]
320 }`
321
322 nummyPrettyJSON = `{
323 "nummy": {
324 "1": 2,
325 "3": 4
326 }
327 }`
328
329 objjyPrettyJSON = `{
330 "objjy": {
331 "1": {
332 "dub": 1
333 }
334 }
335 }`
336 realNumber = &pb.Real{Value: proto.Float64(3.14159265359)}
337 realNumberName = "Pi"
338 complexNumber = &pb.Complex{Imaginary: proto.Float64(0.5772156649)}
339 realNumberJSON = `{` +
340 `"value":3.14159265359,` +
341 `"[jsonpb.Complex.real_extension]":{"imaginary":0.5772156649},` +
342 `"[jsonpb.name]":"Pi"` +
343 `}`
344
345 anySimple = &pb.KnownTypes{
346 An: &types.Any{
347 TypeUrl: "something.example.com/jsonpb.Simple",
348 Value: []byte{
349
350 1 << 3, 1,
351 },
352 },
353 }
354 anySimpleJSON = `{"an":{"@type":"something.example.com/jsonpb.Simple","oBool":true}}`
355 anySimplePrettyJSON = `{
356 "an": {
357 "@type": "something.example.com/jsonpb.Simple",
358 "oBool": true
359 }
360 }`
361
362 anyWellKnown = &pb.KnownTypes{
363 An: &types.Any{
364 TypeUrl: "type.googleapis.com/google.protobuf.Duration",
365 Value: []byte{
366
367 1 << 3, 1,
368 2 << 3, 0x80, 0xba, 0x8b, 0x65,
369 },
370 },
371 }
372 anyWellKnownJSON = `{"an":{"@type":"type.googleapis.com/google.protobuf.Duration","value":"1.212s"}}`
373 anyWellKnownPrettyJSON = `{
374 "an": {
375 "@type": "type.googleapis.com/google.protobuf.Duration",
376 "value": "1.212s"
377 }
378 }`
379
380 nonFinites = &pb.NonFinites{
381 FNan: proto.Float32(float32(math.NaN())),
382 FPinf: proto.Float32(float32(math.Inf(1))),
383 FNinf: proto.Float32(float32(math.Inf(-1))),
384 DNan: proto.Float64(float64(math.NaN())),
385 DPinf: proto.Float64(float64(math.Inf(1))),
386 DNinf: proto.Float64(float64(math.Inf(-1))),
387 }
388 nonFinitesJSON = `{` +
389 `"fNan":"NaN",` +
390 `"fPinf":"Infinity",` +
391 `"fNinf":"-Infinity",` +
392 `"dNan":"NaN",` +
393 `"dPinf":"Infinity",` +
394 `"dNinf":"-Infinity"` +
395 `}`
396 )
397
398 func init() {
399 if err := proto.SetExtension(realNumber, pb.E_Name, &realNumberName); err != nil {
400 panic(err)
401 }
402 if err := proto.SetExtension(realNumber, pb.E_Complex_RealExtension, complexNumber); err != nil {
403 panic(err)
404 }
405 }
406
407 var marshalingTests = []struct {
408 desc string
409 marshaler Marshaler
410 pb proto.Message
411 json string
412 }{
413 {"simple flat object", marshaler, simpleObject, simpleObjectOutputJSON},
414 {"simple pretty object", marshalerAllOptions, simpleObject, simpleObjectOutputPrettyJSON},
415 {"non-finite floats fields object", marshaler, nonFinites, nonFinitesJSON},
416 {"repeated fields flat object", marshaler, repeatsObject, repeatsObjectJSON},
417 {"repeated fields pretty object", marshalerAllOptions, repeatsObject, repeatsObjectPrettyJSON},
418 {"nested message/enum flat object", marshaler, complexObject, complexObjectJSON},
419 {"nested message/enum pretty object", marshalerAllOptions, complexObject, complexObjectPrettyJSON},
420 {"enum-string flat object", Marshaler{},
421 &pb.Widget{Color: pb.Widget_BLUE.Enum()}, `{"color":"BLUE"}`},
422 {"enum-value pretty object", Marshaler{EnumsAsInts: true, Indent: " "},
423 &pb.Widget{Color: pb.Widget_BLUE.Enum()}, colorPrettyJSON},
424 {"unknown enum value object", marshalerAllOptions,
425 &pb.Widget{Color: pb.Widget_Color(1000).Enum(), RColor: []pb.Widget_Color{pb.Widget_RED}}, colorListPrettyJSON},
426 {"repeated proto3 enum", Marshaler{},
427 &proto3pb.Message{RFunny: []proto3pb.Message_Humour{
428 proto3pb.Message_PUNS,
429 proto3pb.Message_SLAPSTICK,
430 }},
431 `{"rFunny":["PUNS","SLAPSTICK"]}`},
432 {"repeated proto3 enum as int", Marshaler{EnumsAsInts: true},
433 &proto3pb.Message{RFunny: []proto3pb.Message_Humour{
434 proto3pb.Message_PUNS,
435 proto3pb.Message_SLAPSTICK,
436 }},
437 `{"rFunny":[1,2]}`},
438 {"empty value", marshaler, &pb.Simple3{}, `{}`},
439 {"empty value emitted", Marshaler{EmitDefaults: true}, &pb.Simple3{}, `{"dub":0}`},
440 {"empty repeated emitted", Marshaler{EmitDefaults: true}, &pb.SimpleSlice3{}, `{"slices":[]}`},
441 {"empty map emitted", Marshaler{EmitDefaults: true}, &pb.SimpleMap3{}, `{"stringy":{}}`},
442 {"nested struct null", Marshaler{EmitDefaults: true}, &pb.SimpleNull3{}, `{"simple":null}`},
443 {"map<int64, int32>", marshaler, &pb.Mappy{Nummy: map[int64]int32{1: 2, 3: 4}}, `{"nummy":{"1":2,"3":4}}`},
444 {"map<int64, int32>", marshalerAllOptions, &pb.Mappy{Nummy: map[int64]int32{1: 2, 3: 4}}, nummyPrettyJSON},
445 {"map<string, string>", marshaler,
446 &pb.Mappy{Strry: map[string]string{`"one"`: "two", "three": "four"}},
447 `{"strry":{"\"one\"":"two","three":"four"}}`},
448 {"map<int32, Object>", marshaler,
449 &pb.Mappy{Objjy: map[int32]*pb.Simple3{1: {Dub: 1}}}, `{"objjy":{"1":{"dub":1}}}`},
450 {"map<int32, Object>", marshalerAllOptions,
451 &pb.Mappy{Objjy: map[int32]*pb.Simple3{1: {Dub: 1}}}, objjyPrettyJSON},
452 {"map<int64, string>", marshaler, &pb.Mappy{Buggy: map[int64]string{1234: "yup"}},
453 `{"buggy":{"1234":"yup"}}`},
454 {"map<bool, bool>", marshaler, &pb.Mappy{Booly: map[bool]bool{false: true}}, `{"booly":{"false":true}}`},
455 {"map<string, enum>", marshaler, &pb.Mappy{Enumy: map[string]pb.Numeral{"XIV": pb.Numeral_ROMAN}}, `{"enumy":{"XIV":"ROMAN"}}`},
456 {"map<string, enum as int>", Marshaler{EnumsAsInts: true}, &pb.Mappy{Enumy: map[string]pb.Numeral{"XIV": pb.Numeral_ROMAN}}, `{"enumy":{"XIV":2}}`},
457 {"map<int32, bool>", marshaler, &pb.Mappy{S32Booly: map[int32]bool{1: true, 3: false, 10: true, 12: false}}, `{"s32booly":{"1":true,"3":false,"10":true,"12":false}}`},
458 {"map<int64, bool>", marshaler, &pb.Mappy{S64Booly: map[int64]bool{1: true, 3: false, 10: true, 12: false}}, `{"s64booly":{"1":true,"3":false,"10":true,"12":false}}`},
459 {"map<uint32, bool>", marshaler, &pb.Mappy{U32Booly: map[uint32]bool{1: true, 3: false, 10: true, 12: false}}, `{"u32booly":{"1":true,"3":false,"10":true,"12":false}}`},
460 {"map<uint64, bool>", marshaler, &pb.Mappy{U64Booly: map[uint64]bool{1: true, 3: false, 10: true, 12: false}}, `{"u64booly":{"1":true,"3":false,"10":true,"12":false}}`},
461 {"proto2 map<int64, string>", marshaler, &pb.Maps{MInt64Str: map[int64]string{213: "cat"}},
462 `{"mInt64Str":{"213":"cat"}}`},
463 {"proto2 map<bool, Object>", marshaler,
464 &pb.Maps{MBoolSimple: map[bool]*pb.Simple{true: {OInt32: proto.Int32(1)}}},
465 `{"mBoolSimple":{"true":{"oInt32":1}}}`},
466 {"oneof, not set", marshaler, &pb.MsgWithOneof{}, `{}`},
467 {"oneof, set", marshaler, &pb.MsgWithOneof{Union: &pb.MsgWithOneof_Title{Title: "Grand Poobah"}}, `{"title":"Grand Poobah"}`},
468 {"force orig_name", Marshaler{OrigName: true}, &pb.Simple{OInt32: proto.Int32(4)},
469 `{"o_int32":4}`},
470 {"proto2 extension", marshaler, realNumber, realNumberJSON},
471 {"Any with message", marshaler, anySimple, anySimpleJSON},
472 {"Any with message and indent", marshalerAllOptions, anySimple, anySimplePrettyJSON},
473 {"Any with WKT", marshaler, anyWellKnown, anyWellKnownJSON},
474 {"Any with WKT and indent", marshalerAllOptions, anyWellKnown, anyWellKnownPrettyJSON},
475 {"Duration empty", marshaler, &types.Duration{}, `"0s"`},
476 {"Duration with secs", marshaler, &types.Duration{Seconds: 3}, `"3s"`},
477 {"Duration with -secs", marshaler, &types.Duration{Seconds: -3}, `"-3s"`},
478 {"Duration with nanos", marshaler, &types.Duration{Nanos: 1e6}, `"0.001s"`},
479 {"Duration with -nanos", marshaler, &types.Duration{Nanos: -1e6}, `"-0.001s"`},
480 {"Duration with large secs", marshaler, &types.Duration{Seconds: 1e10, Nanos: 1}, `"10000000000.000000001s"`},
481 {"Duration with 6-digit nanos", marshaler, &types.Duration{Nanos: 1e4}, `"0.000010s"`},
482 {"Duration with 3-digit nanos", marshaler, &types.Duration{Nanos: 1e6}, `"0.001s"`},
483 {"Duration with -secs -nanos", marshaler, &types.Duration{Seconds: -123, Nanos: -450}, `"-123.000000450s"`},
484 {"Duration max value", marshaler, &types.Duration{Seconds: 315576000000, Nanos: 999999999}, `"315576000000.999999999s"`},
485 {"Duration small negative", marshaler, &types.Duration{Nanos: -1}, `"-0.000000001s"`},
486 {"Duration min value", marshaler, &types.Duration{Seconds: -315576000000, Nanos: -999999999}, `"-315576000000.999999999s"`},
487 {"Struct", marshaler, &pb.KnownTypes{St: &types.Struct{
488 Fields: map[string]*types.Value{
489 "one": {Kind: &types.Value_StringValue{StringValue: "loneliest number"}},
490 "two": {Kind: &types.Value_NullValue{NullValue: types.NullValue_NULL_VALUE}},
491 },
492 }}, `{"st":{"one":"loneliest number","two":null}}`},
493 {"empty ListValue", marshaler, &pb.KnownTypes{Lv: &types.ListValue{}}, `{"lv":[]}`},
494 {"basic ListValue", marshaler, &pb.KnownTypes{Lv: &types.ListValue{Values: []*types.Value{
495 {Kind: &types.Value_StringValue{StringValue: "x"}},
496 {Kind: &types.Value_NullValue{}},
497 {Kind: &types.Value_NumberValue{NumberValue: 3}},
498 {Kind: &types.Value_BoolValue{BoolValue: true}},
499 }}}, `{"lv":["x",null,3,true]}`},
500 {"Timestamp", marshaler, &pb.KnownTypes{Ts: &types.Timestamp{Seconds: 14e8, Nanos: 21e6}}, `{"ts":"2014-05-13T16:53:20.021Z"}`},
501 {"Timestamp", marshaler, &pb.KnownTypes{Ts: &types.Timestamp{Seconds: 14e8, Nanos: 0}}, `{"ts":"2014-05-13T16:53:20Z"}`},
502 {"number Value", marshaler, &pb.KnownTypes{Val: &types.Value{Kind: &types.Value_NumberValue{NumberValue: 1}}}, `{"val":1}`},
503 {"null Value", marshaler, &pb.KnownTypes{Val: &types.Value{Kind: &types.Value_NullValue{NullValue: types.NullValue_NULL_VALUE}}}, `{"val":null}`},
504 {"string number value", marshaler, &pb.KnownTypes{Val: &types.Value{Kind: &types.Value_StringValue{StringValue: "9223372036854775807"}}}, `{"val":"9223372036854775807"}`},
505 {"list of lists Value", marshaler, &pb.KnownTypes{Val: &types.Value{
506 Kind: &types.Value_ListValue{ListValue: &types.ListValue{
507 Values: []*types.Value{
508 {Kind: &types.Value_StringValue{StringValue: "x"}},
509 {Kind: &types.Value_ListValue{ListValue: &types.ListValue{
510 Values: []*types.Value{
511 {Kind: &types.Value_ListValue{ListValue: &types.ListValue{
512 Values: []*types.Value{{Kind: &types.Value_StringValue{StringValue: "y"}}},
513 }}},
514 {Kind: &types.Value_StringValue{StringValue: "z"}},
515 },
516 }}},
517 },
518 }},
519 }}, `{"val":["x",[["y"],"z"]]}`},
520 {"DoubleValue", marshaler, &pb.KnownTypes{Dbl: &types.DoubleValue{Value: 1.2}}, `{"dbl":1.2}`},
521 {"FloatValue", marshaler, &pb.KnownTypes{Flt: &types.FloatValue{Value: 1.2}}, `{"flt":1.2}`},
522 {"Int64Value", marshaler, &pb.KnownTypes{I64: &types.Int64Value{Value: -3}}, `{"i64":"-3"}`},
523 {"UInt64Value", marshaler, &pb.KnownTypes{U64: &types.UInt64Value{Value: 3}}, `{"u64":"3"}`},
524 {"Int32Value", marshaler, &pb.KnownTypes{I32: &types.Int32Value{Value: -4}}, `{"i32":-4}`},
525 {"UInt32Value", marshaler, &pb.KnownTypes{U32: &types.UInt32Value{Value: 4}}, `{"u32":4}`},
526 {"BoolValue", marshaler, &pb.KnownTypes{Bool: &types.BoolValue{Value: true}}, `{"bool":true}`},
527 {"StringValue", marshaler, &pb.KnownTypes{Str: &types.StringValue{Value: "plush"}}, `{"str":"plush"}`},
528 {"BytesValue", marshaler, &pb.KnownTypes{Bytes: &types.BytesValue{Value: []byte("wow")}}, `{"bytes":"d293"}`},
529 {"required", marshaler, &pb.MsgWithRequired{Str: proto.String("hello")}, `{"str":"hello"}`},
530 {"required bytes", marshaler, &pb.MsgWithRequiredBytes{Byts: []byte{}}, `{"byts":""}`},
531 }
532
533 func TestMarshaling(t *testing.T) {
534 for _, tt := range marshalingTests {
535 json, err := tt.marshaler.MarshalToString(tt.pb)
536 if err != nil {
537 t.Errorf("%s: marshaling error: %v", tt.desc, err)
538 } else if tt.json != json {
539 t.Errorf("%s: got [%v] want [%v]", tt.desc, json, tt.json)
540 }
541 }
542 }
543
544 func TestMarshalingNil(t *testing.T) {
545 var msg *pb.Simple
546 m := &Marshaler{}
547 if _, err := m.MarshalToString(msg); err == nil {
548 t.Errorf("mashaling nil returned no error")
549 }
550 }
551
552 func TestMarshalIllegalTime(t *testing.T) {
553 tests := []struct {
554 pb proto.Message
555 fail bool
556 }{
557 {&types.Duration{Seconds: 1, Nanos: 0}, false},
558 {&types.Duration{Seconds: -1, Nanos: 0}, false},
559 {&types.Duration{Seconds: 1, Nanos: -1}, true},
560 {&types.Duration{Seconds: -1, Nanos: 1}, true},
561 {&types.Duration{Seconds: 315576000001}, true},
562 {&types.Duration{Seconds: -315576000001}, true},
563 {&types.Duration{Seconds: 1, Nanos: 1000000000}, true},
564 {&types.Duration{Seconds: -1, Nanos: -1000000000}, true},
565 {&types.Timestamp{Seconds: 1, Nanos: 1}, false},
566 {&types.Timestamp{Seconds: 1, Nanos: -1}, true},
567 {&types.Timestamp{Seconds: 1, Nanos: 1000000000}, true},
568 }
569 for _, tt := range tests {
570 _, err := marshaler.MarshalToString(tt.pb)
571 if err == nil && tt.fail {
572 t.Errorf("marshaler.MarshalToString(%v) = _, <nil>; want _, <non-nil>", tt.pb)
573 }
574 if err != nil && !tt.fail {
575 t.Errorf("marshaler.MarshalToString(%v) = _, %v; want _, <nil>", tt.pb, err)
576 }
577 }
578 }
579
580 func TestMarshalJSONPBMarshaler(t *testing.T) {
581 rawJson := `{ "foo": "bar", "baz": [0, 1, 2, 3] }`
582 msg := dynamicMessage{RawJson: rawJson}
583 str, err := new(Marshaler).MarshalToString(&msg)
584 if err != nil {
585 t.Errorf("an unexpected error occurred when marshalling JSONPBMarshaler: %v", err)
586 }
587 if str != rawJson {
588 t.Errorf("marshalling JSON produced incorrect output: got %s, wanted %s", str, rawJson)
589 }
590 }
591
592 func TestMarshalAnyJSONPBMarshaler(t *testing.T) {
593 msg := dynamicMessage{RawJson: `{ "foo": "bar", "baz": [0, 1, 2, 3] }`}
594 a, err := types.MarshalAny(&msg)
595 if err != nil {
596 t.Errorf("an unexpected error occurred when marshalling to Any: %v", err)
597 }
598 str, err := new(Marshaler).MarshalToString(a)
599 if err != nil {
600 t.Errorf("an unexpected error occurred when marshalling Any to JSON: %v", err)
601 }
602
603
604 expected := `{"@type":"type.googleapis.com/` + dynamicMessageName + `","baz":[0,1,2,3],"foo":"bar"}`
605 if str != expected {
606 t.Errorf("marshalling JSON produced incorrect output: got %s, wanted %s", str, expected)
607 }
608
609
610
611 marshaler := Marshaler{Indent: " "}
612 str, err = marshaler.MarshalToString(a)
613 if err != nil {
614 t.Errorf("an unexpected error occurred when marshalling Any to JSON: %v", err)
615 }
616
617 expected = `{
618 "@type": "type.googleapis.com/` + dynamicMessageName + `",
619 "baz": [
620 0,
621 1,
622 2,
623 3
624 ],
625 "foo": "bar"
626 }`
627 if str != expected {
628 t.Errorf("marshalling JSON produced incorrect output: got %s, wanted %s", str, expected)
629 }
630 }
631
632 func TestMarshalWithCustomValidation(t *testing.T) {
633 msg := dynamicMessage{RawJson: `{ "foo": "bar", "baz": [0, 1, 2, 3] }`, Dummy: &dynamicMessage{}}
634
635 js, err := new(Marshaler).MarshalToString(&msg)
636 if err != nil {
637 t.Errorf("an unexpected error occurred when marshalling to json: %v", err)
638 }
639 err = Unmarshal(strings.NewReader(js), &msg)
640 if err != nil {
641 t.Errorf("an unexpected error occurred when unmarshalling from json: %v", err)
642 }
643 }
644
645
646 func TestMarshalUnsetRequiredFields(t *testing.T) {
647 msgExt := &pb.Real{}
648 proto.SetExtension(msgExt, pb.E_Extm, &pb.MsgWithRequired{})
649
650 tests := []struct {
651 desc string
652 marshaler *Marshaler
653 pb proto.Message
654 }{
655 {
656 desc: "direct required field",
657 marshaler: &Marshaler{},
658 pb: &pb.MsgWithRequired{},
659 },
660 {
661 desc: "direct required field + emit defaults",
662 marshaler: &Marshaler{EmitDefaults: true},
663 pb: &pb.MsgWithRequired{},
664 },
665 {
666 desc: "indirect required field",
667 marshaler: &Marshaler{},
668 pb: &pb.MsgWithIndirectRequired{Subm: &pb.MsgWithRequired{}},
669 },
670 {
671 desc: "indirect required field + emit defaults",
672 marshaler: &Marshaler{EmitDefaults: true},
673 pb: &pb.MsgWithIndirectRequired{Subm: &pb.MsgWithRequired{}},
674 },
675 {
676 desc: "direct required wkt field",
677 marshaler: &Marshaler{},
678 pb: &pb.MsgWithRequiredWKT{},
679 },
680 {
681 desc: "direct required wkt field + emit defaults",
682 marshaler: &Marshaler{EmitDefaults: true},
683 pb: &pb.MsgWithRequiredWKT{},
684 },
685 {
686 desc: "direct required bytes field",
687 marshaler: &Marshaler{},
688 pb: &pb.MsgWithRequiredBytes{},
689 },
690 {
691 desc: "required in map value",
692 marshaler: &Marshaler{},
693 pb: &pb.MsgWithIndirectRequired{
694 MapField: map[string]*pb.MsgWithRequired{
695 "key": {},
696 },
697 },
698 },
699 {
700 desc: "required in repeated item",
701 marshaler: &Marshaler{},
702 pb: &pb.MsgWithIndirectRequired{
703 SliceField: []*pb.MsgWithRequired{
704 {Str: proto.String("hello")},
705 {},
706 },
707 },
708 },
709 {
710 desc: "required inside oneof",
711 marshaler: &Marshaler{},
712 pb: &pb.MsgWithOneof{
713 Union: &pb.MsgWithOneof_MsgWithRequired{MsgWithRequired: &pb.MsgWithRequired{}},
714 },
715 },
716 {
717 desc: "required inside extension",
718 marshaler: &Marshaler{},
719 pb: msgExt,
720 },
721 }
722
723 for _, tc := range tests {
724 if _, err := tc.marshaler.MarshalToString(tc.pb); err == nil {
725 t.Errorf("%s: expecting error in marshaling with unset required fields %+v", tc.desc, tc.pb)
726 }
727 }
728 }
729
730 var unmarshalingTests = []struct {
731 desc string
732 unmarshaler Unmarshaler
733 json string
734 pb proto.Message
735 }{
736 {"simple flat object", Unmarshaler{}, simpleObjectInputJSON, simpleObject},
737 {"simple pretty object", Unmarshaler{}, simpleObjectInputPrettyJSON, simpleObject},
738 {"repeated fields flat object", Unmarshaler{}, repeatsObjectJSON, repeatsObject},
739 {"repeated fields pretty object", Unmarshaler{}, repeatsObjectPrettyJSON, repeatsObject},
740 {"nested message/enum flat object", Unmarshaler{}, complexObjectJSON, complexObject},
741 {"nested message/enum pretty object", Unmarshaler{}, complexObjectPrettyJSON, complexObject},
742 {"enum-string object", Unmarshaler{}, `{"color":"BLUE"}`, &pb.Widget{Color: pb.Widget_BLUE.Enum()}},
743 {"enum-value object", Unmarshaler{}, "{\n \"color\": 2\n}", &pb.Widget{Color: pb.Widget_BLUE.Enum()}},
744 {"unknown field with allowed option", Unmarshaler{AllowUnknownFields: true}, `{"unknown": "foo"}`, new(pb.Simple)},
745 {"proto3 enum string", Unmarshaler{}, `{"hilarity":"PUNS"}`, &proto3pb.Message{Hilarity: proto3pb.Message_PUNS}},
746 {"proto3 enum value", Unmarshaler{}, `{"hilarity":1}`, &proto3pb.Message{Hilarity: proto3pb.Message_PUNS}},
747 {"unknown enum value object",
748 Unmarshaler{},
749 "{\n \"color\": 1000,\n \"r_color\": [\n \"RED\"\n ]\n}",
750 &pb.Widget{Color: pb.Widget_Color(1000).Enum(), RColor: []pb.Widget_Color{pb.Widget_RED}}},
751 {"repeated proto3 enum", Unmarshaler{}, `{"rFunny":["PUNS","SLAPSTICK"]}`,
752 &proto3pb.Message{RFunny: []proto3pb.Message_Humour{
753 proto3pb.Message_PUNS,
754 proto3pb.Message_SLAPSTICK,
755 }}},
756 {"repeated proto3 enum as int", Unmarshaler{}, `{"rFunny":[1,2]}`,
757 &proto3pb.Message{RFunny: []proto3pb.Message_Humour{
758 proto3pb.Message_PUNS,
759 proto3pb.Message_SLAPSTICK,
760 }}},
761 {"repeated proto3 enum as mix of strings and ints", Unmarshaler{}, `{"rFunny":["PUNS",2]}`,
762 &proto3pb.Message{RFunny: []proto3pb.Message_Humour{
763 proto3pb.Message_PUNS,
764 proto3pb.Message_SLAPSTICK,
765 }}},
766 {"unquoted int64 object", Unmarshaler{}, `{"oInt64":-314}`, &pb.Simple{OInt64: proto.Int64(-314)}},
767 {"unquoted uint64 object", Unmarshaler{}, `{"oUint64":123}`, &pb.Simple{OUint64: proto.Uint64(123)}},
768 {"NaN", Unmarshaler{}, `{"oDouble":"NaN"}`, &pb.Simple{ODouble: proto.Float64(math.NaN())}},
769 {"Inf", Unmarshaler{}, `{"oFloat":"Infinity"}`, &pb.Simple{OFloat: proto.Float32(float32(math.Inf(1)))}},
770 {"-Inf", Unmarshaler{}, `{"oDouble":"-Infinity"}`, &pb.Simple{ODouble: proto.Float64(math.Inf(-1))}},
771 {"map<int64, int32>", Unmarshaler{}, `{"nummy":{"1":2,"3":4}}`, &pb.Mappy{Nummy: map[int64]int32{1: 2, 3: 4}}},
772 {"map<string, string>", Unmarshaler{}, `{"strry":{"\"one\"":"two","three":"four"}}`, &pb.Mappy{Strry: map[string]string{`"one"`: "two", "three": "four"}}},
773 {"map<int32, Object>", Unmarshaler{}, `{"objjy":{"1":{"dub":1}}}`, &pb.Mappy{Objjy: map[int32]*pb.Simple3{1: {Dub: 1}}}},
774 {"proto2 extension", Unmarshaler{}, realNumberJSON, realNumber},
775
776
777 {"Any with WKT", Unmarshaler{}, anyWellKnownJSON, anyWellKnown},
778 {"Any with WKT and indent", Unmarshaler{}, anyWellKnownPrettyJSON, anyWellKnown},
779 {"map<string, enum>", Unmarshaler{}, `{"enumy":{"XIV":"ROMAN"}}`, &pb.Mappy{Enumy: map[string]pb.Numeral{"XIV": pb.Numeral_ROMAN}}},
780 {"map<string, enum as int>", Unmarshaler{}, `{"enumy":{"XIV":2}}`, &pb.Mappy{Enumy: map[string]pb.Numeral{"XIV": pb.Numeral_ROMAN}}},
781 {"oneof", Unmarshaler{}, `{"salary":31000}`, &pb.MsgWithOneof{Union: &pb.MsgWithOneof_Salary{Salary: 31000}}},
782 {"oneof spec name", Unmarshaler{}, `{"Country":"Australia"}`, &pb.MsgWithOneof{Union: &pb.MsgWithOneof_Country{Country: "Australia"}}},
783 {"oneof orig_name", Unmarshaler{}, `{"Country":"Australia"}`, &pb.MsgWithOneof{Union: &pb.MsgWithOneof_Country{Country: "Australia"}}},
784 {"oneof spec name2", Unmarshaler{}, `{"homeAddress":"Australia"}`, &pb.MsgWithOneof{Union: &pb.MsgWithOneof_HomeAddress{HomeAddress: "Australia"}}},
785 {"oneof orig_name2", Unmarshaler{}, `{"home_address":"Australia"}`, &pb.MsgWithOneof{Union: &pb.MsgWithOneof_HomeAddress{HomeAddress: "Australia"}}},
786 {"orig_name input", Unmarshaler{}, `{"o_bool":true}`, &pb.Simple{OBool: proto.Bool(true)}},
787 {"camelName input", Unmarshaler{}, `{"oBool":true}`, &pb.Simple{OBool: proto.Bool(true)}},
788 {"Duration", Unmarshaler{}, `{"dur":"3.000s"}`, &pb.KnownTypes{Dur: &types.Duration{Seconds: 3}}},
789 {"Duration", Unmarshaler{}, `{"dur":"4s"}`, &pb.KnownTypes{Dur: &types.Duration{Seconds: 4}}},
790 {"Duration with unicode", Unmarshaler{}, `{"dur": "3\u0073"}`, &pb.KnownTypes{Dur: &types.Duration{Seconds: 3}}},
791 {"null Duration", Unmarshaler{}, `{"dur":null}`, &pb.KnownTypes{Dur: nil}},
792 {"Timestamp", Unmarshaler{}, `{"ts":"2014-05-13T16:53:20.021Z"}`, &pb.KnownTypes{Ts: &types.Timestamp{Seconds: 14e8, Nanos: 21e6}}},
793 {"Timestamp", Unmarshaler{}, `{"ts":"2014-05-13T16:53:20Z"}`, &pb.KnownTypes{Ts: &types.Timestamp{Seconds: 14e8, Nanos: 0}}},
794 {"Timestamp with unicode", Unmarshaler{}, `{"ts": "2014-05-13T16:53:20\u005a"}`, &pb.KnownTypes{Ts: &types.Timestamp{Seconds: 14e8, Nanos: 0}}},
795 {"PreEpochTimestamp", Unmarshaler{}, `{"ts":"1969-12-31T23:59:58.999999995Z"}`, &pb.KnownTypes{Ts: &types.Timestamp{Seconds: -2, Nanos: 999999995}}},
796 {"ZeroTimeTimestamp", Unmarshaler{}, `{"ts":"0001-01-01T00:00:00Z"}`, &pb.KnownTypes{Ts: &types.Timestamp{Seconds: -62135596800, Nanos: 0}}},
797 {"null Timestamp", Unmarshaler{}, `{"ts":null}`, &pb.KnownTypes{Ts: nil}},
798 {"null Struct", Unmarshaler{}, `{"st": null}`, &pb.KnownTypes{St: nil}},
799 {"empty Struct", Unmarshaler{}, `{"st": {}}`, &pb.KnownTypes{St: &types.Struct{}}},
800 {"basic Struct", Unmarshaler{}, `{"st": {"a": "x", "b": null, "c": 3, "d": true}}`, &pb.KnownTypes{St: &types.Struct{Fields: map[string]*types.Value{
801 "a": {Kind: &types.Value_StringValue{StringValue: "x"}},
802 "b": {Kind: &types.Value_NullValue{}},
803 "c": {Kind: &types.Value_NumberValue{NumberValue: 3}},
804 "d": {Kind: &types.Value_BoolValue{BoolValue: true}},
805 }}}},
806 {"nested Struct", Unmarshaler{}, `{"st": {"a": {"b": 1, "c": [{"d": true}, "f"]}}}`, &pb.KnownTypes{St: &types.Struct{Fields: map[string]*types.Value{
807 "a": {Kind: &types.Value_StructValue{StructValue: &types.Struct{Fields: map[string]*types.Value{
808 "b": {Kind: &types.Value_NumberValue{NumberValue: 1}},
809 "c": {Kind: &types.Value_ListValue{ListValue: &types.ListValue{Values: []*types.Value{
810 {Kind: &types.Value_StructValue{StructValue: &types.Struct{Fields: map[string]*types.Value{"d": {Kind: &types.Value_BoolValue{BoolValue: true}}}}}},
811 {Kind: &types.Value_StringValue{StringValue: "f"}},
812 }}}},
813 }}}},
814 }}}},
815 {"null ListValue", Unmarshaler{}, `{"lv": null}`, &pb.KnownTypes{Lv: nil}},
816 {"empty ListValue", Unmarshaler{}, `{"lv": []}`, &pb.KnownTypes{Lv: &types.ListValue{}}},
817 {"basic ListValue", Unmarshaler{}, `{"lv": ["x", null, 3, true]}`, &pb.KnownTypes{Lv: &types.ListValue{Values: []*types.Value{
818 {Kind: &types.Value_StringValue{StringValue: "x"}},
819 {Kind: &types.Value_NullValue{}},
820 {Kind: &types.Value_NumberValue{NumberValue: 3}},
821 {Kind: &types.Value_BoolValue{BoolValue: true}},
822 }}}},
823 {"number Value", Unmarshaler{}, `{"val":1}`, &pb.KnownTypes{Val: &types.Value{Kind: &types.Value_NumberValue{NumberValue: 1}}}},
824 {"null Value", Unmarshaler{}, `{"val":null}`, &pb.KnownTypes{Val: &types.Value{Kind: &types.Value_NullValue{NullValue: types.NullValue_NULL_VALUE}}}},
825 {"bool Value", Unmarshaler{}, `{"val":true}`, &pb.KnownTypes{Val: &types.Value{Kind: &types.Value_BoolValue{BoolValue: true}}}},
826 {"string Value", Unmarshaler{}, `{"val":"x"}`, &pb.KnownTypes{Val: &types.Value{Kind: &types.Value_StringValue{StringValue: "x"}}}},
827 {"string number value", Unmarshaler{}, `{"val":"9223372036854775807"}`, &pb.KnownTypes{Val: &types.Value{Kind: &types.Value_StringValue{StringValue: "9223372036854775807"}}}},
828 {"list of lists Value", Unmarshaler{}, `{"val":["x", [["y"], "z"]]}`, &pb.KnownTypes{Val: &types.Value{
829 Kind: &types.Value_ListValue{ListValue: &types.ListValue{
830 Values: []*types.Value{
831 {Kind: &types.Value_StringValue{StringValue: "x"}},
832 {Kind: &types.Value_ListValue{ListValue: &types.ListValue{
833 Values: []*types.Value{
834 {Kind: &types.Value_ListValue{ListValue: &types.ListValue{
835 Values: []*types.Value{{Kind: &types.Value_StringValue{StringValue: "y"}}},
836 }}},
837 {Kind: &types.Value_StringValue{StringValue: "z"}},
838 },
839 }}},
840 },
841 }}}}},
842
843 {"DoubleValue", Unmarshaler{}, `{"dbl":1.2}`, &pb.KnownTypes{Dbl: &types.DoubleValue{Value: 1.2}}},
844 {"FloatValue", Unmarshaler{}, `{"flt":1.2}`, &pb.KnownTypes{Flt: &types.FloatValue{Value: 1.2}}},
845 {"Int64Value", Unmarshaler{}, `{"i64":"-3"}`, &pb.KnownTypes{I64: &types.Int64Value{Value: -3}}},
846 {"UInt64Value", Unmarshaler{}, `{"u64":"3"}`, &pb.KnownTypes{U64: &types.UInt64Value{Value: 3}}},
847 {"Int32Value", Unmarshaler{}, `{"i32":-4}`, &pb.KnownTypes{I32: &types.Int32Value{Value: -4}}},
848 {"UInt32Value", Unmarshaler{}, `{"u32":4}`, &pb.KnownTypes{U32: &types.UInt32Value{Value: 4}}},
849 {"BoolValue", Unmarshaler{}, `{"bool":true}`, &pb.KnownTypes{Bool: &types.BoolValue{Value: true}}},
850 {"StringValue", Unmarshaler{}, `{"str":"plush"}`, &pb.KnownTypes{Str: &types.StringValue{Value: "plush"}}},
851 {"StringValue containing escaped character", Unmarshaler{}, `{"str":"a\/b"}`, &pb.KnownTypes{Str: &types.StringValue{Value: "a/b"}}},
852 {"StructValue containing StringValue's", Unmarshaler{}, `{"escaped": "a\/b", "unicode": "\u00004E16\u0000754C"}`,
853 &types.Struct{
854 Fields: map[string]*types.Value{
855 "escaped": {Kind: &types.Value_StringValue{StringValue: "a/b"}},
856 "unicode": {Kind: &types.Value_StringValue{StringValue: "\u00004E16\u0000754C"}},
857 },
858 }},
859 {"BytesValue", Unmarshaler{}, `{"bytes":"d293"}`, &pb.KnownTypes{Bytes: &types.BytesValue{Value: []byte("wow")}}},
860
861 {"null DoubleValue", Unmarshaler{}, `{"dbl":null}`, &pb.KnownTypes{Dbl: nil}},
862 {"null FloatValue", Unmarshaler{}, `{"flt":null}`, &pb.KnownTypes{Flt: nil}},
863 {"null Int64Value", Unmarshaler{}, `{"i64":null}`, &pb.KnownTypes{I64: nil}},
864 {"null UInt64Value", Unmarshaler{}, `{"u64":null}`, &pb.KnownTypes{U64: nil}},
865 {"null Int32Value", Unmarshaler{}, `{"i32":null}`, &pb.KnownTypes{I32: nil}},
866 {"null UInt32Value", Unmarshaler{}, `{"u32":null}`, &pb.KnownTypes{U32: nil}},
867 {"null BoolValue", Unmarshaler{}, `{"bool":null}`, &pb.KnownTypes{Bool: nil}},
868 {"null StringValue", Unmarshaler{}, `{"str":null}`, &pb.KnownTypes{Str: nil}},
869 {"null BytesValue", Unmarshaler{}, `{"bytes":null}`, &pb.KnownTypes{Bytes: nil}},
870 {"required", Unmarshaler{}, `{"str":"hello"}`, &pb.MsgWithRequired{Str: proto.String("hello")}},
871 {"required bytes", Unmarshaler{}, `{"byts": []}`, &pb.MsgWithRequiredBytes{Byts: []byte{}}},
872 }
873
874 func TestUnmarshaling(t *testing.T) {
875 for _, tt := range unmarshalingTests {
876
877 p := reflect.New(reflect.TypeOf(tt.pb).Elem()).Interface().(proto.Message)
878
879 err := tt.unmarshaler.Unmarshal(strings.NewReader(tt.json), p)
880 if err != nil {
881 t.Errorf("unmarshalling %s: %v", tt.desc, err)
882 continue
883 }
884
885
886 exp := proto.MarshalTextString(tt.pb)
887 act := proto.MarshalTextString(p)
888 if string(exp) != string(act) {
889 t.Errorf("%s: got [%s] want [%s]", tt.desc, act, exp)
890 }
891 }
892 }
893
894 func TestUnmarshalNullArray(t *testing.T) {
895 var repeats pb.Repeats
896 if err := UnmarshalString(`{"rBool":null}`, &repeats); err != nil {
897 t.Fatal(err)
898 }
899 if !reflect.DeepEqual(repeats, pb.Repeats{}) {
900 t.Errorf("got non-nil fields in [%#v]", repeats)
901 }
902 }
903
904 func TestUnmarshalNullObject(t *testing.T) {
905 var maps pb.Maps
906 if err := UnmarshalString(`{"mInt64Str":null}`, &maps); err != nil {
907 t.Fatal(err)
908 }
909 if !reflect.DeepEqual(maps, pb.Maps{}) {
910 t.Errorf("got non-nil fields in [%#v]", maps)
911 }
912 }
913
914 func TestUnmarshalNext(t *testing.T) {
915
916 tests := unmarshalingTests[:5]
917
918
919 var b bytes.Buffer
920 for _, tt := range tests {
921 b.WriteString(tt.json)
922 }
923
924 dec := json.NewDecoder(&b)
925 for _, tt := range tests {
926
927 p := reflect.New(reflect.TypeOf(tt.pb).Elem()).Interface().(proto.Message)
928
929 err := tt.unmarshaler.UnmarshalNext(dec, p)
930 if err != nil {
931 t.Errorf("%s: %v", tt.desc, err)
932 continue
933 }
934
935
936 exp := proto.MarshalTextString(tt.pb)
937 act := proto.MarshalTextString(p)
938 if string(exp) != string(act) {
939 t.Errorf("%s: got [%s] want [%s]", tt.desc, act, exp)
940 }
941 }
942
943 p := &pb.Simple{}
944 err := new(Unmarshaler).UnmarshalNext(dec, p)
945 if err != io.EOF {
946 t.Errorf("eof: got %v, expected io.EOF", err)
947 }
948 }
949
950 var unmarshalingShouldError = []struct {
951 desc string
952 in string
953 pb proto.Message
954 }{
955 {"a value", "666", new(pb.Simple)},
956 {"gibberish", "{adskja123;l23=-=", new(pb.Simple)},
957 {"unknown field", `{"unknown": "foo"}`, new(pb.Simple)},
958 {"unknown enum name", `{"hilarity":"DAVE"}`, new(proto3pb.Message)},
959 {"Duration containing invalid character", `{"dur": "3\U0073"}`, &pb.KnownTypes{}},
960 {"Timestamp containing invalid character", `{"ts": "2014-05-13T16:53:20\U005a"}`, &pb.KnownTypes{}},
961 {"StringValue containing invalid character", `{"str": "\U00004E16\U0000754C"}`, &pb.KnownTypes{}},
962 {"StructValue containing invalid character", `{"str": "\U00004E16\U0000754C"}`, &types.Struct{}},
963 {"repeated proto3 enum with non array input", `{"rFunny":"PUNS"}`, &proto3pb.Message{RFunny: []proto3pb.Message_Humour{}}},
964 }
965
966 func TestUnmarshalingBadInput(t *testing.T) {
967 for _, tt := range unmarshalingShouldError {
968 err := UnmarshalString(tt.in, tt.pb)
969 if err == nil {
970 t.Errorf("an error was expected when parsing %q instead of an object", tt.desc)
971 }
972 }
973 }
974
975 type funcResolver func(turl string) (proto.Message, error)
976
977 func (fn funcResolver) Resolve(turl string) (proto.Message, error) {
978 return fn(turl)
979 }
980
981 func TestAnyWithCustomResolver(t *testing.T) {
982 var resolvedTypeUrls []string
983 resolver := funcResolver(func(turl string) (proto.Message, error) {
984 resolvedTypeUrls = append(resolvedTypeUrls, turl)
985 return new(pb.Simple), nil
986 })
987 msg := &pb.Simple{
988 OBytes: []byte{1, 2, 3, 4},
989 OBool: proto.Bool(true),
990 OString: proto.String("foobar"),
991 OInt64: proto.Int64(1020304),
992 }
993 msgBytes, err := proto.Marshal(msg)
994 if err != nil {
995 t.Errorf("an unexpected error occurred when marshaling message: %v", err)
996 }
997
998 any := &types.Any{
999 TypeUrl: "https://foobar.com/some.random.MessageKind",
1000 Value: msgBytes,
1001 }
1002
1003 m := Marshaler{AnyResolver: resolver}
1004 js, err := m.MarshalToString(any)
1005 if err != nil {
1006 t.Errorf("an unexpected error occurred when marshaling any to JSON: %v", err)
1007 }
1008 if len(resolvedTypeUrls) != 1 {
1009 t.Errorf("custom resolver was not invoked during marshaling")
1010 } else if resolvedTypeUrls[0] != "https://foobar.com/some.random.MessageKind" {
1011 t.Errorf("custom resolver was invoked with wrong URL: got %q, wanted %q", resolvedTypeUrls[0], "https://foobar.com/some.random.MessageKind")
1012 }
1013 wanted := `{"@type":"https://foobar.com/some.random.MessageKind","oBool":true,"oInt64":"1020304","oString":"foobar","oBytes":"AQIDBA=="}`
1014 if js != wanted {
1015 t.Errorf("marshalling JSON produced incorrect output: got %s, wanted %s", js, wanted)
1016 }
1017
1018 u := Unmarshaler{AnyResolver: resolver}
1019 roundTrip := &types.Any{}
1020 err = u.Unmarshal(bytes.NewReader([]byte(js)), roundTrip)
1021 if err != nil {
1022 t.Errorf("an unexpected error occurred when unmarshaling any from JSON: %v", err)
1023 }
1024 if len(resolvedTypeUrls) != 2 {
1025 t.Errorf("custom resolver was not invoked during marshaling")
1026 } else if resolvedTypeUrls[1] != "https://foobar.com/some.random.MessageKind" {
1027 t.Errorf("custom resolver was invoked with wrong URL: got %q, wanted %q", resolvedTypeUrls[1], "https://foobar.com/some.random.MessageKind")
1028 }
1029 if !proto.Equal(any, roundTrip) {
1030 t.Errorf("message contents not set correctly after unmarshalling JSON: got %s, wanted %s", roundTrip, any)
1031 }
1032 }
1033
1034 func TestUnmarshalJSONPBUnmarshaler(t *testing.T) {
1035 rawJson := `{ "foo": "bar", "baz": [0, 1, 2, 3] }`
1036 var msg dynamicMessage
1037 if err := Unmarshal(strings.NewReader(rawJson), &msg); err != nil {
1038 t.Errorf("an unexpected error occurred when parsing into JSONPBUnmarshaler: %v", err)
1039 }
1040 if msg.RawJson != rawJson {
1041 t.Errorf("message contents not set correctly after unmarshalling JSON: got %s, wanted %s", msg.RawJson, rawJson)
1042 }
1043 }
1044
1045 func TestUnmarshalNullWithJSONPBUnmarshaler(t *testing.T) {
1046 rawJson := `{"stringField":null}`
1047 var ptrFieldMsg ptrFieldMessage
1048 if err := Unmarshal(strings.NewReader(rawJson), &ptrFieldMsg); err != nil {
1049 t.Errorf("unmarshal error: %v", err)
1050 }
1051
1052 want := ptrFieldMessage{StringField: &stringField{IsSet: true, StringValue: "null"}}
1053 if !proto.Equal(&ptrFieldMsg, &want) {
1054 t.Errorf("unmarshal result StringField: got %v, want %v", ptrFieldMsg, want)
1055 }
1056 }
1057
1058 func TestUnmarshalAnyJSONPBUnmarshaler(t *testing.T) {
1059 rawJson := `{ "@type": "blah.com/` + dynamicMessageName + `", "foo": "bar", "baz": [0, 1, 2, 3] }`
1060 var got types.Any
1061 if err := Unmarshal(strings.NewReader(rawJson), &got); err != nil {
1062 t.Errorf("an unexpected error occurred when parsing into JSONPBUnmarshaler: %v", err)
1063 }
1064
1065 dm := &dynamicMessage{RawJson: `{"baz":[0,1,2,3],"foo":"bar"}`}
1066 var want types.Any
1067 if b, err := proto.Marshal(dm); err != nil {
1068 t.Errorf("an unexpected error occurred when marshaling message: %v", err)
1069 } else {
1070 want.TypeUrl = "blah.com/" + dynamicMessageName
1071 want.Value = b
1072 }
1073
1074 if !proto.Equal(&got, &want) {
1075 t.Errorf("message contents not set correctly after unmarshalling JSON: got %v, wanted %v", got, want)
1076 }
1077 }
1078
1079 const (
1080 dynamicMessageName = "google.protobuf.jsonpb.testing.dynamicMessage"
1081 )
1082
1083 func init() {
1084
1085 proto.RegisterType((*dynamicMessage)(nil), dynamicMessageName)
1086 }
1087
1088 type ptrFieldMessage struct {
1089 StringField *stringField `protobuf:"bytes,1,opt,name=stringField"`
1090 }
1091
1092 func (m *ptrFieldMessage) Reset() {
1093 }
1094
1095 func (m *ptrFieldMessage) String() string {
1096 return m.StringField.StringValue
1097 }
1098
1099 func (m *ptrFieldMessage) ProtoMessage() {
1100 }
1101
1102 type stringField struct {
1103 IsSet bool `protobuf:"varint,1,opt,name=isSet"`
1104 StringValue string `protobuf:"bytes,2,opt,name=stringValue"`
1105 }
1106
1107 func (s *stringField) Reset() {
1108 }
1109
1110 func (s *stringField) String() string {
1111 return s.StringValue
1112 }
1113
1114 func (s *stringField) ProtoMessage() {
1115 }
1116
1117 func (s *stringField) UnmarshalJSONPB(jum *Unmarshaler, js []byte) error {
1118 s.IsSet = true
1119 s.StringValue = string(js)
1120 return nil
1121 }
1122
1123
1124
1125 type dynamicMessage struct {
1126 RawJson string `protobuf:"bytes,1,opt,name=rawJson"`
1127
1128
1129
1130 Dummy *dynamicMessage `protobuf:"bytes,2,opt,name=dummy"`
1131 }
1132
1133 func (m *dynamicMessage) Reset() {
1134 m.RawJson = "{}"
1135 }
1136
1137 func (m *dynamicMessage) String() string {
1138 return m.RawJson
1139 }
1140
1141 func (m *dynamicMessage) ProtoMessage() {
1142 }
1143
1144 func (m *dynamicMessage) MarshalJSONPB(jm *Marshaler) ([]byte, error) {
1145 return []byte(m.RawJson), nil
1146 }
1147
1148 func (m *dynamicMessage) UnmarshalJSONPB(jum *Unmarshaler, js []byte) error {
1149 m.RawJson = string(js)
1150 return nil
1151 }
1152
1153
1154 func TestUnmarshalUnsetRequiredFields(t *testing.T) {
1155 tests := []struct {
1156 desc string
1157 pb proto.Message
1158 json string
1159 }{
1160 {
1161 desc: "direct required field missing",
1162 pb: &pb.MsgWithRequired{},
1163 json: `{}`,
1164 },
1165 {
1166 desc: "direct required field set to null",
1167 pb: &pb.MsgWithRequired{},
1168 json: `{"str": null}`,
1169 },
1170 {
1171 desc: "indirect required field missing",
1172 pb: &pb.MsgWithIndirectRequired{},
1173 json: `{"subm": {}}`,
1174 },
1175 {
1176 desc: "indirect required field set to null",
1177 pb: &pb.MsgWithIndirectRequired{},
1178 json: `{"subm": {"str": null}}`,
1179 },
1180 {
1181 desc: "direct required bytes field missing",
1182 pb: &pb.MsgWithRequiredBytes{},
1183 json: `{}`,
1184 },
1185 {
1186 desc: "direct required bytes field set to null",
1187 pb: &pb.MsgWithRequiredBytes{},
1188 json: `{"byts": null}`,
1189 },
1190 {
1191 desc: "direct required wkt field missing",
1192 pb: &pb.MsgWithRequiredWKT{},
1193 json: `{}`,
1194 },
1195 {
1196 desc: "direct required wkt field set to null",
1197 pb: &pb.MsgWithRequiredWKT{},
1198 json: `{"str": null}`,
1199 },
1200 {
1201 desc: "any containing message with required field set to null",
1202 pb: &pb.KnownTypes{},
1203 json: `{"an": {"@type": "example.com/jsonpb.MsgWithRequired", "str": null}}`,
1204 },
1205 {
1206 desc: "any containing message with missing required field",
1207 pb: &pb.KnownTypes{},
1208 json: `{"an": {"@type": "example.com/jsonpb.MsgWithRequired"}}`,
1209 },
1210 {
1211 desc: "missing required in map value",
1212 pb: &pb.MsgWithIndirectRequired{},
1213 json: `{"map_field": {"a": {}, "b": {"str": "hi"}}}`,
1214 },
1215 {
1216 desc: "required in map value set to null",
1217 pb: &pb.MsgWithIndirectRequired{},
1218 json: `{"map_field": {"a": {"str": "hello"}, "b": {"str": null}}}`,
1219 },
1220 {
1221 desc: "missing required in slice item",
1222 pb: &pb.MsgWithIndirectRequired{},
1223 json: `{"slice_field": [{}, {"str": "hi"}]}`,
1224 },
1225 {
1226 desc: "required in slice item set to null",
1227 pb: &pb.MsgWithIndirectRequired{},
1228 json: `{"slice_field": [{"str": "hello"}, {"str": null}]}`,
1229 },
1230 {
1231 desc: "required inside oneof missing",
1232 pb: &pb.MsgWithOneof{},
1233 json: `{"msgWithRequired": {}}`,
1234 },
1235 {
1236 desc: "required inside oneof set to null",
1237 pb: &pb.MsgWithOneof{},
1238 json: `{"msgWithRequired": {"str": null}}`,
1239 },
1240 {
1241 desc: "required field in extension missing",
1242 pb: &pb.Real{},
1243 json: `{"[jsonpb.extm]":{}}`,
1244 },
1245 {
1246 desc: "required field in extension set to null",
1247 pb: &pb.Real{},
1248 json: `{"[jsonpb.extm]":{"str": null}}`,
1249 },
1250 }
1251
1252 for _, tc := range tests {
1253 if err := UnmarshalString(tc.json, tc.pb); err == nil {
1254 t.Errorf("%s: expecting error in unmarshaling with unset required fields %s", tc.desc, tc.json)
1255 }
1256 }
1257 }
1258
View as plain text