blob: 280e8db9034a2a088e2dd8aee2fe9ec4375e6317 [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
5package jsonpb_test
6
7import (
8 "math"
9 "strings"
10 "testing"
11
Herbie Ongf83d5bb2019-03-14 00:01:27 -070012 "github.com/golang/protobuf/protoapi"
Herbie Ong7b828bc2019-02-08 19:56:24 -080013 "github.com/golang/protobuf/v2/encoding/jsonpb"
14 "github.com/golang/protobuf/v2/internal/encoding/pack"
Herbie Ongf83d5bb2019-03-14 00:01:27 -070015 "github.com/golang/protobuf/v2/internal/encoding/wire"
Herbie Ong7b828bc2019-02-08 19:56:24 -080016 "github.com/golang/protobuf/v2/internal/scalar"
17 "github.com/golang/protobuf/v2/proto"
18 "github.com/google/go-cmp/cmp"
19 "github.com/google/go-cmp/cmp/cmpopts"
20
Herbie Ongf83d5bb2019-03-14 00:01:27 -070021 // This legacy package is still needed when importing legacy message.
22 _ "github.com/golang/protobuf/v2/internal/legacy"
23
Herbie Ong7b828bc2019-02-08 19:56:24 -080024 "github.com/golang/protobuf/v2/encoding/testprotos/pb2"
25 "github.com/golang/protobuf/v2/encoding/testprotos/pb3"
26)
27
28// splitLines is a cmpopts.Option for comparing strings with line breaks.
29var splitLines = cmpopts.AcyclicTransformer("SplitLines", func(s string) []string {
30 return strings.Split(s, "\n")
31})
32
33func pb2Enum(i int32) *pb2.Enum {
34 p := new(pb2.Enum)
35 *p = pb2.Enum(i)
36 return p
37}
38
39func pb2Enums_NestedEnum(i int32) *pb2.Enums_NestedEnum {
40 p := new(pb2.Enums_NestedEnum)
41 *p = pb2.Enums_NestedEnum(i)
42 return p
43}
44
Herbie Ongf83d5bb2019-03-14 00:01:27 -070045func setExtension(m proto.Message, xd *protoapi.ExtensionDesc, val interface{}) {
46 knownFields := m.ProtoReflect().KnownFields()
47 extTypes := knownFields.ExtensionTypes()
48 extTypes.Register(xd.Type)
49 if val == nil {
50 return
51 }
52 pval := xd.Type.ValueOf(val)
53 knownFields.Set(wire.Number(xd.Field), pval)
54}
55
Herbie Ong7b828bc2019-02-08 19:56:24 -080056func TestMarshal(t *testing.T) {
57 tests := []struct {
58 desc string
59 mo jsonpb.MarshalOptions
60 input proto.Message
61 want string
62 }{{
63 desc: "proto2 optional scalars not set",
64 input: &pb2.Scalars{},
65 want: "{}",
66 }, {
67 desc: "proto3 scalars not set",
68 input: &pb3.Scalars{},
69 want: "{}",
70 }, {
71 desc: "proto2 optional scalars set to zero values",
72 input: &pb2.Scalars{
73 OptBool: scalar.Bool(false),
74 OptInt32: scalar.Int32(0),
75 OptInt64: scalar.Int64(0),
76 OptUint32: scalar.Uint32(0),
77 OptUint64: scalar.Uint64(0),
78 OptSint32: scalar.Int32(0),
79 OptSint64: scalar.Int64(0),
80 OptFixed32: scalar.Uint32(0),
81 OptFixed64: scalar.Uint64(0),
82 OptSfixed32: scalar.Int32(0),
83 OptSfixed64: scalar.Int64(0),
84 OptFloat: scalar.Float32(0),
85 OptDouble: scalar.Float64(0),
86 OptBytes: []byte{},
87 OptString: scalar.String(""),
88 },
89 want: `{
90 "optBool": false,
91 "optInt32": 0,
92 "optInt64": "0",
93 "optUint32": 0,
94 "optUint64": "0",
95 "optSint32": 0,
96 "optSint64": "0",
97 "optFixed32": 0,
98 "optFixed64": "0",
99 "optSfixed32": 0,
100 "optSfixed64": "0",
101 "optFloat": 0,
102 "optDouble": 0,
103 "optBytes": "",
104 "optString": ""
105}`,
106 }, {
107 desc: "proto2 optional scalars set to some values",
108 input: &pb2.Scalars{
109 OptBool: scalar.Bool(true),
110 OptInt32: scalar.Int32(0xff),
111 OptInt64: scalar.Int64(0xdeadbeef),
112 OptUint32: scalar.Uint32(47),
113 OptUint64: scalar.Uint64(0xdeadbeef),
114 OptSint32: scalar.Int32(-1001),
115 OptSint64: scalar.Int64(-0xffff),
116 OptFixed64: scalar.Uint64(64),
117 OptSfixed32: scalar.Int32(-32),
118 OptFloat: scalar.Float32(1.02),
119 OptDouble: scalar.Float64(1.234),
Herbie Ong87608a72019-03-06 14:32:24 -0800120 OptBytes: []byte("谷歌"),
Herbie Ong7b828bc2019-02-08 19:56:24 -0800121 OptString: scalar.String("谷歌"),
122 },
123 want: `{
124 "optBool": true,
125 "optInt32": 255,
126 "optInt64": "3735928559",
127 "optUint32": 47,
128 "optUint64": "3735928559",
129 "optSint32": -1001,
130 "optSint64": "-65535",
131 "optFixed64": "64",
132 "optSfixed32": -32,
133 "optFloat": 1.02,
134 "optDouble": 1.234,
135 "optBytes": "6LC35q2M",
136 "optString": "谷歌"
137}`,
138 }, {
139 desc: "float nan",
140 input: &pb3.Scalars{
141 SFloat: float32(math.NaN()),
142 },
143 want: `{
144 "sFloat": "NaN"
145}`,
146 }, {
147 desc: "float positive infinity",
148 input: &pb3.Scalars{
149 SFloat: float32(math.Inf(1)),
150 },
151 want: `{
152 "sFloat": "Infinity"
153}`,
154 }, {
155 desc: "float negative infinity",
156 input: &pb3.Scalars{
157 SFloat: float32(math.Inf(-1)),
158 },
159 want: `{
160 "sFloat": "-Infinity"
161}`,
162 }, {
163 desc: "double nan",
164 input: &pb3.Scalars{
165 SDouble: math.NaN(),
166 },
167 want: `{
168 "sDouble": "NaN"
169}`,
170 }, {
171 desc: "double positive infinity",
172 input: &pb3.Scalars{
173 SDouble: math.Inf(1),
174 },
175 want: `{
176 "sDouble": "Infinity"
177}`,
178 }, {
179 desc: "double negative infinity",
180 input: &pb3.Scalars{
181 SDouble: math.Inf(-1),
182 },
183 want: `{
184 "sDouble": "-Infinity"
185}`,
186 }, {
187 desc: "proto2 enum not set",
188 input: &pb2.Enums{},
189 want: "{}",
190 }, {
191 desc: "proto2 enum set to zero value",
192 input: &pb2.Enums{
193 OptEnum: pb2Enum(0),
194 OptNestedEnum: pb2Enums_NestedEnum(0),
195 },
196 want: `{
197 "optEnum": 0,
198 "optNestedEnum": 0
199}`,
200 }, {
201 desc: "proto2 enum",
202 input: &pb2.Enums{
203 OptEnum: pb2.Enum_ONE.Enum(),
204 OptNestedEnum: pb2.Enums_UNO.Enum(),
205 },
206 want: `{
207 "optEnum": "ONE",
208 "optNestedEnum": "UNO"
209}`,
210 }, {
211 desc: "proto2 enum set to numeric values",
212 input: &pb2.Enums{
213 OptEnum: pb2Enum(2),
214 OptNestedEnum: pb2Enums_NestedEnum(2),
215 },
216 want: `{
217 "optEnum": "TWO",
218 "optNestedEnum": "DOS"
219}`,
220 }, {
221 desc: "proto2 enum set to unnamed numeric values",
222 input: &pb2.Enums{
223 OptEnum: pb2Enum(101),
224 OptNestedEnum: pb2Enums_NestedEnum(-101),
225 },
226 want: `{
227 "optEnum": 101,
228 "optNestedEnum": -101
229}`,
230 }, {
231 desc: "proto3 enum not set",
232 input: &pb3.Enums{},
233 want: "{}",
234 }, {
235 desc: "proto3 enum set to zero value",
236 input: &pb3.Enums{
237 SEnum: pb3.Enum_ZERO,
238 SNestedEnum: pb3.Enums_CERO,
239 },
240 want: "{}",
241 }, {
242 desc: "proto3 enum",
243 input: &pb3.Enums{
244 SEnum: pb3.Enum_ONE,
245 SNestedEnum: pb3.Enums_UNO,
246 },
247 want: `{
248 "sEnum": "ONE",
249 "sNestedEnum": "UNO"
250}`,
251 }, {
252 desc: "proto3 enum set to numeric values",
253 input: &pb3.Enums{
254 SEnum: 2,
255 SNestedEnum: 2,
256 },
257 want: `{
258 "sEnum": "TWO",
259 "sNestedEnum": "DOS"
260}`,
261 }, {
262 desc: "proto3 enum set to unnamed numeric values",
263 input: &pb3.Enums{
264 SEnum: -47,
265 SNestedEnum: 47,
266 },
267 want: `{
268 "sEnum": -47,
269 "sNestedEnum": 47
270}`,
271 }, {
272 desc: "proto2 nested message not set",
273 input: &pb2.Nests{},
274 want: "{}",
275 }, {
276 desc: "proto2 nested message set to empty",
277 input: &pb2.Nests{
278 OptNested: &pb2.Nested{},
279 Optgroup: &pb2.Nests_OptGroup{},
280 },
281 want: `{
282 "optNested": {},
283 "optgroup": {}
284}`,
285 }, {
286 desc: "proto2 nested messages",
287 input: &pb2.Nests{
288 OptNested: &pb2.Nested{
289 OptString: scalar.String("nested message"),
290 OptNested: &pb2.Nested{
291 OptString: scalar.String("another nested message"),
292 },
293 },
294 },
295 want: `{
296 "optNested": {
297 "optString": "nested message",
298 "optNested": {
299 "optString": "another nested message"
300 }
301 }
302}`,
303 }, {
304 desc: "proto2 groups",
305 input: &pb2.Nests{
306 Optgroup: &pb2.Nests_OptGroup{
307 OptString: scalar.String("inside a group"),
308 OptNested: &pb2.Nested{
309 OptString: scalar.String("nested message inside a group"),
310 },
311 Optnestedgroup: &pb2.Nests_OptGroup_OptNestedGroup{
312 OptFixed32: scalar.Uint32(47),
313 },
314 },
315 },
316 want: `{
317 "optgroup": {
318 "optString": "inside a group",
319 "optNested": {
320 "optString": "nested message inside a group"
321 },
322 "optnestedgroup": {
323 "optFixed32": 47
324 }
325 }
326}`,
327 }, {
328 desc: "proto3 nested message not set",
329 input: &pb3.Nests{},
330 want: "{}",
331 }, {
332 desc: "proto3 nested message set to empty",
333 input: &pb3.Nests{
334 SNested: &pb3.Nested{},
335 },
336 want: `{
337 "sNested": {}
338}`,
339 }, {
340 desc: "proto3 nested message",
341 input: &pb3.Nests{
342 SNested: &pb3.Nested{
343 SString: "nested message",
344 SNested: &pb3.Nested{
345 SString: "another nested message",
346 },
347 },
348 },
349 want: `{
350 "sNested": {
351 "sString": "nested message",
352 "sNested": {
353 "sString": "another nested message"
354 }
355 }
356}`,
357 }, {
358 desc: "oneof not set",
359 input: &pb3.Oneofs{},
360 want: "{}",
361 }, {
362 desc: "oneof set to empty string",
363 input: &pb3.Oneofs{
364 Union: &pb3.Oneofs_OneofString{},
365 },
366 want: `{
367 "oneofString": ""
368}`,
369 }, {
370 desc: "oneof set to string",
371 input: &pb3.Oneofs{
372 Union: &pb3.Oneofs_OneofString{
373 OneofString: "hello",
374 },
375 },
376 want: `{
377 "oneofString": "hello"
378}`,
379 }, {
380 desc: "oneof set to enum",
381 input: &pb3.Oneofs{
382 Union: &pb3.Oneofs_OneofEnum{
383 OneofEnum: pb3.Enum_ZERO,
384 },
385 },
386 want: `{
387 "oneofEnum": "ZERO"
388}`,
389 }, {
390 desc: "oneof set to empty message",
391 input: &pb3.Oneofs{
392 Union: &pb3.Oneofs_OneofNested{
393 OneofNested: &pb3.Nested{},
394 },
395 },
396 want: `{
397 "oneofNested": {}
398}`,
399 }, {
400 desc: "oneof set to message",
401 input: &pb3.Oneofs{
402 Union: &pb3.Oneofs_OneofNested{
403 OneofNested: &pb3.Nested{
404 SString: "nested message",
405 },
406 },
407 },
408 want: `{
409 "oneofNested": {
410 "sString": "nested message"
411 }
412}`,
413 }, {
414 desc: "repeated fields not set",
415 input: &pb2.Repeats{},
416 want: "{}",
417 }, {
418 desc: "repeated fields set to empty slices",
419 input: &pb2.Repeats{
420 RptBool: []bool{},
421 RptInt32: []int32{},
422 RptInt64: []int64{},
423 RptUint32: []uint32{},
424 RptUint64: []uint64{},
425 RptFloat: []float32{},
426 RptDouble: []float64{},
427 RptBytes: [][]byte{},
428 },
429 want: "{}",
430 }, {
431 desc: "repeated fields set to some values",
432 input: &pb2.Repeats{
433 RptBool: []bool{true, false, true, true},
434 RptInt32: []int32{1, 6, 0, 0},
435 RptInt64: []int64{-64, 47},
436 RptUint32: []uint32{0xff, 0xffff},
437 RptUint64: []uint64{0xdeadbeef},
438 RptFloat: []float32{float32(math.NaN()), float32(math.Inf(1)), float32(math.Inf(-1)), 1.034},
439 RptDouble: []float64{math.NaN(), math.Inf(1), math.Inf(-1), 1.23e-308},
440 RptString: []string{"hello", "世界"},
441 RptBytes: [][]byte{
442 []byte("hello"),
443 []byte("\xe4\xb8\x96\xe7\x95\x8c"),
444 },
445 },
446 want: `{
447 "rptBool": [
448 true,
449 false,
450 true,
451 true
452 ],
453 "rptInt32": [
454 1,
455 6,
456 0,
457 0
458 ],
459 "rptInt64": [
460 "-64",
461 "47"
462 ],
463 "rptUint32": [
464 255,
465 65535
466 ],
467 "rptUint64": [
468 "3735928559"
469 ],
470 "rptFloat": [
471 "NaN",
472 "Infinity",
473 "-Infinity",
474 1.034
475 ],
476 "rptDouble": [
477 "NaN",
478 "Infinity",
479 "-Infinity",
480 1.23e-308
481 ],
482 "rptString": [
483 "hello",
484 "世界"
485 ],
486 "rptBytes": [
487 "aGVsbG8=",
488 "5LiW55WM"
489 ]
490}`,
491 }, {
492 desc: "repeated enums",
493 input: &pb2.Enums{
494 RptEnum: []pb2.Enum{pb2.Enum_ONE, 2, pb2.Enum_TEN, 42},
495 RptNestedEnum: []pb2.Enums_NestedEnum{2, 47, 10},
496 },
497 want: `{
498 "rptEnum": [
499 "ONE",
500 "TWO",
501 "TEN",
502 42
503 ],
504 "rptNestedEnum": [
505 "DOS",
506 47,
507 "DIEZ"
508 ]
509}`,
510 }, {
511 desc: "repeated messages set to empty",
512 input: &pb2.Nests{
513 RptNested: []*pb2.Nested{},
514 Rptgroup: []*pb2.Nests_RptGroup{},
515 },
516 want: "{}",
517 }, {
518 desc: "repeated messages",
519 input: &pb2.Nests{
520 RptNested: []*pb2.Nested{
521 {
522 OptString: scalar.String("repeat nested one"),
523 },
524 {
525 OptString: scalar.String("repeat nested two"),
526 OptNested: &pb2.Nested{
527 OptString: scalar.String("inside repeat nested two"),
528 },
529 },
530 {},
531 },
532 },
533 want: `{
534 "rptNested": [
535 {
536 "optString": "repeat nested one"
537 },
538 {
539 "optString": "repeat nested two",
540 "optNested": {
541 "optString": "inside repeat nested two"
542 }
543 },
544 {}
545 ]
546}`,
547 }, {
548 desc: "repeated messages contains nil value",
549 input: &pb2.Nests{
550 RptNested: []*pb2.Nested{nil, {}},
551 },
552 want: `{
553 "rptNested": [
554 {},
555 {}
556 ]
557}`,
558 }, {
559 desc: "repeated groups",
560 input: &pb2.Nests{
561 Rptgroup: []*pb2.Nests_RptGroup{
562 {
563 RptString: []string{"hello", "world"},
564 },
565 {},
566 nil,
567 },
568 },
569 want: `{
570 "rptgroup": [
571 {
572 "rptString": [
573 "hello",
574 "world"
575 ]
576 },
577 {},
578 {}
579 ]
580}`,
581 }, {
582 desc: "map fields not set",
583 input: &pb3.Maps{},
584 want: "{}",
585 }, {
586 desc: "map fields set to empty",
587 input: &pb3.Maps{
588 Int32ToStr: map[int32]string{},
589 BoolToUint32: map[bool]uint32{},
590 Uint64ToEnum: map[uint64]pb3.Enum{},
591 StrToNested: map[string]*pb3.Nested{},
592 StrToOneofs: map[string]*pb3.Oneofs{},
593 },
594 want: "{}",
595 }, {
596 desc: "map fields 1",
597 input: &pb3.Maps{
598 BoolToUint32: map[bool]uint32{
599 true: 42,
600 false: 101,
601 },
602 },
603 want: `{
604 "boolToUint32": {
605 "false": 101,
606 "true": 42
607 }
608}`,
609 }, {
610 desc: "map fields 2",
611 input: &pb3.Maps{
612 Int32ToStr: map[int32]string{
613 -101: "-101",
614 0xff: "0xff",
615 0: "zero",
616 },
617 },
618 want: `{
619 "int32ToStr": {
620 "-101": "-101",
621 "0": "zero",
622 "255": "0xff"
623 }
624}`,
625 }, {
626 desc: "map fields 3",
627 input: &pb3.Maps{
628 Uint64ToEnum: map[uint64]pb3.Enum{
629 1: pb3.Enum_ONE,
630 2: pb3.Enum_TWO,
631 10: pb3.Enum_TEN,
632 47: 47,
633 },
634 },
635 want: `{
636 "uint64ToEnum": {
637 "1": "ONE",
638 "2": "TWO",
639 "10": "TEN",
640 "47": 47
641 }
642}`,
643 }, {
644 desc: "map fields 4",
645 input: &pb3.Maps{
646 StrToNested: map[string]*pb3.Nested{
647 "nested": &pb3.Nested{
648 SString: "nested in a map",
649 },
650 },
651 },
652 want: `{
653 "strToNested": {
654 "nested": {
655 "sString": "nested in a map"
656 }
657 }
658}`,
659 }, {
660 desc: "map fields 5",
661 input: &pb3.Maps{
662 StrToOneofs: map[string]*pb3.Oneofs{
663 "string": &pb3.Oneofs{
664 Union: &pb3.Oneofs_OneofString{
665 OneofString: "hello",
666 },
667 },
668 "nested": &pb3.Oneofs{
669 Union: &pb3.Oneofs_OneofNested{
670 OneofNested: &pb3.Nested{
671 SString: "nested oneof in map field value",
672 },
673 },
674 },
675 },
676 },
677 want: `{
678 "strToOneofs": {
679 "nested": {
680 "oneofNested": {
681 "sString": "nested oneof in map field value"
682 }
683 },
684 "string": {
685 "oneofString": "hello"
686 }
687 }
688}`,
689 }, {
690 desc: "map field contains nil value",
691 input: &pb3.Maps{
692 StrToNested: map[string]*pb3.Nested{
693 "nil": nil,
694 },
695 },
696 want: `{
697 "strToNested": {
698 "nil": {}
699 }
700}`,
701 }, {
702 desc: "unknown fields are ignored",
703 input: &pb2.Scalars{
704 OptString: scalar.String("no unknowns"),
705 XXX_unrecognized: pack.Message{
706 pack.Tag{101, pack.BytesType}, pack.String("hello world"),
707 }.Marshal(),
708 },
709 want: `{
710 "optString": "no unknowns"
711}`,
712 }, {
713 desc: "json_name",
714 input: &pb3.JSONNames{
715 SString: "json_name",
716 },
717 want: `{
718 "foo_bar": "json_name"
719}`,
Herbie Ongf83d5bb2019-03-14 00:01:27 -0700720 }, {
721 desc: "extensions of non-repeated fields",
722 input: func() proto.Message {
723 m := &pb2.Extensions{
724 OptString: scalar.String("non-extension field"),
725 OptBool: scalar.Bool(true),
726 OptInt32: scalar.Int32(42),
727 }
728 setExtension(m, pb2.E_OptExtBool, true)
729 setExtension(m, pb2.E_OptExtString, "extension field")
730 setExtension(m, pb2.E_OptExtEnum, pb2.Enum_TEN)
731 setExtension(m, pb2.E_OptExtNested, &pb2.Nested{
732 OptString: scalar.String("nested in an extension"),
733 OptNested: &pb2.Nested{
734 OptString: scalar.String("another nested in an extension"),
735 },
736 })
737 return m
738 }(),
739 want: `{
740 "optString": "non-extension field",
741 "optBool": true,
742 "optInt32": 42,
743 "[pb2.opt_ext_bool]": true,
744 "[pb2.opt_ext_enum]": "TEN",
745 "[pb2.opt_ext_nested]": {
746 "optString": "nested in an extension",
747 "optNested": {
748 "optString": "another nested in an extension"
749 }
750 },
751 "[pb2.opt_ext_string]": "extension field"
752}`,
753 }, {
754 desc: "extension message field set to nil",
755 input: func() proto.Message {
756 m := &pb2.Extensions{}
757 setExtension(m, pb2.E_OptExtNested, nil)
758 return m
759 }(),
760 want: "{}",
761 }, {
762 desc: "extensions of repeated fields",
763 input: func() proto.Message {
764 m := &pb2.Extensions{}
765 setExtension(m, pb2.E_RptExtEnum, &[]pb2.Enum{pb2.Enum_TEN, 101, pb2.Enum_ONE})
766 setExtension(m, pb2.E_RptExtFixed32, &[]uint32{42, 47})
767 setExtension(m, pb2.E_RptExtNested, &[]*pb2.Nested{
768 &pb2.Nested{OptString: scalar.String("one")},
769 &pb2.Nested{OptString: scalar.String("two")},
770 &pb2.Nested{OptString: scalar.String("three")},
771 })
772 return m
773 }(),
774 want: `{
775 "[pb2.rpt_ext_enum]": [
776 "TEN",
777 101,
778 "ONE"
779 ],
780 "[pb2.rpt_ext_fixed32]": [
781 42,
782 47
783 ],
784 "[pb2.rpt_ext_nested]": [
785 {
786 "optString": "one"
787 },
788 {
789 "optString": "two"
790 },
791 {
792 "optString": "three"
793 }
794 ]
795}`,
796 }, {
797 desc: "extensions of non-repeated fields in another message",
798 input: func() proto.Message {
799 m := &pb2.Extensions{}
800 setExtension(m, pb2.E_ExtensionsContainer_OptExtBool, true)
801 setExtension(m, pb2.E_ExtensionsContainer_OptExtString, "extension field")
802 setExtension(m, pb2.E_ExtensionsContainer_OptExtEnum, pb2.Enum_TEN)
803 setExtension(m, pb2.E_ExtensionsContainer_OptExtNested, &pb2.Nested{
804 OptString: scalar.String("nested in an extension"),
805 OptNested: &pb2.Nested{
806 OptString: scalar.String("another nested in an extension"),
807 },
808 })
809 return m
810 }(),
811 want: `{
812 "[pb2.ExtensionsContainer.opt_ext_bool]": true,
813 "[pb2.ExtensionsContainer.opt_ext_enum]": "TEN",
814 "[pb2.ExtensionsContainer.opt_ext_nested]": {
815 "optString": "nested in an extension",
816 "optNested": {
817 "optString": "another nested in an extension"
818 }
819 },
820 "[pb2.ExtensionsContainer.opt_ext_string]": "extension field"
821}`,
822 }, {
823 desc: "extensions of repeated fields in another message",
824 input: func() proto.Message {
825 m := &pb2.Extensions{
826 OptString: scalar.String("non-extension field"),
827 OptBool: scalar.Bool(true),
828 OptInt32: scalar.Int32(42),
829 }
830 setExtension(m, pb2.E_ExtensionsContainer_RptExtEnum, &[]pb2.Enum{pb2.Enum_TEN, 101, pb2.Enum_ONE})
831 setExtension(m, pb2.E_ExtensionsContainer_RptExtString, &[]string{"hello", "world"})
832 setExtension(m, pb2.E_ExtensionsContainer_RptExtNested, &[]*pb2.Nested{
833 &pb2.Nested{OptString: scalar.String("one")},
834 &pb2.Nested{OptString: scalar.String("two")},
835 &pb2.Nested{OptString: scalar.String("three")},
836 })
837 return m
838 }(),
839 want: `{
840 "optString": "non-extension field",
841 "optBool": true,
842 "optInt32": 42,
843 "[pb2.ExtensionsContainer.rpt_ext_enum]": [
844 "TEN",
845 101,
846 "ONE"
847 ],
848 "[pb2.ExtensionsContainer.rpt_ext_nested]": [
849 {
850 "optString": "one"
851 },
852 {
853 "optString": "two"
854 },
855 {
856 "optString": "three"
857 }
858 ],
859 "[pb2.ExtensionsContainer.rpt_ext_string]": [
860 "hello",
861 "world"
862 ]
863}`,
864 }, {
865 desc: "MessageSet",
866 input: func() proto.Message {
867 m := &pb2.MessageSet{}
868 setExtension(m, pb2.E_MessageSetExtension_MessageSetExtension, &pb2.MessageSetExtension{
869 OptString: scalar.String("a messageset extension"),
870 })
871 setExtension(m, pb2.E_MessageSetExtension_NotMessageSetExtension, &pb2.MessageSetExtension{
872 OptString: scalar.String("not a messageset extension"),
873 })
874 setExtension(m, pb2.E_MessageSetExtension_ExtNested, &pb2.Nested{
875 OptString: scalar.String("just a regular extension"),
876 })
877 return m
878 }(),
879 want: `{
880 "[pb2.MessageSetExtension]": {
881 "optString": "a messageset extension"
882 },
883 "[pb2.MessageSetExtension.ext_nested]": {
884 "optString": "just a regular extension"
885 },
886 "[pb2.MessageSetExtension.not_message_set_extension]": {
887 "optString": "not a messageset extension"
888 }
889}`,
890 }, {
891 desc: "not real MessageSet 1",
892 input: func() proto.Message {
893 m := &pb2.FakeMessageSet{}
894 setExtension(m, pb2.E_FakeMessageSetExtension_MessageSetExtension, &pb2.FakeMessageSetExtension{
895 OptString: scalar.String("not a messageset extension"),
896 })
897 return m
898 }(),
899 want: `{
900 "[pb2.FakeMessageSetExtension.message_set_extension]": {
901 "optString": "not a messageset extension"
902 }
903}`,
904 }, {
905 desc: "not real MessageSet 2",
906 input: func() proto.Message {
907 m := &pb2.MessageSet{}
908 setExtension(m, pb2.E_MessageSetExtension, &pb2.FakeMessageSetExtension{
909 OptString: scalar.String("another not a messageset extension"),
910 })
911 return m
912 }(),
913 want: `{
914 "[pb2.message_set_extension]": {
915 "optString": "another not a messageset extension"
916 }
917}`,
Herbie Ong7b828bc2019-02-08 19:56:24 -0800918 }}
919
920 for _, tt := range tests {
921 tt := tt
922 t.Run(tt.desc, func(t *testing.T) {
Herbie Ong7b828bc2019-02-08 19:56:24 -0800923 b, err := tt.mo.Marshal(tt.input)
924 if err != nil {
925 t.Errorf("Marshal() returned error: %v\n", err)
926 }
927 got := string(b)
928 if got != tt.want {
929 t.Errorf("Marshal()\n<got>\n%v\n<want>\n%v\n", got, tt.want)
930 if diff := cmp.Diff(tt.want, got, splitLines); diff != "" {
931 t.Errorf("Marshal() diff -want +got\n%v\n", diff)
932 }
933 }
934 })
935 }
936}