blob: 2d46bd4e91a47eebdcfa2b7f4ce7faaeae879140 [file] [log] [blame]
Herbie Ong7b828bc2019-02-08 19:56:24 -08001// Copyright 2019 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
Damien Neil5c5b5312019-05-14 12:44:37 -07005package protojson_test
Herbie Ong7b828bc2019-02-08 19:56:24 -08006
7import (
Damien Neilbc310b52019-04-11 11:46:55 -07008 "bytes"
Herbie Ong7b828bc2019-02-08 19:56:24 -08009 "math"
Herbie Ong7b828bc2019-02-08 19:56:24 -080010 "testing"
11
Herbie Ong7b828bc2019-02-08 19:56:24 -080012 "github.com/google/go-cmp/cmp"
Damien Neil5c5b5312019-05-14 12:44:37 -070013 "google.golang.org/protobuf/encoding/protojson"
Herbie Ong582ab3d2019-09-06 15:56:09 -070014 "google.golang.org/protobuf/internal/detrand"
Damien Neile89e6242019-05-13 23:55:40 -070015 "google.golang.org/protobuf/internal/encoding/pack"
Joe Tsai5ae10aa2019-07-11 18:23:08 -070016 "google.golang.org/protobuf/internal/flags"
Damien Neile89e6242019-05-13 23:55:40 -070017 "google.golang.org/protobuf/proto"
18 preg "google.golang.org/protobuf/reflect/protoregistry"
Herbie Ong7b828bc2019-02-08 19:56:24 -080019
Joe Tsai94e730b2020-01-10 23:31:25 -080020 pb2 "google.golang.org/protobuf/internal/testprotos/textpb2"
21 pb3 "google.golang.org/protobuf/internal/testprotos/textpb3"
Joe Tsaia95b29f2019-05-16 12:47:20 -070022 "google.golang.org/protobuf/types/known/anypb"
23 "google.golang.org/protobuf/types/known/durationpb"
24 "google.golang.org/protobuf/types/known/emptypb"
25 "google.golang.org/protobuf/types/known/fieldmaskpb"
26 "google.golang.org/protobuf/types/known/structpb"
27 "google.golang.org/protobuf/types/known/timestamppb"
28 "google.golang.org/protobuf/types/known/wrapperspb"
Herbie Ong7b828bc2019-02-08 19:56:24 -080029)
30
Herbie Ong582ab3d2019-09-06 15:56:09 -070031// Disable detrand to enable direct comparisons on outputs.
32func init() { detrand.Disable() }
33
Herbie Ong7b828bc2019-02-08 19:56:24 -080034func TestMarshal(t *testing.T) {
35 tests := []struct {
Herbie Ong0b0f4032019-03-18 19:06:15 -070036 desc string
Damien Neil5c5b5312019-05-14 12:44:37 -070037 mo protojson.MarshalOptions
Herbie Ong0b0f4032019-03-18 19:06:15 -070038 input proto.Message
39 want string
40 wantErr bool // TODO: Verify error message substring.
Joe Tsai5ae10aa2019-07-11 18:23:08 -070041 skip bool
Herbie Ong7b828bc2019-02-08 19:56:24 -080042 }{{
43 desc: "proto2 optional scalars not set",
44 input: &pb2.Scalars{},
45 want: "{}",
46 }, {
47 desc: "proto3 scalars not set",
48 input: &pb3.Scalars{},
49 want: "{}",
50 }, {
51 desc: "proto2 optional scalars set to zero values",
52 input: &pb2.Scalars{
Damien Neila8a2cea2019-07-10 16:17:16 -070053 OptBool: proto.Bool(false),
54 OptInt32: proto.Int32(0),
55 OptInt64: proto.Int64(0),
56 OptUint32: proto.Uint32(0),
57 OptUint64: proto.Uint64(0),
58 OptSint32: proto.Int32(0),
59 OptSint64: proto.Int64(0),
60 OptFixed32: proto.Uint32(0),
61 OptFixed64: proto.Uint64(0),
62 OptSfixed32: proto.Int32(0),
63 OptSfixed64: proto.Int64(0),
64 OptFloat: proto.Float32(0),
65 OptDouble: proto.Float64(0),
Herbie Ong7b828bc2019-02-08 19:56:24 -080066 OptBytes: []byte{},
Damien Neila8a2cea2019-07-10 16:17:16 -070067 OptString: proto.String(""),
Herbie Ong7b828bc2019-02-08 19:56:24 -080068 },
69 want: `{
70 "optBool": false,
71 "optInt32": 0,
72 "optInt64": "0",
73 "optUint32": 0,
74 "optUint64": "0",
75 "optSint32": 0,
76 "optSint64": "0",
77 "optFixed32": 0,
78 "optFixed64": "0",
79 "optSfixed32": 0,
80 "optSfixed64": "0",
81 "optFloat": 0,
82 "optDouble": 0,
83 "optBytes": "",
84 "optString": ""
85}`,
86 }, {
87 desc: "proto2 optional scalars set to some values",
88 input: &pb2.Scalars{
Damien Neila8a2cea2019-07-10 16:17:16 -070089 OptBool: proto.Bool(true),
90 OptInt32: proto.Int32(0xff),
91 OptInt64: proto.Int64(0xdeadbeef),
92 OptUint32: proto.Uint32(47),
93 OptUint64: proto.Uint64(0xdeadbeef),
94 OptSint32: proto.Int32(-1001),
95 OptSint64: proto.Int64(-0xffff),
96 OptFixed64: proto.Uint64(64),
97 OptSfixed32: proto.Int32(-32),
98 OptFloat: proto.Float32(1.02),
99 OptDouble: proto.Float64(1.234),
Herbie Ong87608a72019-03-06 14:32:24 -0800100 OptBytes: []byte("谷歌"),
Damien Neila8a2cea2019-07-10 16:17:16 -0700101 OptString: proto.String("谷歌"),
Herbie Ong7b828bc2019-02-08 19:56:24 -0800102 },
103 want: `{
104 "optBool": true,
105 "optInt32": 255,
106 "optInt64": "3735928559",
107 "optUint32": 47,
108 "optUint64": "3735928559",
109 "optSint32": -1001,
110 "optSint64": "-65535",
111 "optFixed64": "64",
112 "optSfixed32": -32,
113 "optFloat": 1.02,
114 "optDouble": 1.234,
115 "optBytes": "6LC35q2M",
116 "optString": "谷歌"
117}`,
118 }, {
Herbie Ong0b0f4032019-03-18 19:06:15 -0700119 desc: "string",
120 input: &pb3.Scalars{
121 SString: "谷歌",
122 },
123 want: `{
124 "sString": "谷歌"
125}`,
126 }, {
127 desc: "string with invalid UTF8",
128 input: &pb3.Scalars{
129 SString: "abc\xff",
130 },
Herbie Ong0b0f4032019-03-18 19:06:15 -0700131 wantErr: true,
132 }, {
Herbie Ong7b828bc2019-02-08 19:56:24 -0800133 desc: "float nan",
134 input: &pb3.Scalars{
135 SFloat: float32(math.NaN()),
136 },
137 want: `{
138 "sFloat": "NaN"
139}`,
140 }, {
141 desc: "float positive infinity",
142 input: &pb3.Scalars{
143 SFloat: float32(math.Inf(1)),
144 },
145 want: `{
146 "sFloat": "Infinity"
147}`,
148 }, {
149 desc: "float negative infinity",
150 input: &pb3.Scalars{
151 SFloat: float32(math.Inf(-1)),
152 },
153 want: `{
154 "sFloat": "-Infinity"
155}`,
156 }, {
157 desc: "double nan",
158 input: &pb3.Scalars{
159 SDouble: math.NaN(),
160 },
161 want: `{
162 "sDouble": "NaN"
163}`,
164 }, {
165 desc: "double positive infinity",
166 input: &pb3.Scalars{
167 SDouble: math.Inf(1),
168 },
169 want: `{
170 "sDouble": "Infinity"
171}`,
172 }, {
173 desc: "double negative infinity",
174 input: &pb3.Scalars{
175 SDouble: math.Inf(-1),
176 },
177 want: `{
178 "sDouble": "-Infinity"
179}`,
180 }, {
181 desc: "proto2 enum not set",
182 input: &pb2.Enums{},
183 want: "{}",
184 }, {
185 desc: "proto2 enum set to zero value",
186 input: &pb2.Enums{
Joe Tsai6dc168e2019-07-09 23:11:13 -0700187 OptEnum: pb2.Enum(0).Enum(),
188 OptNestedEnum: pb2.Enums_NestedEnum(0).Enum(),
Herbie Ong7b828bc2019-02-08 19:56:24 -0800189 },
190 want: `{
191 "optEnum": 0,
192 "optNestedEnum": 0
193}`,
194 }, {
195 desc: "proto2 enum",
196 input: &pb2.Enums{
197 OptEnum: pb2.Enum_ONE.Enum(),
198 OptNestedEnum: pb2.Enums_UNO.Enum(),
199 },
200 want: `{
201 "optEnum": "ONE",
202 "optNestedEnum": "UNO"
203}`,
204 }, {
205 desc: "proto2 enum set to numeric values",
206 input: &pb2.Enums{
Joe Tsai6dc168e2019-07-09 23:11:13 -0700207 OptEnum: pb2.Enum(2).Enum(),
208 OptNestedEnum: pb2.Enums_NestedEnum(2).Enum(),
Herbie Ong7b828bc2019-02-08 19:56:24 -0800209 },
210 want: `{
211 "optEnum": "TWO",
212 "optNestedEnum": "DOS"
213}`,
214 }, {
215 desc: "proto2 enum set to unnamed numeric values",
216 input: &pb2.Enums{
Joe Tsai6dc168e2019-07-09 23:11:13 -0700217 OptEnum: pb2.Enum(101).Enum(),
218 OptNestedEnum: pb2.Enums_NestedEnum(-101).Enum(),
Herbie Ong7b828bc2019-02-08 19:56:24 -0800219 },
220 want: `{
221 "optEnum": 101,
222 "optNestedEnum": -101
223}`,
224 }, {
225 desc: "proto3 enum not set",
226 input: &pb3.Enums{},
227 want: "{}",
228 }, {
229 desc: "proto3 enum set to zero value",
230 input: &pb3.Enums{
231 SEnum: pb3.Enum_ZERO,
232 SNestedEnum: pb3.Enums_CERO,
233 },
234 want: "{}",
235 }, {
236 desc: "proto3 enum",
237 input: &pb3.Enums{
238 SEnum: pb3.Enum_ONE,
239 SNestedEnum: pb3.Enums_UNO,
240 },
241 want: `{
242 "sEnum": "ONE",
243 "sNestedEnum": "UNO"
244}`,
245 }, {
246 desc: "proto3 enum set to numeric values",
247 input: &pb3.Enums{
248 SEnum: 2,
249 SNestedEnum: 2,
250 },
251 want: `{
252 "sEnum": "TWO",
253 "sNestedEnum": "DOS"
254}`,
255 }, {
256 desc: "proto3 enum set to unnamed numeric values",
257 input: &pb3.Enums{
258 SEnum: -47,
259 SNestedEnum: 47,
260 },
261 want: `{
262 "sEnum": -47,
263 "sNestedEnum": 47
264}`,
265 }, {
266 desc: "proto2 nested message not set",
267 input: &pb2.Nests{},
268 want: "{}",
269 }, {
270 desc: "proto2 nested message set to empty",
271 input: &pb2.Nests{
272 OptNested: &pb2.Nested{},
273 Optgroup: &pb2.Nests_OptGroup{},
274 },
275 want: `{
276 "optNested": {},
277 "optgroup": {}
278}`,
279 }, {
280 desc: "proto2 nested messages",
281 input: &pb2.Nests{
282 OptNested: &pb2.Nested{
Damien Neila8a2cea2019-07-10 16:17:16 -0700283 OptString: proto.String("nested message"),
Herbie Ong7b828bc2019-02-08 19:56:24 -0800284 OptNested: &pb2.Nested{
Damien Neila8a2cea2019-07-10 16:17:16 -0700285 OptString: proto.String("another nested message"),
Herbie Ong7b828bc2019-02-08 19:56:24 -0800286 },
287 },
288 },
289 want: `{
290 "optNested": {
291 "optString": "nested message",
292 "optNested": {
293 "optString": "another nested message"
294 }
295 }
296}`,
297 }, {
298 desc: "proto2 groups",
299 input: &pb2.Nests{
300 Optgroup: &pb2.Nests_OptGroup{
Damien Neila8a2cea2019-07-10 16:17:16 -0700301 OptString: proto.String("inside a group"),
Herbie Ong7b828bc2019-02-08 19:56:24 -0800302 OptNested: &pb2.Nested{
Damien Neila8a2cea2019-07-10 16:17:16 -0700303 OptString: proto.String("nested message inside a group"),
Herbie Ong7b828bc2019-02-08 19:56:24 -0800304 },
305 Optnestedgroup: &pb2.Nests_OptGroup_OptNestedGroup{
Damien Neila8a2cea2019-07-10 16:17:16 -0700306 OptFixed32: proto.Uint32(47),
Herbie Ong7b828bc2019-02-08 19:56:24 -0800307 },
308 },
309 },
310 want: `{
311 "optgroup": {
312 "optString": "inside a group",
313 "optNested": {
314 "optString": "nested message inside a group"
315 },
316 "optnestedgroup": {
317 "optFixed32": 47
318 }
319 }
320}`,
321 }, {
322 desc: "proto3 nested message not set",
323 input: &pb3.Nests{},
324 want: "{}",
325 }, {
326 desc: "proto3 nested message set to empty",
327 input: &pb3.Nests{
328 SNested: &pb3.Nested{},
329 },
330 want: `{
331 "sNested": {}
332}`,
333 }, {
334 desc: "proto3 nested message",
335 input: &pb3.Nests{
336 SNested: &pb3.Nested{
337 SString: "nested message",
338 SNested: &pb3.Nested{
339 SString: "another nested message",
340 },
341 },
342 },
343 want: `{
344 "sNested": {
345 "sString": "nested message",
346 "sNested": {
347 "sString": "another nested message"
348 }
349 }
350}`,
351 }, {
352 desc: "oneof not set",
353 input: &pb3.Oneofs{},
354 want: "{}",
355 }, {
356 desc: "oneof set to empty string",
357 input: &pb3.Oneofs{
358 Union: &pb3.Oneofs_OneofString{},
359 },
360 want: `{
361 "oneofString": ""
362}`,
363 }, {
364 desc: "oneof set to string",
365 input: &pb3.Oneofs{
366 Union: &pb3.Oneofs_OneofString{
367 OneofString: "hello",
368 },
369 },
370 want: `{
371 "oneofString": "hello"
372}`,
373 }, {
374 desc: "oneof set to enum",
375 input: &pb3.Oneofs{
376 Union: &pb3.Oneofs_OneofEnum{
377 OneofEnum: pb3.Enum_ZERO,
378 },
379 },
380 want: `{
381 "oneofEnum": "ZERO"
382}`,
383 }, {
384 desc: "oneof set to empty message",
385 input: &pb3.Oneofs{
386 Union: &pb3.Oneofs_OneofNested{
387 OneofNested: &pb3.Nested{},
388 },
389 },
390 want: `{
391 "oneofNested": {}
392}`,
393 }, {
394 desc: "oneof set to message",
395 input: &pb3.Oneofs{
396 Union: &pb3.Oneofs_OneofNested{
397 OneofNested: &pb3.Nested{
398 SString: "nested message",
399 },
400 },
401 },
402 want: `{
403 "oneofNested": {
404 "sString": "nested message"
405 }
406}`,
407 }, {
408 desc: "repeated fields not set",
409 input: &pb2.Repeats{},
410 want: "{}",
411 }, {
412 desc: "repeated fields set to empty slices",
413 input: &pb2.Repeats{
414 RptBool: []bool{},
415 RptInt32: []int32{},
416 RptInt64: []int64{},
417 RptUint32: []uint32{},
418 RptUint64: []uint64{},
419 RptFloat: []float32{},
420 RptDouble: []float64{},
421 RptBytes: [][]byte{},
422 },
423 want: "{}",
424 }, {
425 desc: "repeated fields set to some values",
426 input: &pb2.Repeats{
427 RptBool: []bool{true, false, true, true},
428 RptInt32: []int32{1, 6, 0, 0},
429 RptInt64: []int64{-64, 47},
430 RptUint32: []uint32{0xff, 0xffff},
431 RptUint64: []uint64{0xdeadbeef},
432 RptFloat: []float32{float32(math.NaN()), float32(math.Inf(1)), float32(math.Inf(-1)), 1.034},
433 RptDouble: []float64{math.NaN(), math.Inf(1), math.Inf(-1), 1.23e-308},
434 RptString: []string{"hello", "世界"},
435 RptBytes: [][]byte{
436 []byte("hello"),
437 []byte("\xe4\xb8\x96\xe7\x95\x8c"),
438 },
439 },
440 want: `{
441 "rptBool": [
442 true,
443 false,
444 true,
445 true
446 ],
447 "rptInt32": [
448 1,
449 6,
450 0,
451 0
452 ],
453 "rptInt64": [
454 "-64",
455 "47"
456 ],
457 "rptUint32": [
458 255,
459 65535
460 ],
461 "rptUint64": [
462 "3735928559"
463 ],
464 "rptFloat": [
465 "NaN",
466 "Infinity",
467 "-Infinity",
468 1.034
469 ],
470 "rptDouble": [
471 "NaN",
472 "Infinity",
473 "-Infinity",
474 1.23e-308
475 ],
476 "rptString": [
477 "hello",
478 "世界"
479 ],
480 "rptBytes": [
481 "aGVsbG8=",
482 "5LiW55WM"
483 ]
484}`,
485 }, {
486 desc: "repeated enums",
487 input: &pb2.Enums{
488 RptEnum: []pb2.Enum{pb2.Enum_ONE, 2, pb2.Enum_TEN, 42},
489 RptNestedEnum: []pb2.Enums_NestedEnum{2, 47, 10},
490 },
491 want: `{
492 "rptEnum": [
493 "ONE",
494 "TWO",
495 "TEN",
496 42
497 ],
498 "rptNestedEnum": [
499 "DOS",
500 47,
501 "DIEZ"
502 ]
503}`,
504 }, {
505 desc: "repeated messages set to empty",
506 input: &pb2.Nests{
507 RptNested: []*pb2.Nested{},
508 Rptgroup: []*pb2.Nests_RptGroup{},
509 },
510 want: "{}",
511 }, {
512 desc: "repeated messages",
513 input: &pb2.Nests{
514 RptNested: []*pb2.Nested{
515 {
Damien Neila8a2cea2019-07-10 16:17:16 -0700516 OptString: proto.String("repeat nested one"),
Herbie Ong7b828bc2019-02-08 19:56:24 -0800517 },
518 {
Damien Neila8a2cea2019-07-10 16:17:16 -0700519 OptString: proto.String("repeat nested two"),
Herbie Ong7b828bc2019-02-08 19:56:24 -0800520 OptNested: &pb2.Nested{
Damien Neila8a2cea2019-07-10 16:17:16 -0700521 OptString: proto.String("inside repeat nested two"),
Herbie Ong7b828bc2019-02-08 19:56:24 -0800522 },
523 },
524 {},
525 },
526 },
527 want: `{
528 "rptNested": [
529 {
530 "optString": "repeat nested one"
531 },
532 {
533 "optString": "repeat nested two",
534 "optNested": {
535 "optString": "inside repeat nested two"
536 }
537 },
538 {}
539 ]
540}`,
541 }, {
542 desc: "repeated messages contains nil value",
543 input: &pb2.Nests{
544 RptNested: []*pb2.Nested{nil, {}},
545 },
546 want: `{
547 "rptNested": [
548 {},
549 {}
550 ]
551}`,
552 }, {
553 desc: "repeated groups",
554 input: &pb2.Nests{
555 Rptgroup: []*pb2.Nests_RptGroup{
556 {
557 RptString: []string{"hello", "world"},
558 },
559 {},
560 nil,
561 },
562 },
563 want: `{
564 "rptgroup": [
565 {
566 "rptString": [
567 "hello",
568 "world"
569 ]
570 },
571 {},
572 {}
573 ]
574}`,
575 }, {
576 desc: "map fields not set",
577 input: &pb3.Maps{},
578 want: "{}",
579 }, {
580 desc: "map fields set to empty",
581 input: &pb3.Maps{
582 Int32ToStr: map[int32]string{},
583 BoolToUint32: map[bool]uint32{},
584 Uint64ToEnum: map[uint64]pb3.Enum{},
585 StrToNested: map[string]*pb3.Nested{},
586 StrToOneofs: map[string]*pb3.Oneofs{},
587 },
588 want: "{}",
589 }, {
590 desc: "map fields 1",
591 input: &pb3.Maps{
592 BoolToUint32: map[bool]uint32{
593 true: 42,
594 false: 101,
595 },
596 },
597 want: `{
598 "boolToUint32": {
599 "false": 101,
600 "true": 42
601 }
602}`,
603 }, {
604 desc: "map fields 2",
605 input: &pb3.Maps{
606 Int32ToStr: map[int32]string{
607 -101: "-101",
608 0xff: "0xff",
609 0: "zero",
610 },
611 },
612 want: `{
613 "int32ToStr": {
614 "-101": "-101",
615 "0": "zero",
616 "255": "0xff"
617 }
618}`,
619 }, {
620 desc: "map fields 3",
621 input: &pb3.Maps{
622 Uint64ToEnum: map[uint64]pb3.Enum{
623 1: pb3.Enum_ONE,
624 2: pb3.Enum_TWO,
625 10: pb3.Enum_TEN,
626 47: 47,
627 },
628 },
629 want: `{
630 "uint64ToEnum": {
631 "1": "ONE",
632 "2": "TWO",
633 "10": "TEN",
634 "47": 47
635 }
636}`,
637 }, {
638 desc: "map fields 4",
639 input: &pb3.Maps{
640 StrToNested: map[string]*pb3.Nested{
641 "nested": &pb3.Nested{
642 SString: "nested in a map",
643 },
644 },
645 },
646 want: `{
647 "strToNested": {
648 "nested": {
649 "sString": "nested in a map"
650 }
651 }
652}`,
653 }, {
654 desc: "map fields 5",
655 input: &pb3.Maps{
656 StrToOneofs: map[string]*pb3.Oneofs{
657 "string": &pb3.Oneofs{
658 Union: &pb3.Oneofs_OneofString{
659 OneofString: "hello",
660 },
661 },
662 "nested": &pb3.Oneofs{
663 Union: &pb3.Oneofs_OneofNested{
664 OneofNested: &pb3.Nested{
665 SString: "nested oneof in map field value",
666 },
667 },
668 },
669 },
670 },
671 want: `{
672 "strToOneofs": {
673 "nested": {
674 "oneofNested": {
675 "sString": "nested oneof in map field value"
676 }
677 },
678 "string": {
679 "oneofString": "hello"
680 }
681 }
682}`,
683 }, {
684 desc: "map field contains nil value",
685 input: &pb3.Maps{
686 StrToNested: map[string]*pb3.Nested{
687 "nil": nil,
688 },
689 },
690 want: `{
691 "strToNested": {
692 "nil": {}
693 }
694}`,
695 }, {
Herbie Ong329be5b2019-03-27 14:47:59 -0700696 desc: "required fields not set",
697 input: &pb2.Requireds{},
698 want: `{}`,
699 wantErr: true,
700 }, {
701 desc: "required fields partially set",
702 input: &pb2.Requireds{
Damien Neila8a2cea2019-07-10 16:17:16 -0700703 ReqBool: proto.Bool(false),
704 ReqSfixed64: proto.Int64(0),
705 ReqDouble: proto.Float64(1.23),
706 ReqString: proto.String("hello"),
Herbie Ong329be5b2019-03-27 14:47:59 -0700707 ReqEnum: pb2.Enum_ONE.Enum(),
708 },
709 want: `{
710 "reqBool": false,
711 "reqSfixed64": "0",
712 "reqDouble": 1.23,
713 "reqString": "hello",
714 "reqEnum": "ONE"
715}`,
716 wantErr: true,
717 }, {
718 desc: "required fields not set with AllowPartial",
Damien Neil5c5b5312019-05-14 12:44:37 -0700719 mo: protojson.MarshalOptions{AllowPartial: true},
Herbie Ong329be5b2019-03-27 14:47:59 -0700720 input: &pb2.Requireds{
Damien Neila8a2cea2019-07-10 16:17:16 -0700721 ReqBool: proto.Bool(false),
722 ReqSfixed64: proto.Int64(0),
723 ReqDouble: proto.Float64(1.23),
724 ReqString: proto.String("hello"),
Herbie Ong329be5b2019-03-27 14:47:59 -0700725 ReqEnum: pb2.Enum_ONE.Enum(),
726 },
727 want: `{
728 "reqBool": false,
729 "reqSfixed64": "0",
730 "reqDouble": 1.23,
731 "reqString": "hello",
732 "reqEnum": "ONE"
733}`,
734 }, {
735 desc: "required fields all set",
736 input: &pb2.Requireds{
Damien Neila8a2cea2019-07-10 16:17:16 -0700737 ReqBool: proto.Bool(false),
738 ReqSfixed64: proto.Int64(0),
739 ReqDouble: proto.Float64(1.23),
740 ReqString: proto.String("hello"),
Herbie Ong329be5b2019-03-27 14:47:59 -0700741 ReqEnum: pb2.Enum_ONE.Enum(),
742 ReqNested: &pb2.Nested{},
743 },
744 want: `{
745 "reqBool": false,
746 "reqSfixed64": "0",
747 "reqDouble": 1.23,
748 "reqString": "hello",
749 "reqEnum": "ONE",
750 "reqNested": {}
751}`,
752 }, {
753 desc: "indirect required field",
754 input: &pb2.IndirectRequired{
755 OptNested: &pb2.NestedWithRequired{},
756 },
757 want: `{
758 "optNested": {}
759}`,
760 wantErr: true,
761 }, {
762 desc: "indirect required field with AllowPartial",
Damien Neil5c5b5312019-05-14 12:44:37 -0700763 mo: protojson.MarshalOptions{AllowPartial: true},
Herbie Ong329be5b2019-03-27 14:47:59 -0700764 input: &pb2.IndirectRequired{
765 OptNested: &pb2.NestedWithRequired{},
766 },
767 want: `{
768 "optNested": {}
769}`,
770 }, {
771 desc: "indirect required field in empty repeated",
772 input: &pb2.IndirectRequired{
773 RptNested: []*pb2.NestedWithRequired{},
774 },
775 want: `{}`,
776 }, {
777 desc: "indirect required field in repeated",
778 input: &pb2.IndirectRequired{
779 RptNested: []*pb2.NestedWithRequired{
780 &pb2.NestedWithRequired{},
781 },
782 },
783 want: `{
784 "rptNested": [
785 {}
786 ]
787}`,
788 wantErr: true,
789 }, {
790 desc: "indirect required field in repeated with AllowPartial",
Damien Neil5c5b5312019-05-14 12:44:37 -0700791 mo: protojson.MarshalOptions{AllowPartial: true},
Herbie Ong329be5b2019-03-27 14:47:59 -0700792 input: &pb2.IndirectRequired{
793 RptNested: []*pb2.NestedWithRequired{
794 &pb2.NestedWithRequired{},
795 },
796 },
797 want: `{
798 "rptNested": [
799 {}
800 ]
801}`,
802 }, {
803 desc: "indirect required field in empty map",
804 input: &pb2.IndirectRequired{
805 StrToNested: map[string]*pb2.NestedWithRequired{},
806 },
807 want: "{}",
808 }, {
809 desc: "indirect required field in map",
810 input: &pb2.IndirectRequired{
811 StrToNested: map[string]*pb2.NestedWithRequired{
812 "fail": &pb2.NestedWithRequired{},
813 },
814 },
815 want: `{
816 "strToNested": {
817 "fail": {}
818 }
819}`,
820 wantErr: true,
821 }, {
822 desc: "indirect required field in map with AllowPartial",
Damien Neil5c5b5312019-05-14 12:44:37 -0700823 mo: protojson.MarshalOptions{AllowPartial: true},
Herbie Ong329be5b2019-03-27 14:47:59 -0700824 input: &pb2.IndirectRequired{
825 StrToNested: map[string]*pb2.NestedWithRequired{
826 "fail": &pb2.NestedWithRequired{},
827 },
828 },
829 want: `{
830 "strToNested": {
831 "fail": {}
832 }
833}`,
834 }, {
835 desc: "indirect required field in oneof",
836 input: &pb2.IndirectRequired{
837 Union: &pb2.IndirectRequired_OneofNested{
838 OneofNested: &pb2.NestedWithRequired{},
839 },
840 },
841 want: `{
842 "oneofNested": {}
843}`,
844 wantErr: true,
845 }, {
846 desc: "indirect required field in oneof with AllowPartial",
Damien Neil5c5b5312019-05-14 12:44:37 -0700847 mo: protojson.MarshalOptions{AllowPartial: true},
Herbie Ong329be5b2019-03-27 14:47:59 -0700848 input: &pb2.IndirectRequired{
849 Union: &pb2.IndirectRequired_OneofNested{
850 OneofNested: &pb2.NestedWithRequired{},
851 },
852 },
853 want: `{
854 "oneofNested": {}
855}`,
856 }, {
Herbie Ong7b828bc2019-02-08 19:56:24 -0800857 desc: "unknown fields are ignored",
Joe Tsai28216c72019-06-22 13:20:09 -0700858 input: func() proto.Message {
859 m := &pb2.Scalars{
Damien Neila8a2cea2019-07-10 16:17:16 -0700860 OptString: proto.String("no unknowns"),
Joe Tsai28216c72019-06-22 13:20:09 -0700861 }
862 m.ProtoReflect().SetUnknown(pack.Message{
Herbie Ong7b828bc2019-02-08 19:56:24 -0800863 pack.Tag{101, pack.BytesType}, pack.String("hello world"),
Joe Tsai28216c72019-06-22 13:20:09 -0700864 }.Marshal())
865 return m
866 }(),
Herbie Ong7b828bc2019-02-08 19:56:24 -0800867 want: `{
868 "optString": "no unknowns"
869}`,
870 }, {
871 desc: "json_name",
872 input: &pb3.JSONNames{
873 SString: "json_name",
874 },
875 want: `{
876 "foo_bar": "json_name"
877}`,
Herbie Ongf83d5bb2019-03-14 00:01:27 -0700878 }, {
879 desc: "extensions of non-repeated fields",
880 input: func() proto.Message {
881 m := &pb2.Extensions{
Damien Neila8a2cea2019-07-10 16:17:16 -0700882 OptString: proto.String("non-extension field"),
883 OptBool: proto.Bool(true),
884 OptInt32: proto.Int32(42),
Herbie Ongf83d5bb2019-03-14 00:01:27 -0700885 }
Damien Neil92f76182019-08-02 16:58:08 -0700886 proto.SetExtension(m, pb2.E_OptExtBool, true)
887 proto.SetExtension(m, pb2.E_OptExtString, "extension field")
888 proto.SetExtension(m, pb2.E_OptExtEnum, pb2.Enum_TEN)
889 proto.SetExtension(m, pb2.E_OptExtNested, &pb2.Nested{
Damien Neila8a2cea2019-07-10 16:17:16 -0700890 OptString: proto.String("nested in an extension"),
Herbie Ongf83d5bb2019-03-14 00:01:27 -0700891 OptNested: &pb2.Nested{
Damien Neila8a2cea2019-07-10 16:17:16 -0700892 OptString: proto.String("another nested in an extension"),
Herbie Ongf83d5bb2019-03-14 00:01:27 -0700893 },
894 })
895 return m
896 }(),
897 want: `{
898 "optString": "non-extension field",
899 "optBool": true,
900 "optInt32": 42,
901 "[pb2.opt_ext_bool]": true,
902 "[pb2.opt_ext_enum]": "TEN",
903 "[pb2.opt_ext_nested]": {
904 "optString": "nested in an extension",
905 "optNested": {
906 "optString": "another nested in an extension"
907 }
908 },
909 "[pb2.opt_ext_string]": "extension field"
910}`,
911 }, {
Herbie Ongf83d5bb2019-03-14 00:01:27 -0700912 desc: "extensions of repeated fields",
913 input: func() proto.Message {
914 m := &pb2.Extensions{}
Damien Neil293dc762019-08-29 11:42:57 -0700915 proto.SetExtension(m, pb2.E_RptExtEnum, []pb2.Enum{pb2.Enum_TEN, 101, pb2.Enum_ONE})
916 proto.SetExtension(m, pb2.E_RptExtFixed32, []uint32{42, 47})
917 proto.SetExtension(m, pb2.E_RptExtNested, []*pb2.Nested{
Damien Neila8a2cea2019-07-10 16:17:16 -0700918 &pb2.Nested{OptString: proto.String("one")},
919 &pb2.Nested{OptString: proto.String("two")},
920 &pb2.Nested{OptString: proto.String("three")},
Herbie Ongf83d5bb2019-03-14 00:01:27 -0700921 })
922 return m
923 }(),
924 want: `{
925 "[pb2.rpt_ext_enum]": [
926 "TEN",
927 101,
928 "ONE"
929 ],
930 "[pb2.rpt_ext_fixed32]": [
931 42,
932 47
933 ],
934 "[pb2.rpt_ext_nested]": [
935 {
936 "optString": "one"
937 },
938 {
939 "optString": "two"
940 },
941 {
942 "optString": "three"
943 }
944 ]
945}`,
946 }, {
947 desc: "extensions of non-repeated fields in another message",
948 input: func() proto.Message {
949 m := &pb2.Extensions{}
Damien Neil92f76182019-08-02 16:58:08 -0700950 proto.SetExtension(m, pb2.E_ExtensionsContainer_OptExtBool, true)
951 proto.SetExtension(m, pb2.E_ExtensionsContainer_OptExtString, "extension field")
952 proto.SetExtension(m, pb2.E_ExtensionsContainer_OptExtEnum, pb2.Enum_TEN)
953 proto.SetExtension(m, pb2.E_ExtensionsContainer_OptExtNested, &pb2.Nested{
Damien Neila8a2cea2019-07-10 16:17:16 -0700954 OptString: proto.String("nested in an extension"),
Herbie Ongf83d5bb2019-03-14 00:01:27 -0700955 OptNested: &pb2.Nested{
Damien Neila8a2cea2019-07-10 16:17:16 -0700956 OptString: proto.String("another nested in an extension"),
Herbie Ongf83d5bb2019-03-14 00:01:27 -0700957 },
958 })
959 return m
960 }(),
961 want: `{
962 "[pb2.ExtensionsContainer.opt_ext_bool]": true,
963 "[pb2.ExtensionsContainer.opt_ext_enum]": "TEN",
964 "[pb2.ExtensionsContainer.opt_ext_nested]": {
965 "optString": "nested in an extension",
966 "optNested": {
967 "optString": "another nested in an extension"
968 }
969 },
970 "[pb2.ExtensionsContainer.opt_ext_string]": "extension field"
971}`,
972 }, {
973 desc: "extensions of repeated fields in another message",
974 input: func() proto.Message {
975 m := &pb2.Extensions{
Damien Neila8a2cea2019-07-10 16:17:16 -0700976 OptString: proto.String("non-extension field"),
977 OptBool: proto.Bool(true),
978 OptInt32: proto.Int32(42),
Herbie Ongf83d5bb2019-03-14 00:01:27 -0700979 }
Damien Neil293dc762019-08-29 11:42:57 -0700980 proto.SetExtension(m, pb2.E_ExtensionsContainer_RptExtEnum, []pb2.Enum{pb2.Enum_TEN, 101, pb2.Enum_ONE})
981 proto.SetExtension(m, pb2.E_ExtensionsContainer_RptExtString, []string{"hello", "world"})
982 proto.SetExtension(m, pb2.E_ExtensionsContainer_RptExtNested, []*pb2.Nested{
Damien Neila8a2cea2019-07-10 16:17:16 -0700983 &pb2.Nested{OptString: proto.String("one")},
984 &pb2.Nested{OptString: proto.String("two")},
985 &pb2.Nested{OptString: proto.String("three")},
Herbie Ongf83d5bb2019-03-14 00:01:27 -0700986 })
987 return m
988 }(),
989 want: `{
990 "optString": "non-extension field",
991 "optBool": true,
992 "optInt32": 42,
993 "[pb2.ExtensionsContainer.rpt_ext_enum]": [
994 "TEN",
995 101,
996 "ONE"
997 ],
998 "[pb2.ExtensionsContainer.rpt_ext_nested]": [
999 {
1000 "optString": "one"
1001 },
1002 {
1003 "optString": "two"
1004 },
1005 {
1006 "optString": "three"
1007 }
1008 ],
1009 "[pb2.ExtensionsContainer.rpt_ext_string]": [
1010 "hello",
1011 "world"
1012 ]
1013}`,
1014 }, {
1015 desc: "MessageSet",
1016 input: func() proto.Message {
1017 m := &pb2.MessageSet{}
Damien Neil92f76182019-08-02 16:58:08 -07001018 proto.SetExtension(m, pb2.E_MessageSetExtension_MessageSetExtension, &pb2.MessageSetExtension{
Damien Neila8a2cea2019-07-10 16:17:16 -07001019 OptString: proto.String("a messageset extension"),
Herbie Ongf83d5bb2019-03-14 00:01:27 -07001020 })
Damien Neil92f76182019-08-02 16:58:08 -07001021 proto.SetExtension(m, pb2.E_MessageSetExtension_NotMessageSetExtension, &pb2.MessageSetExtension{
Damien Neila8a2cea2019-07-10 16:17:16 -07001022 OptString: proto.String("not a messageset extension"),
Herbie Ongf83d5bb2019-03-14 00:01:27 -07001023 })
Damien Neil92f76182019-08-02 16:58:08 -07001024 proto.SetExtension(m, pb2.E_MessageSetExtension_ExtNested, &pb2.Nested{
Damien Neila8a2cea2019-07-10 16:17:16 -07001025 OptString: proto.String("just a regular extension"),
Herbie Ongf83d5bb2019-03-14 00:01:27 -07001026 })
1027 return m
1028 }(),
1029 want: `{
1030 "[pb2.MessageSetExtension]": {
1031 "optString": "a messageset extension"
1032 },
1033 "[pb2.MessageSetExtension.ext_nested]": {
1034 "optString": "just a regular extension"
1035 },
1036 "[pb2.MessageSetExtension.not_message_set_extension]": {
1037 "optString": "not a messageset extension"
1038 }
1039}`,
Joe Tsai1799d112019-08-08 13:31:59 -07001040 skip: !flags.ProtoLegacy,
Herbie Ongf83d5bb2019-03-14 00:01:27 -07001041 }, {
1042 desc: "not real MessageSet 1",
1043 input: func() proto.Message {
1044 m := &pb2.FakeMessageSet{}
Damien Neil92f76182019-08-02 16:58:08 -07001045 proto.SetExtension(m, pb2.E_FakeMessageSetExtension_MessageSetExtension, &pb2.FakeMessageSetExtension{
Damien Neila8a2cea2019-07-10 16:17:16 -07001046 OptString: proto.String("not a messageset extension"),
Herbie Ongf83d5bb2019-03-14 00:01:27 -07001047 })
1048 return m
1049 }(),
1050 want: `{
1051 "[pb2.FakeMessageSetExtension.message_set_extension]": {
1052 "optString": "not a messageset extension"
1053 }
1054}`,
Joe Tsai1799d112019-08-08 13:31:59 -07001055 skip: !flags.ProtoLegacy,
Herbie Ongf83d5bb2019-03-14 00:01:27 -07001056 }, {
1057 desc: "not real MessageSet 2",
1058 input: func() proto.Message {
1059 m := &pb2.MessageSet{}
Damien Neil92f76182019-08-02 16:58:08 -07001060 proto.SetExtension(m, pb2.E_MessageSetExtension, &pb2.FakeMessageSetExtension{
Damien Neila8a2cea2019-07-10 16:17:16 -07001061 OptString: proto.String("another not a messageset extension"),
Herbie Ongf83d5bb2019-03-14 00:01:27 -07001062 })
1063 return m
1064 }(),
1065 want: `{
1066 "[pb2.message_set_extension]": {
1067 "optString": "another not a messageset extension"
1068 }
1069}`,
Joe Tsai1799d112019-08-08 13:31:59 -07001070 skip: !flags.ProtoLegacy,
Herbie Ong0b0f4032019-03-18 19:06:15 -07001071 }, {
1072 desc: "BoolValue empty",
Joe Tsaia95b29f2019-05-16 12:47:20 -07001073 input: &wrapperspb.BoolValue{},
Herbie Ong0b0f4032019-03-18 19:06:15 -07001074 want: `false`,
1075 }, {
1076 desc: "BoolValue",
Joe Tsaia95b29f2019-05-16 12:47:20 -07001077 input: &wrapperspb.BoolValue{Value: true},
Herbie Ong0b0f4032019-03-18 19:06:15 -07001078 want: `true`,
1079 }, {
1080 desc: "Int32Value empty",
Joe Tsaia95b29f2019-05-16 12:47:20 -07001081 input: &wrapperspb.Int32Value{},
Herbie Ong0b0f4032019-03-18 19:06:15 -07001082 want: `0`,
1083 }, {
1084 desc: "Int32Value",
Joe Tsaia95b29f2019-05-16 12:47:20 -07001085 input: &wrapperspb.Int32Value{Value: 42},
Herbie Ong0b0f4032019-03-18 19:06:15 -07001086 want: `42`,
1087 }, {
1088 desc: "Int64Value",
Joe Tsaia95b29f2019-05-16 12:47:20 -07001089 input: &wrapperspb.Int64Value{Value: 42},
Herbie Ong0b0f4032019-03-18 19:06:15 -07001090 want: `"42"`,
1091 }, {
1092 desc: "UInt32Value",
Joe Tsaia95b29f2019-05-16 12:47:20 -07001093 input: &wrapperspb.UInt32Value{Value: 42},
Herbie Ong0b0f4032019-03-18 19:06:15 -07001094 want: `42`,
1095 }, {
1096 desc: "UInt64Value",
Joe Tsaia95b29f2019-05-16 12:47:20 -07001097 input: &wrapperspb.UInt64Value{Value: 42},
Herbie Ong0b0f4032019-03-18 19:06:15 -07001098 want: `"42"`,
1099 }, {
1100 desc: "FloatValue",
Joe Tsaia95b29f2019-05-16 12:47:20 -07001101 input: &wrapperspb.FloatValue{Value: 1.02},
Herbie Ong0b0f4032019-03-18 19:06:15 -07001102 want: `1.02`,
1103 }, {
Herbie Onge63c4c42019-03-22 22:20:22 -07001104 desc: "FloatValue Infinity",
Joe Tsaia95b29f2019-05-16 12:47:20 -07001105 input: &wrapperspb.FloatValue{Value: float32(math.Inf(-1))},
Herbie Onge63c4c42019-03-22 22:20:22 -07001106 want: `"-Infinity"`,
1107 }, {
Herbie Ong0b0f4032019-03-18 19:06:15 -07001108 desc: "DoubleValue",
Joe Tsaia95b29f2019-05-16 12:47:20 -07001109 input: &wrapperspb.DoubleValue{Value: 1.02},
Herbie Ong0b0f4032019-03-18 19:06:15 -07001110 want: `1.02`,
1111 }, {
Herbie Onge63c4c42019-03-22 22:20:22 -07001112 desc: "DoubleValue NaN",
Joe Tsaia95b29f2019-05-16 12:47:20 -07001113 input: &wrapperspb.DoubleValue{Value: math.NaN()},
Herbie Onge63c4c42019-03-22 22:20:22 -07001114 want: `"NaN"`,
1115 }, {
Herbie Ong0b0f4032019-03-18 19:06:15 -07001116 desc: "StringValue empty",
Joe Tsaia95b29f2019-05-16 12:47:20 -07001117 input: &wrapperspb.StringValue{},
Herbie Ong0b0f4032019-03-18 19:06:15 -07001118 want: `""`,
1119 }, {
1120 desc: "StringValue",
Joe Tsaia95b29f2019-05-16 12:47:20 -07001121 input: &wrapperspb.StringValue{Value: "谷歌"},
Herbie Ong0b0f4032019-03-18 19:06:15 -07001122 want: `"谷歌"`,
1123 }, {
1124 desc: "StringValue with invalid UTF8 error",
Joe Tsaia95b29f2019-05-16 12:47:20 -07001125 input: &wrapperspb.StringValue{Value: "abc\xff"},
Herbie Ong0b0f4032019-03-18 19:06:15 -07001126 wantErr: true,
1127 }, {
1128 desc: "StringValue field with invalid UTF8 error",
1129 input: &pb2.KnownTypes{
Joe Tsaia95b29f2019-05-16 12:47:20 -07001130 OptString: &wrapperspb.StringValue{Value: "abc\xff"},
Herbie Ong0b0f4032019-03-18 19:06:15 -07001131 },
Herbie Ong0b0f4032019-03-18 19:06:15 -07001132 wantErr: true,
1133 }, {
1134 desc: "BytesValue",
Joe Tsaia95b29f2019-05-16 12:47:20 -07001135 input: &wrapperspb.BytesValue{Value: []byte("hello")},
Herbie Ong0b0f4032019-03-18 19:06:15 -07001136 want: `"aGVsbG8="`,
1137 }, {
1138 desc: "Empty",
Joe Tsaia95b29f2019-05-16 12:47:20 -07001139 input: &emptypb.Empty{},
Herbie Ong0b0f4032019-03-18 19:06:15 -07001140 want: `{}`,
1141 }, {
Herbie Ong300b9fe2019-03-29 15:42:20 -07001142 desc: "NullValue field",
Joe Tsaia95b29f2019-05-16 12:47:20 -07001143 input: &pb2.KnownTypes{OptNull: new(structpb.NullValue)},
Herbie Ong300b9fe2019-03-29 15:42:20 -07001144 want: `{
1145 "optNull": null
1146}`,
1147 }, {
Herbie Ong1c7462c2019-03-22 17:56:55 -07001148 desc: "Value empty",
Joe Tsaia95b29f2019-05-16 12:47:20 -07001149 input: &structpb.Value{},
Herbie Ong1c7462c2019-03-22 17:56:55 -07001150 wantErr: true,
Herbie Ong0b0f4032019-03-18 19:06:15 -07001151 }, {
1152 desc: "Value empty field",
1153 input: &pb2.KnownTypes{
Joe Tsaia95b29f2019-05-16 12:47:20 -07001154 OptValue: &structpb.Value{},
Herbie Ong0b0f4032019-03-18 19:06:15 -07001155 },
Herbie Ong1c7462c2019-03-22 17:56:55 -07001156 wantErr: true,
Herbie Ong0b0f4032019-03-18 19:06:15 -07001157 }, {
1158 desc: "Value contains NullValue",
Joe Tsaia95b29f2019-05-16 12:47:20 -07001159 input: &structpb.Value{Kind: &structpb.Value_NullValue{}},
Herbie Ong0b0f4032019-03-18 19:06:15 -07001160 want: `null`,
1161 }, {
1162 desc: "Value contains BoolValue",
Joe Tsaia95b29f2019-05-16 12:47:20 -07001163 input: &structpb.Value{Kind: &structpb.Value_BoolValue{}},
Herbie Ong0b0f4032019-03-18 19:06:15 -07001164 want: `false`,
1165 }, {
1166 desc: "Value contains NumberValue",
Joe Tsaia95b29f2019-05-16 12:47:20 -07001167 input: &structpb.Value{Kind: &structpb.Value_NumberValue{1.02}},
Herbie Ong0b0f4032019-03-18 19:06:15 -07001168 want: `1.02`,
1169 }, {
1170 desc: "Value contains StringValue",
Joe Tsaia95b29f2019-05-16 12:47:20 -07001171 input: &structpb.Value{Kind: &structpb.Value_StringValue{"hello"}},
Herbie Ong0b0f4032019-03-18 19:06:15 -07001172 want: `"hello"`,
1173 }, {
1174 desc: "Value contains StringValue with invalid UTF8",
Joe Tsaia95b29f2019-05-16 12:47:20 -07001175 input: &structpb.Value{Kind: &structpb.Value_StringValue{"\xff"}},
Herbie Ong0b0f4032019-03-18 19:06:15 -07001176 wantErr: true,
1177 }, {
1178 desc: "Value contains Struct",
Joe Tsaia95b29f2019-05-16 12:47:20 -07001179 input: &structpb.Value{
1180 Kind: &structpb.Value_StructValue{
1181 &structpb.Struct{
1182 Fields: map[string]*structpb.Value{
1183 "null": {Kind: &structpb.Value_NullValue{}},
1184 "number": {Kind: &structpb.Value_NumberValue{}},
1185 "string": {Kind: &structpb.Value_StringValue{}},
1186 "struct": {Kind: &structpb.Value_StructValue{}},
1187 "list": {Kind: &structpb.Value_ListValue{}},
1188 "bool": {Kind: &structpb.Value_BoolValue{}},
Herbie Ong0b0f4032019-03-18 19:06:15 -07001189 },
1190 },
1191 },
1192 },
1193 want: `{
1194 "bool": false,
1195 "list": [],
1196 "null": null,
1197 "number": 0,
1198 "string": "",
1199 "struct": {}
1200}`,
1201 }, {
1202 desc: "Value contains ListValue",
Joe Tsaia95b29f2019-05-16 12:47:20 -07001203 input: &structpb.Value{
1204 Kind: &structpb.Value_ListValue{
1205 &structpb.ListValue{
1206 Values: []*structpb.Value{
1207 {Kind: &structpb.Value_BoolValue{}},
1208 {Kind: &structpb.Value_NullValue{}},
1209 {Kind: &structpb.Value_NumberValue{}},
1210 {Kind: &structpb.Value_StringValue{}},
1211 {Kind: &structpb.Value_StructValue{}},
1212 {Kind: &structpb.Value_ListValue{}},
Herbie Ong0b0f4032019-03-18 19:06:15 -07001213 },
1214 },
1215 },
1216 },
1217 want: `[
1218 false,
1219 null,
1220 0,
1221 "",
1222 {},
1223 []
1224]`,
1225 }, {
1226 desc: "Struct with nil map",
Joe Tsaia95b29f2019-05-16 12:47:20 -07001227 input: &structpb.Struct{},
Herbie Ong0b0f4032019-03-18 19:06:15 -07001228 want: `{}`,
1229 }, {
1230 desc: "Struct with empty map",
Joe Tsaia95b29f2019-05-16 12:47:20 -07001231 input: &structpb.Struct{
1232 Fields: map[string]*structpb.Value{},
Herbie Ong0b0f4032019-03-18 19:06:15 -07001233 },
1234 want: `{}`,
1235 }, {
1236 desc: "Struct",
Joe Tsaia95b29f2019-05-16 12:47:20 -07001237 input: &structpb.Struct{
1238 Fields: map[string]*structpb.Value{
1239 "bool": {Kind: &structpb.Value_BoolValue{true}},
1240 "null": {Kind: &structpb.Value_NullValue{}},
1241 "number": {Kind: &structpb.Value_NumberValue{3.1415}},
1242 "string": {Kind: &structpb.Value_StringValue{"hello"}},
Herbie Ong0b0f4032019-03-18 19:06:15 -07001243 "struct": {
Joe Tsaia95b29f2019-05-16 12:47:20 -07001244 Kind: &structpb.Value_StructValue{
1245 &structpb.Struct{
1246 Fields: map[string]*structpb.Value{
1247 "string": {Kind: &structpb.Value_StringValue{"world"}},
Herbie Ong0b0f4032019-03-18 19:06:15 -07001248 },
1249 },
1250 },
1251 },
1252 "list": {
Joe Tsaia95b29f2019-05-16 12:47:20 -07001253 Kind: &structpb.Value_ListValue{
1254 &structpb.ListValue{
1255 Values: []*structpb.Value{
1256 {Kind: &structpb.Value_BoolValue{}},
1257 {Kind: &structpb.Value_NullValue{}},
1258 {Kind: &structpb.Value_NumberValue{}},
Herbie Ong0b0f4032019-03-18 19:06:15 -07001259 },
1260 },
1261 },
1262 },
1263 },
1264 },
1265 want: `{
1266 "bool": true,
1267 "list": [
1268 false,
1269 null,
1270 0
1271 ],
1272 "null": null,
1273 "number": 3.1415,
1274 "string": "hello",
1275 "struct": {
1276 "string": "world"
1277 }
1278}`,
1279 }, {
1280 desc: "Struct message with invalid UTF8 string",
Joe Tsaia95b29f2019-05-16 12:47:20 -07001281 input: &structpb.Struct{
1282 Fields: map[string]*structpb.Value{
1283 "string": {Kind: &structpb.Value_StringValue{"\xff"}},
Herbie Ong0b0f4032019-03-18 19:06:15 -07001284 },
1285 },
Herbie Ong0b0f4032019-03-18 19:06:15 -07001286 wantErr: true,
1287 }, {
1288 desc: "ListValue with nil values",
Joe Tsaia95b29f2019-05-16 12:47:20 -07001289 input: &structpb.ListValue{},
Herbie Ong0b0f4032019-03-18 19:06:15 -07001290 want: `[]`,
1291 }, {
1292 desc: "ListValue with empty values",
Joe Tsaia95b29f2019-05-16 12:47:20 -07001293 input: &structpb.ListValue{
1294 Values: []*structpb.Value{},
Herbie Ong0b0f4032019-03-18 19:06:15 -07001295 },
1296 want: `[]`,
1297 }, {
1298 desc: "ListValue",
Joe Tsaia95b29f2019-05-16 12:47:20 -07001299 input: &structpb.ListValue{
1300 Values: []*structpb.Value{
1301 {Kind: &structpb.Value_BoolValue{true}},
1302 {Kind: &structpb.Value_NullValue{}},
1303 {Kind: &structpb.Value_NumberValue{3.1415}},
1304 {Kind: &structpb.Value_StringValue{"hello"}},
Herbie Ong0b0f4032019-03-18 19:06:15 -07001305 {
Joe Tsaia95b29f2019-05-16 12:47:20 -07001306 Kind: &structpb.Value_ListValue{
1307 &structpb.ListValue{
1308 Values: []*structpb.Value{
1309 {Kind: &structpb.Value_BoolValue{}},
1310 {Kind: &structpb.Value_NullValue{}},
1311 {Kind: &structpb.Value_NumberValue{}},
Herbie Ong0b0f4032019-03-18 19:06:15 -07001312 },
1313 },
1314 },
1315 },
1316 {
Joe Tsaia95b29f2019-05-16 12:47:20 -07001317 Kind: &structpb.Value_StructValue{
1318 &structpb.Struct{
1319 Fields: map[string]*structpb.Value{
1320 "string": {Kind: &structpb.Value_StringValue{"world"}},
Herbie Ong0b0f4032019-03-18 19:06:15 -07001321 },
1322 },
1323 },
1324 },
1325 },
1326 },
1327 want: `[
1328 true,
1329 null,
1330 3.1415,
1331 "hello",
1332 [
1333 false,
1334 null,
1335 0
1336 ],
1337 {
1338 "string": "world"
1339 }
1340]`,
1341 }, {
1342 desc: "ListValue with invalid UTF8 string",
Joe Tsaia95b29f2019-05-16 12:47:20 -07001343 input: &structpb.ListValue{
1344 Values: []*structpb.Value{
1345 {Kind: &structpb.Value_StringValue{"\xff"}},
Herbie Ong0b0f4032019-03-18 19:06:15 -07001346 },
1347 },
Herbie Ong0b0f4032019-03-18 19:06:15 -07001348 wantErr: true,
1349 }, {
1350 desc: "Duration empty",
Joe Tsaia95b29f2019-05-16 12:47:20 -07001351 input: &durationpb.Duration{},
Herbie Ong0b0f4032019-03-18 19:06:15 -07001352 want: `"0s"`,
1353 }, {
1354 desc: "Duration with secs",
Joe Tsaia95b29f2019-05-16 12:47:20 -07001355 input: &durationpb.Duration{Seconds: 3},
Herbie Ong0b0f4032019-03-18 19:06:15 -07001356 want: `"3s"`,
1357 }, {
1358 desc: "Duration with -secs",
Joe Tsaia95b29f2019-05-16 12:47:20 -07001359 input: &durationpb.Duration{Seconds: -3},
Herbie Ong0b0f4032019-03-18 19:06:15 -07001360 want: `"-3s"`,
1361 }, {
1362 desc: "Duration with nanos",
Joe Tsaia95b29f2019-05-16 12:47:20 -07001363 input: &durationpb.Duration{Nanos: 1e6},
Herbie Ong0b0f4032019-03-18 19:06:15 -07001364 want: `"0.001s"`,
1365 }, {
1366 desc: "Duration with -nanos",
Joe Tsaia95b29f2019-05-16 12:47:20 -07001367 input: &durationpb.Duration{Nanos: -1e6},
Herbie Ong0b0f4032019-03-18 19:06:15 -07001368 want: `"-0.001s"`,
1369 }, {
1370 desc: "Duration with large secs",
Joe Tsaia95b29f2019-05-16 12:47:20 -07001371 input: &durationpb.Duration{Seconds: 1e10, Nanos: 1},
Herbie Ong0b0f4032019-03-18 19:06:15 -07001372 want: `"10000000000.000000001s"`,
1373 }, {
1374 desc: "Duration with 6-digit nanos",
Joe Tsaia95b29f2019-05-16 12:47:20 -07001375 input: &durationpb.Duration{Nanos: 1e4},
Herbie Ong0b0f4032019-03-18 19:06:15 -07001376 want: `"0.000010s"`,
1377 }, {
1378 desc: "Duration with 3-digit nanos",
Joe Tsaia95b29f2019-05-16 12:47:20 -07001379 input: &durationpb.Duration{Nanos: 1e6},
Herbie Ong0b0f4032019-03-18 19:06:15 -07001380 want: `"0.001s"`,
1381 }, {
1382 desc: "Duration with -secs -nanos",
Joe Tsaia95b29f2019-05-16 12:47:20 -07001383 input: &durationpb.Duration{Seconds: -123, Nanos: -450},
Herbie Ong0b0f4032019-03-18 19:06:15 -07001384 want: `"-123.000000450s"`,
1385 }, {
Herbie Ongad9c1252019-04-24 20:51:28 -07001386 desc: "Duration max value",
Joe Tsaia95b29f2019-05-16 12:47:20 -07001387 input: &durationpb.Duration{Seconds: 315576000000, Nanos: 999999999},
Herbie Ongad9c1252019-04-24 20:51:28 -07001388 want: `"315576000000.999999999s"`,
1389 }, {
1390 desc: "Duration min value",
Joe Tsaia95b29f2019-05-16 12:47:20 -07001391 input: &durationpb.Duration{Seconds: -315576000000, Nanos: -999999999},
Herbie Ongad9c1252019-04-24 20:51:28 -07001392 want: `"-315576000000.999999999s"`,
1393 }, {
Herbie Ong0b0f4032019-03-18 19:06:15 -07001394 desc: "Duration with +secs -nanos",
Joe Tsaia95b29f2019-05-16 12:47:20 -07001395 input: &durationpb.Duration{Seconds: 1, Nanos: -1},
Herbie Ong0b0f4032019-03-18 19:06:15 -07001396 wantErr: true,
1397 }, {
1398 desc: "Duration with -secs +nanos",
Joe Tsaia95b29f2019-05-16 12:47:20 -07001399 input: &durationpb.Duration{Seconds: -1, Nanos: 1},
Herbie Ong0b0f4032019-03-18 19:06:15 -07001400 wantErr: true,
1401 }, {
1402 desc: "Duration with +secs out of range",
Joe Tsaia95b29f2019-05-16 12:47:20 -07001403 input: &durationpb.Duration{Seconds: 315576000001},
Herbie Ong0b0f4032019-03-18 19:06:15 -07001404 wantErr: true,
1405 }, {
1406 desc: "Duration with -secs out of range",
Joe Tsaia95b29f2019-05-16 12:47:20 -07001407 input: &durationpb.Duration{Seconds: -315576000001},
Herbie Ong0b0f4032019-03-18 19:06:15 -07001408 wantErr: true,
1409 }, {
1410 desc: "Duration with +nanos out of range",
Joe Tsaia95b29f2019-05-16 12:47:20 -07001411 input: &durationpb.Duration{Seconds: 0, Nanos: 1e9},
Herbie Ong0b0f4032019-03-18 19:06:15 -07001412 wantErr: true,
1413 }, {
1414 desc: "Duration with -nanos out of range",
Joe Tsaia95b29f2019-05-16 12:47:20 -07001415 input: &durationpb.Duration{Seconds: 0, Nanos: -1e9},
Herbie Ong0b0f4032019-03-18 19:06:15 -07001416 wantErr: true,
1417 }, {
1418 desc: "Timestamp zero",
Joe Tsaia95b29f2019-05-16 12:47:20 -07001419 input: &timestamppb.Timestamp{},
Herbie Ong0b0f4032019-03-18 19:06:15 -07001420 want: `"1970-01-01T00:00:00Z"`,
1421 }, {
1422 desc: "Timestamp",
Joe Tsaia95b29f2019-05-16 12:47:20 -07001423 input: &timestamppb.Timestamp{Seconds: 1553036601},
Herbie Ong0b0f4032019-03-18 19:06:15 -07001424 want: `"2019-03-19T23:03:21Z"`,
1425 }, {
1426 desc: "Timestamp with nanos",
Joe Tsaia95b29f2019-05-16 12:47:20 -07001427 input: &timestamppb.Timestamp{Seconds: 1553036601, Nanos: 1},
Herbie Ong0b0f4032019-03-18 19:06:15 -07001428 want: `"2019-03-19T23:03:21.000000001Z"`,
1429 }, {
1430 desc: "Timestamp with 6-digit nanos",
Joe Tsaia95b29f2019-05-16 12:47:20 -07001431 input: &timestamppb.Timestamp{Nanos: 1e3},
Herbie Ong0b0f4032019-03-18 19:06:15 -07001432 want: `"1970-01-01T00:00:00.000001Z"`,
1433 }, {
1434 desc: "Timestamp with 3-digit nanos",
Joe Tsaia95b29f2019-05-16 12:47:20 -07001435 input: &timestamppb.Timestamp{Nanos: 1e7},
Herbie Ong0b0f4032019-03-18 19:06:15 -07001436 want: `"1970-01-01T00:00:00.010Z"`,
1437 }, {
Herbie Ongad9c1252019-04-24 20:51:28 -07001438 desc: "Timestamp max value",
Joe Tsaia95b29f2019-05-16 12:47:20 -07001439 input: &timestamppb.Timestamp{Seconds: 253402300799, Nanos: 999999999},
Herbie Ongad9c1252019-04-24 20:51:28 -07001440 want: `"9999-12-31T23:59:59.999999999Z"`,
1441 }, {
1442 desc: "Timestamp min value",
Joe Tsaia95b29f2019-05-16 12:47:20 -07001443 input: &timestamppb.Timestamp{Seconds: -62135596800},
Herbie Ongad9c1252019-04-24 20:51:28 -07001444 want: `"0001-01-01T00:00:00Z"`,
1445 }, {
Herbie Ong0b0f4032019-03-18 19:06:15 -07001446 desc: "Timestamp with +secs out of range",
Joe Tsaia95b29f2019-05-16 12:47:20 -07001447 input: &timestamppb.Timestamp{Seconds: 253402300800},
Herbie Ong0b0f4032019-03-18 19:06:15 -07001448 wantErr: true,
1449 }, {
1450 desc: "Timestamp with -secs out of range",
Joe Tsaia95b29f2019-05-16 12:47:20 -07001451 input: &timestamppb.Timestamp{Seconds: -62135596801},
Herbie Ong0b0f4032019-03-18 19:06:15 -07001452 wantErr: true,
1453 }, {
1454 desc: "Timestamp with -nanos",
Joe Tsaia95b29f2019-05-16 12:47:20 -07001455 input: &timestamppb.Timestamp{Nanos: -1},
Herbie Ong0b0f4032019-03-18 19:06:15 -07001456 wantErr: true,
1457 }, {
1458 desc: "Timestamp with +nanos out of range",
Joe Tsaia95b29f2019-05-16 12:47:20 -07001459 input: &timestamppb.Timestamp{Nanos: 1e9},
Herbie Ong0b0f4032019-03-18 19:06:15 -07001460 wantErr: true,
1461 }, {
1462 desc: "FieldMask empty",
Joe Tsaia95b29f2019-05-16 12:47:20 -07001463 input: &fieldmaskpb.FieldMask{},
Herbie Ong0b0f4032019-03-18 19:06:15 -07001464 want: `""`,
1465 }, {
1466 desc: "FieldMask",
Joe Tsaia95b29f2019-05-16 12:47:20 -07001467 input: &fieldmaskpb.FieldMask{
Herbie Ong0b0f4032019-03-18 19:06:15 -07001468 Paths: []string{
1469 "foo",
1470 "foo_bar",
1471 "foo.bar_qux",
1472 "_foo",
1473 },
1474 },
1475 want: `"foo,fooBar,foo.barQux,Foo"`,
1476 }, {
1477 desc: "FieldMask error 1",
Joe Tsaia95b29f2019-05-16 12:47:20 -07001478 input: &fieldmaskpb.FieldMask{
Herbie Ong0b0f4032019-03-18 19:06:15 -07001479 Paths: []string{"foo_"},
1480 },
1481 wantErr: true,
1482 }, {
1483 desc: "FieldMask error 2",
Joe Tsaia95b29f2019-05-16 12:47:20 -07001484 input: &fieldmaskpb.FieldMask{
Herbie Ong0b0f4032019-03-18 19:06:15 -07001485 Paths: []string{"foo__bar"},
1486 },
1487 wantErr: true,
1488 }, {
1489 desc: "Any empty",
Joe Tsaia95b29f2019-05-16 12:47:20 -07001490 input: &anypb.Any{},
Herbie Ong0b0f4032019-03-18 19:06:15 -07001491 want: `{}`,
1492 }, {
Herbie Ong8ac9dd22019-03-27 12:20:50 -07001493 desc: "Any with non-custom message",
Herbie Ong0b0f4032019-03-18 19:06:15 -07001494 input: func() proto.Message {
1495 m := &pb2.Nested{
Damien Neila8a2cea2019-07-10 16:17:16 -07001496 OptString: proto.String("embedded inside Any"),
Herbie Ong0b0f4032019-03-18 19:06:15 -07001497 OptNested: &pb2.Nested{
Damien Neila8a2cea2019-07-10 16:17:16 -07001498 OptString: proto.String("inception"),
Herbie Ong0b0f4032019-03-18 19:06:15 -07001499 },
1500 }
1501 b, err := proto.MarshalOptions{Deterministic: true}.Marshal(m)
1502 if err != nil {
1503 t.Fatalf("error in binary marshaling message for Any.value: %v", err)
1504 }
Joe Tsaia95b29f2019-05-16 12:47:20 -07001505 return &anypb.Any{
Herbie Ong0b0f4032019-03-18 19:06:15 -07001506 TypeUrl: "foo/pb2.Nested",
1507 Value: b,
1508 }
1509 }(),
1510 want: `{
1511 "@type": "foo/pb2.Nested",
1512 "optString": "embedded inside Any",
1513 "optNested": {
1514 "optString": "inception"
1515 }
1516}`,
1517 }, {
Damien Neilc1507ac2019-10-08 13:24:16 -07001518 desc: "Any with empty embedded message",
Joe Tsaia95b29f2019-05-16 12:47:20 -07001519 input: &anypb.Any{TypeUrl: "foo/pb2.Nested"},
Herbie Ong0b0f4032019-03-18 19:06:15 -07001520 want: `{
1521 "@type": "foo/pb2.Nested"
1522}`,
1523 }, {
Herbie Ong8ac9dd22019-03-27 12:20:50 -07001524 desc: "Any without registered type",
Damien Neilc1507ac2019-10-08 13:24:16 -07001525 mo: protojson.MarshalOptions{Resolver: new(preg.Types)},
Joe Tsaia95b29f2019-05-16 12:47:20 -07001526 input: &anypb.Any{TypeUrl: "foo/pb2.Nested"},
Herbie Ong0b0f4032019-03-18 19:06:15 -07001527 wantErr: true,
1528 }, {
Damien Neil0c9f0a92019-06-19 10:41:09 -07001529 desc: "Any with missing required",
Herbie Ong0b0f4032019-03-18 19:06:15 -07001530 input: func() proto.Message {
1531 m := &pb2.PartialRequired{
Damien Neila8a2cea2019-07-10 16:17:16 -07001532 OptString: proto.String("embedded inside Any"),
Herbie Ong0b0f4032019-03-18 19:06:15 -07001533 }
Damien Neil96c229a2019-04-03 12:17:24 -07001534 b, err := proto.MarshalOptions{
1535 AllowPartial: true,
1536 Deterministic: true,
1537 }.Marshal(m)
Herbie Ong0b0f4032019-03-18 19:06:15 -07001538 if err != nil {
1539 t.Fatalf("error in binary marshaling message for Any.value: %v", err)
1540 }
Joe Tsaia95b29f2019-05-16 12:47:20 -07001541 return &anypb.Any{
Joe Tsai0fc49f82019-05-01 12:29:25 -07001542 TypeUrl: string(m.ProtoReflect().Descriptor().FullName()),
Herbie Ong0b0f4032019-03-18 19:06:15 -07001543 Value: b,
1544 }
1545 }(),
1546 want: `{
1547 "@type": "pb2.PartialRequired",
1548 "optString": "embedded inside Any"
1549}`,
Herbie Ong0b0f4032019-03-18 19:06:15 -07001550 }, {
Herbie Ong8ac9dd22019-03-27 12:20:50 -07001551 desc: "Any with partial required and AllowPartial",
Damien Neil5c5b5312019-05-14 12:44:37 -07001552 mo: protojson.MarshalOptions{
Herbie Ong8ac9dd22019-03-27 12:20:50 -07001553 AllowPartial: true,
Herbie Ong8ac9dd22019-03-27 12:20:50 -07001554 },
1555 input: func() proto.Message {
1556 m := &pb2.PartialRequired{
Damien Neila8a2cea2019-07-10 16:17:16 -07001557 OptString: proto.String("embedded inside Any"),
Herbie Ong8ac9dd22019-03-27 12:20:50 -07001558 }
Damien Neil96c229a2019-04-03 12:17:24 -07001559 b, err := proto.MarshalOptions{
1560 AllowPartial: true,
1561 Deterministic: true,
1562 }.Marshal(m)
Herbie Ong8ac9dd22019-03-27 12:20:50 -07001563 if err != nil {
1564 t.Fatalf("error in binary marshaling message for Any.value: %v", err)
1565 }
Joe Tsaia95b29f2019-05-16 12:47:20 -07001566 return &anypb.Any{
Joe Tsai0fc49f82019-05-01 12:29:25 -07001567 TypeUrl: string(m.ProtoReflect().Descriptor().FullName()),
Herbie Ong8ac9dd22019-03-27 12:20:50 -07001568 Value: b,
1569 }
1570 }(),
1571 want: `{
1572 "@type": "pb2.PartialRequired",
1573 "optString": "embedded inside Any"
1574}`,
1575 }, {
Herbie Ong0b0f4032019-03-18 19:06:15 -07001576 desc: "Any with invalid UTF8",
Herbie Ong0b0f4032019-03-18 19:06:15 -07001577 input: func() proto.Message {
1578 m := &pb2.Nested{
Damien Neila8a2cea2019-07-10 16:17:16 -07001579 OptString: proto.String("abc\xff"),
Herbie Ong0b0f4032019-03-18 19:06:15 -07001580 }
1581 b, err := proto.MarshalOptions{Deterministic: true}.Marshal(m)
1582 if err != nil {
1583 t.Fatalf("error in binary marshaling message for Any.value: %v", err)
1584 }
Joe Tsaia95b29f2019-05-16 12:47:20 -07001585 return &anypb.Any{
Herbie Ong0b0f4032019-03-18 19:06:15 -07001586 TypeUrl: "foo/pb2.Nested",
1587 Value: b,
1588 }
1589 }(),
Herbie Ong0b0f4032019-03-18 19:06:15 -07001590 wantErr: true,
1591 }, {
1592 desc: "Any with invalid value",
Joe Tsaia95b29f2019-05-16 12:47:20 -07001593 input: &anypb.Any{
Herbie Ong0b0f4032019-03-18 19:06:15 -07001594 TypeUrl: "foo/pb2.Nested",
Joe Tsai6dc168e2019-07-09 23:11:13 -07001595 Value: []byte("\x80"),
Herbie Ong0b0f4032019-03-18 19:06:15 -07001596 },
1597 wantErr: true,
1598 }, {
1599 desc: "Any with BoolValue",
Herbie Ong0b0f4032019-03-18 19:06:15 -07001600 input: func() proto.Message {
Joe Tsaia95b29f2019-05-16 12:47:20 -07001601 m := &wrapperspb.BoolValue{Value: true}
Herbie Ong0b0f4032019-03-18 19:06:15 -07001602 b, err := proto.MarshalOptions{Deterministic: true}.Marshal(m)
1603 if err != nil {
1604 t.Fatalf("error in binary marshaling message for Any.value: %v", err)
1605 }
Joe Tsaia95b29f2019-05-16 12:47:20 -07001606 return &anypb.Any{
Herbie Ong0b0f4032019-03-18 19:06:15 -07001607 TypeUrl: "type.googleapis.com/google.protobuf.BoolValue",
1608 Value: b,
1609 }
1610 }(),
1611 want: `{
1612 "@type": "type.googleapis.com/google.protobuf.BoolValue",
1613 "value": true
1614}`,
1615 }, {
Herbie Ong0b0f4032019-03-18 19:06:15 -07001616 desc: "Any with Empty",
Herbie Ong0b0f4032019-03-18 19:06:15 -07001617 input: func() proto.Message {
Joe Tsaia95b29f2019-05-16 12:47:20 -07001618 m := &emptypb.Empty{}
Herbie Ong0b0f4032019-03-18 19:06:15 -07001619 b, err := proto.MarshalOptions{Deterministic: true}.Marshal(m)
1620 if err != nil {
1621 t.Fatalf("error in binary marshaling message for Any.value: %v", err)
1622 }
Joe Tsaia95b29f2019-05-16 12:47:20 -07001623 return &anypb.Any{
Herbie Ong0b0f4032019-03-18 19:06:15 -07001624 TypeUrl: "type.googleapis.com/google.protobuf.Empty",
1625 Value: b,
1626 }
1627 }(),
1628 want: `{
Herbie Ong82014a52019-03-27 15:21:43 -07001629 "@type": "type.googleapis.com/google.protobuf.Empty",
1630 "value": {}
Herbie Ong0b0f4032019-03-18 19:06:15 -07001631}`,
1632 }, {
1633 desc: "Any with StringValue containing invalid UTF8",
Herbie Ong0b0f4032019-03-18 19:06:15 -07001634 input: func() proto.Message {
Joe Tsaia95b29f2019-05-16 12:47:20 -07001635 m := &wrapperspb.StringValue{Value: "abcd"}
Herbie Ong0b0f4032019-03-18 19:06:15 -07001636 b, err := proto.MarshalOptions{Deterministic: true}.Marshal(m)
1637 if err != nil {
1638 t.Fatalf("error in binary marshaling message for Any.value: %v", err)
1639 }
Joe Tsaia95b29f2019-05-16 12:47:20 -07001640 return &anypb.Any{
Herbie Ong0b0f4032019-03-18 19:06:15 -07001641 TypeUrl: "google.protobuf.StringValue",
Damien Neilbc310b52019-04-11 11:46:55 -07001642 Value: bytes.Replace(b, []byte("abcd"), []byte("abc\xff"), -1),
Herbie Ong0b0f4032019-03-18 19:06:15 -07001643 }
1644 }(),
Herbie Ong0b0f4032019-03-18 19:06:15 -07001645 wantErr: true,
1646 }, {
Herbie Ong8ac9dd22019-03-27 12:20:50 -07001647 desc: "Any with Int64Value",
Herbie Ong8ac9dd22019-03-27 12:20:50 -07001648 input: func() proto.Message {
Joe Tsaia95b29f2019-05-16 12:47:20 -07001649 m := &wrapperspb.Int64Value{Value: 42}
Herbie Ong8ac9dd22019-03-27 12:20:50 -07001650 b, err := proto.MarshalOptions{Deterministic: true}.Marshal(m)
1651 if err != nil {
1652 t.Fatalf("error in binary marshaling message for Any.value: %v", err)
1653 }
Joe Tsaia95b29f2019-05-16 12:47:20 -07001654 return &anypb.Any{
Herbie Ong8ac9dd22019-03-27 12:20:50 -07001655 TypeUrl: "google.protobuf.Int64Value",
1656 Value: b,
1657 }
1658 }(),
1659 want: `{
1660 "@type": "google.protobuf.Int64Value",
1661 "value": "42"
1662}`,
1663 }, {
1664 desc: "Any with Duration",
Herbie Ong8ac9dd22019-03-27 12:20:50 -07001665 input: func() proto.Message {
Joe Tsaia95b29f2019-05-16 12:47:20 -07001666 m := &durationpb.Duration{}
Herbie Ong8ac9dd22019-03-27 12:20:50 -07001667 b, err := proto.MarshalOptions{Deterministic: true}.Marshal(m)
1668 if err != nil {
1669 t.Fatalf("error in binary marshaling message for Any.value: %v", err)
1670 }
Joe Tsaia95b29f2019-05-16 12:47:20 -07001671 return &anypb.Any{
Herbie Ong8ac9dd22019-03-27 12:20:50 -07001672 TypeUrl: "type.googleapis.com/google.protobuf.Duration",
1673 Value: b,
1674 }
1675 }(),
1676 want: `{
1677 "@type": "type.googleapis.com/google.protobuf.Duration",
1678 "value": "0s"
1679}`,
1680 }, {
1681 desc: "Any with empty Value",
Herbie Ong8ac9dd22019-03-27 12:20:50 -07001682 input: func() proto.Message {
Joe Tsaia95b29f2019-05-16 12:47:20 -07001683 m := &structpb.Value{}
Herbie Ong8ac9dd22019-03-27 12:20:50 -07001684 b, err := proto.Marshal(m)
1685 if err != nil {
1686 t.Fatalf("error in binary marshaling message for Any.value: %v", err)
1687 }
Joe Tsaia95b29f2019-05-16 12:47:20 -07001688 return &anypb.Any{
Herbie Ong8ac9dd22019-03-27 12:20:50 -07001689 TypeUrl: "type.googleapis.com/google.protobuf.Value",
1690 Value: b,
1691 }
1692 }(),
1693 wantErr: true,
1694 }, {
Herbie Ong0b0f4032019-03-18 19:06:15 -07001695 desc: "Any with Value of StringValue",
Herbie Ong0b0f4032019-03-18 19:06:15 -07001696 input: func() proto.Message {
Joe Tsaia95b29f2019-05-16 12:47:20 -07001697 m := &structpb.Value{Kind: &structpb.Value_StringValue{"abcd"}}
Herbie Ong0b0f4032019-03-18 19:06:15 -07001698 b, err := proto.MarshalOptions{Deterministic: true}.Marshal(m)
1699 if err != nil {
1700 t.Fatalf("error in binary marshaling message for Any.value: %v", err)
1701 }
Joe Tsaia95b29f2019-05-16 12:47:20 -07001702 return &anypb.Any{
Herbie Ong0b0f4032019-03-18 19:06:15 -07001703 TypeUrl: "type.googleapis.com/google.protobuf.Value",
Damien Neilbc310b52019-04-11 11:46:55 -07001704 Value: bytes.Replace(b, []byte("abcd"), []byte("abc\xff"), -1),
Herbie Ong0b0f4032019-03-18 19:06:15 -07001705 }
1706 }(),
Herbie Ong0b0f4032019-03-18 19:06:15 -07001707 wantErr: true,
1708 }, {
Herbie Ong8ac9dd22019-03-27 12:20:50 -07001709 desc: "Any with Value of NullValue",
Herbie Ong0b0f4032019-03-18 19:06:15 -07001710 input: func() proto.Message {
Joe Tsaia95b29f2019-05-16 12:47:20 -07001711 m := &structpb.Value{Kind: &structpb.Value_NullValue{}}
Herbie Ong8ac9dd22019-03-27 12:20:50 -07001712 b, err := proto.MarshalOptions{Deterministic: true}.Marshal(m)
Herbie Ong0b0f4032019-03-18 19:06:15 -07001713 if err != nil {
1714 t.Fatalf("error in binary marshaling message for Any.value: %v", err)
1715 }
Joe Tsaia95b29f2019-05-16 12:47:20 -07001716 return &anypb.Any{
Herbie Ong0b0f4032019-03-18 19:06:15 -07001717 TypeUrl: "type.googleapis.com/google.protobuf.Value",
1718 Value: b,
1719 }
1720 }(),
Herbie Ong0b0f4032019-03-18 19:06:15 -07001721 want: `{
Herbie Ong8ac9dd22019-03-27 12:20:50 -07001722 "@type": "type.googleapis.com/google.protobuf.Value",
1723 "value": null
Herbie Ong0b0f4032019-03-18 19:06:15 -07001724}`,
1725 }, {
1726 desc: "Any with Struct",
Herbie Ong0b0f4032019-03-18 19:06:15 -07001727 input: func() proto.Message {
Joe Tsaia95b29f2019-05-16 12:47:20 -07001728 m := &structpb.Struct{
1729 Fields: map[string]*structpb.Value{
1730 "bool": {Kind: &structpb.Value_BoolValue{true}},
1731 "null": {Kind: &structpb.Value_NullValue{}},
1732 "string": {Kind: &structpb.Value_StringValue{"hello"}},
Herbie Ong0b0f4032019-03-18 19:06:15 -07001733 "struct": {
Joe Tsaia95b29f2019-05-16 12:47:20 -07001734 Kind: &structpb.Value_StructValue{
1735 &structpb.Struct{
1736 Fields: map[string]*structpb.Value{
1737 "string": {Kind: &structpb.Value_StringValue{"world"}},
Herbie Ong0b0f4032019-03-18 19:06:15 -07001738 },
1739 },
1740 },
1741 },
1742 },
1743 }
1744 b, err := proto.MarshalOptions{Deterministic: true}.Marshal(m)
1745 if err != nil {
1746 t.Fatalf("error in binary marshaling message for Any.value: %v", err)
1747 }
Joe Tsaia95b29f2019-05-16 12:47:20 -07001748 return &anypb.Any{
Herbie Ong0b0f4032019-03-18 19:06:15 -07001749 TypeUrl: "google.protobuf.Struct",
1750 Value: b,
1751 }
1752 }(),
1753 want: `{
1754 "@type": "google.protobuf.Struct",
1755 "value": {
1756 "bool": true,
1757 "null": null,
1758 "string": "hello",
1759 "struct": {
1760 "string": "world"
1761 }
1762 }
1763}`,
1764 }, {
Herbie Ong8ac9dd22019-03-27 12:20:50 -07001765 desc: "Any with missing type_url",
Herbie Ong8ac9dd22019-03-27 12:20:50 -07001766 input: func() proto.Message {
Joe Tsaia95b29f2019-05-16 12:47:20 -07001767 m := &wrapperspb.BoolValue{Value: true}
Herbie Ong8ac9dd22019-03-27 12:20:50 -07001768 b, err := proto.MarshalOptions{Deterministic: true}.Marshal(m)
1769 if err != nil {
1770 t.Fatalf("error in binary marshaling message for Any.value: %v", err)
1771 }
Joe Tsaia95b29f2019-05-16 12:47:20 -07001772 return &anypb.Any{
Herbie Ong8ac9dd22019-03-27 12:20:50 -07001773 Value: b,
1774 }
1775 }(),
1776 wantErr: true,
1777 }, {
Herbie Ong0b0f4032019-03-18 19:06:15 -07001778 desc: "well known types as field values",
Herbie Ong0b0f4032019-03-18 19:06:15 -07001779 input: &pb2.KnownTypes{
Joe Tsaia95b29f2019-05-16 12:47:20 -07001780 OptBool: &wrapperspb.BoolValue{Value: false},
1781 OptInt32: &wrapperspb.Int32Value{Value: 42},
1782 OptInt64: &wrapperspb.Int64Value{Value: 42},
1783 OptUint32: &wrapperspb.UInt32Value{Value: 42},
1784 OptUint64: &wrapperspb.UInt64Value{Value: 42},
1785 OptFloat: &wrapperspb.FloatValue{Value: 1.23},
1786 OptDouble: &wrapperspb.DoubleValue{Value: 3.1415},
1787 OptString: &wrapperspb.StringValue{Value: "hello"},
1788 OptBytes: &wrapperspb.BytesValue{Value: []byte("hello")},
1789 OptDuration: &durationpb.Duration{Seconds: 123},
1790 OptTimestamp: &timestamppb.Timestamp{Seconds: 1553036601},
1791 OptStruct: &structpb.Struct{
1792 Fields: map[string]*structpb.Value{
1793 "string": {Kind: &structpb.Value_StringValue{"hello"}},
Herbie Ong0b0f4032019-03-18 19:06:15 -07001794 },
1795 },
Joe Tsaia95b29f2019-05-16 12:47:20 -07001796 OptList: &structpb.ListValue{
1797 Values: []*structpb.Value{
1798 {Kind: &structpb.Value_NullValue{}},
1799 {Kind: &structpb.Value_StringValue{}},
1800 {Kind: &structpb.Value_StructValue{}},
1801 {Kind: &structpb.Value_ListValue{}},
Herbie Ong0b0f4032019-03-18 19:06:15 -07001802 },
1803 },
Joe Tsaia95b29f2019-05-16 12:47:20 -07001804 OptValue: &structpb.Value{
1805 Kind: &structpb.Value_StringValue{"world"},
Herbie Ong1c7462c2019-03-22 17:56:55 -07001806 },
Joe Tsaia95b29f2019-05-16 12:47:20 -07001807 OptEmpty: &emptypb.Empty{},
1808 OptAny: &anypb.Any{
Herbie Ong0b0f4032019-03-18 19:06:15 -07001809 TypeUrl: "google.protobuf.Empty",
1810 },
Joe Tsaia95b29f2019-05-16 12:47:20 -07001811 OptFieldmask: &fieldmaskpb.FieldMask{
Herbie Ong0b0f4032019-03-18 19:06:15 -07001812 Paths: []string{"foo_bar", "bar_foo"},
1813 },
1814 },
1815 want: `{
1816 "optBool": false,
1817 "optInt32": 42,
1818 "optInt64": "42",
1819 "optUint32": 42,
1820 "optUint64": "42",
1821 "optFloat": 1.23,
1822 "optDouble": 3.1415,
1823 "optString": "hello",
1824 "optBytes": "aGVsbG8=",
1825 "optDuration": "123s",
1826 "optTimestamp": "2019-03-19T23:03:21Z",
1827 "optStruct": {
1828 "string": "hello"
1829 },
1830 "optList": [
1831 null,
1832 "",
1833 {},
1834 []
1835 ],
Herbie Ong1c7462c2019-03-22 17:56:55 -07001836 "optValue": "world",
Herbie Ong0b0f4032019-03-18 19:06:15 -07001837 "optEmpty": {},
1838 "optAny": {
Herbie Ong82014a52019-03-27 15:21:43 -07001839 "@type": "google.protobuf.Empty",
1840 "value": {}
Herbie Ong0b0f4032019-03-18 19:06:15 -07001841 },
1842 "optFieldmask": "fooBar,barFoo"
1843}`,
Herbie Ong984e5282019-09-06 00:29:48 -07001844 }, {
1845 desc: "EmitUnpopulated: proto2 optional scalars",
1846 mo: protojson.MarshalOptions{EmitUnpopulated: true},
1847 input: &pb2.Scalars{},
1848 want: `{
1849 "optBool": null,
1850 "optInt32": null,
1851 "optInt64": null,
1852 "optUint32": null,
1853 "optUint64": null,
1854 "optSint32": null,
1855 "optSint64": null,
1856 "optFixed32": null,
1857 "optFixed64": null,
1858 "optSfixed32": null,
1859 "optSfixed64": null,
1860 "optFloat": null,
1861 "optDouble": null,
1862 "optBytes": null,
1863 "optString": null
1864}`,
1865 }, {
1866 desc: "EmitUnpopulated: proto3 scalars",
1867 mo: protojson.MarshalOptions{EmitUnpopulated: true},
1868 input: &pb3.Scalars{},
1869 want: `{
1870 "sBool": false,
1871 "sInt32": 0,
1872 "sInt64": "0",
1873 "sUint32": 0,
1874 "sUint64": "0",
1875 "sSint32": 0,
1876 "sSint64": "0",
1877 "sFixed32": 0,
1878 "sFixed64": "0",
1879 "sSfixed32": 0,
1880 "sSfixed64": "0",
1881 "sFloat": 0,
1882 "sDouble": 0,
1883 "sBytes": "",
1884 "sString": ""
1885}`,
1886 }, {
1887 desc: "EmitUnpopulated: proto2 enum",
1888 mo: protojson.MarshalOptions{EmitUnpopulated: true},
1889 input: &pb2.Enums{},
1890 want: `{
1891 "optEnum": null,
1892 "rptEnum": [],
1893 "optNestedEnum": null,
1894 "rptNestedEnum": []
1895}`,
1896 }, {
1897 desc: "EmitUnpopulated: proto3 enum",
1898 mo: protojson.MarshalOptions{EmitUnpopulated: true},
1899 input: &pb3.Enums{},
1900 want: `{
1901 "sEnum": "ZERO",
1902 "sNestedEnum": "CERO"
1903}`,
1904 }, {
1905 desc: "EmitUnpopulated: proto2 message and group fields",
1906 mo: protojson.MarshalOptions{EmitUnpopulated: true},
1907 input: &pb2.Nests{},
1908 want: `{
1909 "optNested": null,
1910 "optgroup": null,
1911 "rptNested": [],
1912 "rptgroup": []
1913}`,
1914 }, {
1915 desc: "EmitUnpopulated: proto3 message field",
1916 mo: protojson.MarshalOptions{EmitUnpopulated: true},
1917 input: &pb3.Nests{},
1918 want: `{
1919 "sNested": null
1920}`,
1921 }, {
1922 desc: "EmitUnpopulated: proto2 empty message and group fields",
1923 mo: protojson.MarshalOptions{EmitUnpopulated: true},
1924 input: &pb2.Nests{
1925 OptNested: &pb2.Nested{},
1926 Optgroup: &pb2.Nests_OptGroup{},
1927 },
1928 want: `{
1929 "optNested": {
1930 "optString": null,
1931 "optNested": null
1932 },
1933 "optgroup": {
1934 "optString": null,
1935 "optNested": null,
1936 "optnestedgroup": null
1937 },
1938 "rptNested": [],
1939 "rptgroup": []
1940}`,
1941 }, {
1942 desc: "EmitUnpopulated: proto3 empty message field",
1943 mo: protojson.MarshalOptions{EmitUnpopulated: true},
1944 input: &pb3.Nests{
1945 SNested: &pb3.Nested{},
1946 },
1947 want: `{
1948 "sNested": {
1949 "sString": "",
1950 "sNested": null
1951 }
1952}`,
1953 }, {
1954 desc: "EmitUnpopulated: proto2 required fields",
1955 mo: protojson.MarshalOptions{
1956 AllowPartial: true,
1957 EmitUnpopulated: true,
1958 },
1959 input: &pb2.Requireds{},
1960 want: `{
1961 "reqBool": null,
1962 "reqSfixed64": null,
1963 "reqDouble": null,
1964 "reqString": null,
1965 "reqEnum": null,
1966 "reqNested": null
1967}`,
1968 }, {
1969 desc: "EmitUnpopulated: repeated fields",
1970 mo: protojson.MarshalOptions{EmitUnpopulated: true},
1971 input: &pb2.Repeats{},
1972 want: `{
1973 "rptBool": [],
1974 "rptInt32": [],
1975 "rptInt64": [],
1976 "rptUint32": [],
1977 "rptUint64": [],
1978 "rptFloat": [],
1979 "rptDouble": [],
1980 "rptString": [],
1981 "rptBytes": []
1982}`,
1983 }, {
1984 desc: "EmitUnpopulated: repeated containing empty message",
1985 mo: protojson.MarshalOptions{EmitUnpopulated: true},
1986 input: &pb2.Nests{
1987 RptNested: []*pb2.Nested{nil, {}},
1988 },
1989 want: `{
1990 "optNested": null,
1991 "optgroup": null,
1992 "rptNested": [
1993 {
1994 "optString": null,
1995 "optNested": null
1996 },
1997 {
1998 "optString": null,
1999 "optNested": null
2000 }
2001 ],
2002 "rptgroup": []
2003}`,
2004 }, {
2005 desc: "EmitUnpopulated: map fields",
2006 mo: protojson.MarshalOptions{EmitUnpopulated: true},
2007 input: &pb3.Maps{},
2008 want: `{
2009 "int32ToStr": {},
2010 "boolToUint32": {},
2011 "uint64ToEnum": {},
2012 "strToNested": {},
2013 "strToOneofs": {}
2014}`,
2015 }, {
2016 desc: "EmitUnpopulated: map containing empty message",
2017 mo: protojson.MarshalOptions{EmitUnpopulated: true},
2018 input: &pb3.Maps{
2019 StrToNested: map[string]*pb3.Nested{
2020 "nested": &pb3.Nested{},
2021 },
2022 StrToOneofs: map[string]*pb3.Oneofs{
2023 "nested": &pb3.Oneofs{},
2024 },
2025 },
2026 want: `{
2027 "int32ToStr": {},
2028 "boolToUint32": {},
2029 "uint64ToEnum": {},
2030 "strToNested": {
2031 "nested": {
2032 "sString": "",
2033 "sNested": null
2034 }
2035 },
2036 "strToOneofs": {
2037 "nested": {}
2038 }
2039}`,
2040 }, {
2041 desc: "EmitUnpopulated: oneof fields",
2042 mo: protojson.MarshalOptions{EmitUnpopulated: true},
2043 input: &pb3.Oneofs{},
2044 want: `{}`,
2045 }, {
2046 desc: "EmitUnpopulated: extensions",
2047 mo: protojson.MarshalOptions{EmitUnpopulated: true},
2048 input: func() proto.Message {
2049 m := &pb2.Extensions{}
2050 proto.SetExtension(m, pb2.E_OptExtNested, &pb2.Nested{})
2051 proto.SetExtension(m, pb2.E_RptExtNested, []*pb2.Nested{
2052 nil,
2053 {},
2054 })
2055 return m
2056 }(),
2057 want: `{
2058 "optString": null,
2059 "optBool": null,
2060 "optInt32": null,
2061 "[pb2.opt_ext_nested]": {
2062 "optString": null,
2063 "optNested": null
2064 },
2065 "[pb2.rpt_ext_nested]": [
2066 {
2067 "optString": null,
2068 "optNested": null
2069 },
2070 {
2071 "optString": null,
2072 "optNested": null
2073 }
2074 ]
2075}`,
Herbie Ong9111f3b2019-09-06 14:35:09 -07002076 }, {
2077 desc: "UseEnumNumbers in singular field",
2078 mo: protojson.MarshalOptions{UseEnumNumbers: true},
2079 input: &pb2.Enums{
2080 OptEnum: pb2.Enum_ONE.Enum(),
2081 OptNestedEnum: pb2.Enums_UNO.Enum(),
2082 },
2083 want: `{
2084 "optEnum": 1,
2085 "optNestedEnum": 1
2086}`,
2087 }, {
2088 desc: "UseEnumNumbers in repeated field",
2089 mo: protojson.MarshalOptions{UseEnumNumbers: true},
2090 input: &pb2.Enums{
2091 RptEnum: []pb2.Enum{pb2.Enum_ONE, 2, pb2.Enum_TEN, 42},
2092 RptNestedEnum: []pb2.Enums_NestedEnum{pb2.Enums_UNO, pb2.Enums_DOS, 47},
2093 },
2094 want: `{
2095 "rptEnum": [
2096 1,
2097 2,
2098 10,
2099 42
2100 ],
2101 "rptNestedEnum": [
2102 1,
2103 2,
2104 47
2105 ]
2106}`,
2107 }, {
2108 desc: "UseEnumNumbers in map field",
2109 mo: protojson.MarshalOptions{UseEnumNumbers: true},
2110 input: &pb3.Maps{
2111 Uint64ToEnum: map[uint64]pb3.Enum{
2112 1: pb3.Enum_ONE,
2113 2: pb3.Enum_TWO,
2114 10: pb3.Enum_TEN,
2115 47: 47,
2116 },
2117 },
2118 want: `{
2119 "uint64ToEnum": {
2120 "1": 1,
2121 "2": 2,
2122 "10": 10,
2123 "47": 47
2124 }
2125}`,
Herbie Ong956cd6d2019-09-06 15:17:22 -07002126 }, {
2127 desc: "UseProtoNames",
2128 mo: protojson.MarshalOptions{UseProtoNames: true},
2129 input: &pb2.Nests{
2130 OptNested: &pb2.Nested{},
2131 Optgroup: &pb2.Nests_OptGroup{
2132 OptString: proto.String("inside a group"),
2133 OptNested: &pb2.Nested{
2134 OptString: proto.String("nested message inside a group"),
2135 },
2136 Optnestedgroup: &pb2.Nests_OptGroup_OptNestedGroup{
2137 OptFixed32: proto.Uint32(47),
2138 },
2139 },
2140 Rptgroup: []*pb2.Nests_RptGroup{
2141 {
2142 RptString: []string{"hello", "world"},
2143 },
2144 },
2145 },
2146 want: `{
2147 "opt_nested": {},
2148 "OptGroup": {
2149 "opt_string": "inside a group",
2150 "opt_nested": {
2151 "opt_string": "nested message inside a group"
2152 },
2153 "OptNestedGroup": {
2154 "opt_fixed32": 47
2155 }
2156 },
2157 "RptGroup": [
2158 {
2159 "rpt_string": [
2160 "hello",
2161 "world"
2162 ]
2163 }
2164 ]
2165}`,
Herbie Ong7b828bc2019-02-08 19:56:24 -08002166 }}
2167
2168 for _, tt := range tests {
2169 tt := tt
Joe Tsai5ae10aa2019-07-11 18:23:08 -07002170 if tt.skip {
2171 continue
2172 }
Herbie Ong7b828bc2019-02-08 19:56:24 -08002173 t.Run(tt.desc, func(t *testing.T) {
Herbie Ong0b0f4032019-03-18 19:06:15 -07002174 // Use 2-space indentation on all MarshalOptions.
2175 tt.mo.Indent = " "
Herbie Ong7b828bc2019-02-08 19:56:24 -08002176 b, err := tt.mo.Marshal(tt.input)
Herbie Ong0b0f4032019-03-18 19:06:15 -07002177 if err != nil && !tt.wantErr {
Herbie Ong7b828bc2019-02-08 19:56:24 -08002178 t.Errorf("Marshal() returned error: %v\n", err)
2179 }
Herbie Ong0b0f4032019-03-18 19:06:15 -07002180 if err == nil && tt.wantErr {
2181 t.Errorf("Marshal() got nil error, want error\n")
2182 }
Herbie Ong7b828bc2019-02-08 19:56:24 -08002183 got := string(b)
2184 if got != tt.want {
2185 t.Errorf("Marshal()\n<got>\n%v\n<want>\n%v\n", got, tt.want)
Joe Tsai6dc168e2019-07-09 23:11:13 -07002186 if diff := cmp.Diff(tt.want, got); diff != "" {
Herbie Ong7b828bc2019-02-08 19:56:24 -08002187 t.Errorf("Marshal() diff -want +got\n%v\n", diff)
2188 }
2189 }
2190 })
2191 }
2192}