blob: 8b7974e91b4ea080522c2d6be731dfde337809da [file] [log] [blame]
Herbie Ongcddf8192018-11-28 18:25:20 -08001// Copyright 2018 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 textpb_test
6
7import (
8 "math"
9 "strings"
10 "testing"
11
Herbie Ongcf253082018-12-17 17:13:07 -080012 "github.com/golang/protobuf/protoapi"
Herbie Ongcddf8192018-11-28 18:25:20 -080013 "github.com/golang/protobuf/v2/encoding/textpb"
Herbie Ongcddf8192018-11-28 18:25:20 -080014 "github.com/golang/protobuf/v2/internal/detrand"
Herbie Ong20a1d312018-12-11 21:08:58 -080015 "github.com/golang/protobuf/v2/internal/encoding/pack"
Herbie Ongcf253082018-12-17 17:13:07 -080016 "github.com/golang/protobuf/v2/internal/encoding/wire"
17 "github.com/golang/protobuf/v2/internal/legacy"
Herbie Ongcddf8192018-11-28 18:25:20 -080018 "github.com/golang/protobuf/v2/internal/scalar"
19 "github.com/golang/protobuf/v2/proto"
20 "github.com/google/go-cmp/cmp"
21 "github.com/google/go-cmp/cmp/cmpopts"
22
Joe Tsai08e00302018-11-26 22:32:06 -080023 // The legacy package must be imported prior to use of any legacy messages.
24 // TODO: Remove this when protoV1 registers these hooks for you.
25 _ "github.com/golang/protobuf/v2/internal/legacy"
26
Joe Tsai08e00302018-11-26 22:32:06 -080027 "github.com/golang/protobuf/v2/encoding/textpb/testprotos/pb2"
28 "github.com/golang/protobuf/v2/encoding/textpb/testprotos/pb3"
Herbie Ongcddf8192018-11-28 18:25:20 -080029)
30
31func init() {
32 // Disable detrand to enable direct comparisons on outputs.
33 detrand.Disable()
34}
35
Herbie Ongcddf8192018-11-28 18:25:20 -080036// splitLines is a cmpopts.Option for comparing strings with line breaks.
37var splitLines = cmpopts.AcyclicTransformer("SplitLines", func(s string) []string {
38 return strings.Split(s, "\n")
39})
40
Herbie Ong800c9902018-12-06 15:28:53 -080041func pb2Enum(i int32) *pb2.Enum {
42 p := new(pb2.Enum)
43 *p = pb2.Enum(i)
44 return p
45}
46
47func pb2Enums_NestedEnum(i int32) *pb2.Enums_NestedEnum {
48 p := new(pb2.Enums_NestedEnum)
49 *p = pb2.Enums_NestedEnum(i)
50 return p
51}
52
Herbie Ongcf253082018-12-17 17:13:07 -080053func setExtension(m proto.Message, xd *protoapi.ExtensionDesc, val interface{}) {
54 xt := legacy.Export{}.ExtensionTypeFromDesc(xd)
55 knownFields := m.ProtoReflect().KnownFields()
56 extTypes := knownFields.ExtensionTypes()
57 extTypes.Register(xt)
58 if val == nil {
59 return
60 }
61 pval := xt.ValueOf(val)
62 knownFields.Set(wire.Number(xd.Field), pval)
63}
64
Herbie Ongcddf8192018-11-28 18:25:20 -080065func TestMarshal(t *testing.T) {
66 tests := []struct {
67 desc string
Herbie Ong70651952018-12-13 14:19:50 -080068 input proto.Message
Herbie Ongcddf8192018-11-28 18:25:20 -080069 want string
70 wantErr bool
71 }{{
Herbie Ongcddf8192018-11-28 18:25:20 -080072 desc: "proto2 optional scalar fields not set",
Herbie Ong800c9902018-12-06 15:28:53 -080073 input: &pb2.Scalars{},
Herbie Ongcddf8192018-11-28 18:25:20 -080074 want: "\n",
75 }, {
76 desc: "proto3 scalar fields not set",
Herbie Ong800c9902018-12-06 15:28:53 -080077 input: &pb3.Scalars{},
Herbie Ongcddf8192018-11-28 18:25:20 -080078 want: "\n",
79 }, {
80 desc: "proto2 optional scalar fields set to zero values",
Herbie Ong800c9902018-12-06 15:28:53 -080081 input: &pb2.Scalars{
Herbie Ongcddf8192018-11-28 18:25:20 -080082 OptBool: scalar.Bool(false),
83 OptInt32: scalar.Int32(0),
84 OptInt64: scalar.Int64(0),
85 OptUint32: scalar.Uint32(0),
86 OptUint64: scalar.Uint64(0),
87 OptSint32: scalar.Int32(0),
88 OptSint64: scalar.Int64(0),
89 OptFixed32: scalar.Uint32(0),
90 OptFixed64: scalar.Uint64(0),
91 OptSfixed32: scalar.Int32(0),
92 OptSfixed64: scalar.Int64(0),
93 OptFloat: scalar.Float32(0),
94 OptDouble: scalar.Float64(0),
95 OptBytes: []byte{},
96 OptString: scalar.String(""),
Herbie Ong800c9902018-12-06 15:28:53 -080097 },
Herbie Ongcddf8192018-11-28 18:25:20 -080098 want: `opt_bool: false
99opt_int32: 0
100opt_int64: 0
101opt_uint32: 0
102opt_uint64: 0
103opt_sint32: 0
104opt_sint64: 0
105opt_fixed32: 0
106opt_fixed64: 0
107opt_sfixed32: 0
108opt_sfixed64: 0
109opt_float: 0
110opt_double: 0
111opt_bytes: ""
112opt_string: ""
113`,
114 }, {
115 desc: "proto3 scalar fields set to zero values",
Herbie Ong800c9902018-12-06 15:28:53 -0800116 input: &pb3.Scalars{
Herbie Ongcddf8192018-11-28 18:25:20 -0800117 SBool: false,
118 SInt32: 0,
119 SInt64: 0,
120 SUint32: 0,
121 SUint64: 0,
122 SSint32: 0,
123 SSint64: 0,
124 SFixed32: 0,
125 SFixed64: 0,
126 SSfixed32: 0,
127 SSfixed64: 0,
128 SFloat: 0,
129 SDouble: 0,
130 SBytes: []byte{},
131 SString: "",
Herbie Ong800c9902018-12-06 15:28:53 -0800132 },
Herbie Ongcddf8192018-11-28 18:25:20 -0800133 want: "\n",
134 }, {
135 desc: "proto2 optional scalar fields set to some values",
Herbie Ong800c9902018-12-06 15:28:53 -0800136 input: &pb2.Scalars{
Herbie Ongcddf8192018-11-28 18:25:20 -0800137 OptBool: scalar.Bool(true),
138 OptInt32: scalar.Int32(0xff),
139 OptInt64: scalar.Int64(0xdeadbeef),
140 OptUint32: scalar.Uint32(47),
141 OptUint64: scalar.Uint64(0xdeadbeef),
142 OptSint32: scalar.Int32(-1001),
143 OptSint64: scalar.Int64(-0xffff),
144 OptFixed64: scalar.Uint64(64),
145 OptSfixed32: scalar.Int32(-32),
146 // TODO: Update encoder to output same decimals.
147 OptFloat: scalar.Float32(1.02),
148 OptDouble: scalar.Float64(1.23e100),
149 // TODO: Update encoder to not output UTF8 for bytes.
150 OptBytes: []byte("\xe8\xb0\xb7\xe6\xad\x8c"),
151 OptString: scalar.String("谷歌"),
Herbie Ong800c9902018-12-06 15:28:53 -0800152 },
Herbie Ongcddf8192018-11-28 18:25:20 -0800153 want: `opt_bool: true
154opt_int32: 255
155opt_int64: 3735928559
156opt_uint32: 47
157opt_uint64: 3735928559
158opt_sint32: -1001
159opt_sint64: -65535
160opt_fixed64: 64
161opt_sfixed32: -32
162opt_float: 1.0199999809265137
163opt_double: 1.23e+100
164opt_bytes: "谷歌"
165opt_string: "谷歌"
166`,
167 }, {
Herbie Ongcddf8192018-11-28 18:25:20 -0800168 desc: "float32 nan",
Herbie Ong800c9902018-12-06 15:28:53 -0800169 input: &pb3.Scalars{
Herbie Ongcddf8192018-11-28 18:25:20 -0800170 SFloat: float32(math.NaN()),
Herbie Ong800c9902018-12-06 15:28:53 -0800171 },
Herbie Ongcddf8192018-11-28 18:25:20 -0800172 want: "s_float: nan\n",
173 }, {
174 desc: "float32 positive infinity",
Herbie Ong800c9902018-12-06 15:28:53 -0800175 input: &pb3.Scalars{
Herbie Ongcddf8192018-11-28 18:25:20 -0800176 SFloat: float32(math.Inf(1)),
Herbie Ong800c9902018-12-06 15:28:53 -0800177 },
Herbie Ongcddf8192018-11-28 18:25:20 -0800178 want: "s_float: inf\n",
179 }, {
180 desc: "float32 negative infinity",
Herbie Ong800c9902018-12-06 15:28:53 -0800181 input: &pb3.Scalars{
Herbie Ongcddf8192018-11-28 18:25:20 -0800182 SFloat: float32(math.Inf(-1)),
Herbie Ong800c9902018-12-06 15:28:53 -0800183 },
Herbie Ongcddf8192018-11-28 18:25:20 -0800184 want: "s_float: -inf\n",
185 }, {
186 desc: "float64 nan",
Herbie Ong800c9902018-12-06 15:28:53 -0800187 input: &pb3.Scalars{
Herbie Ongcddf8192018-11-28 18:25:20 -0800188 SDouble: math.NaN(),
Herbie Ong800c9902018-12-06 15:28:53 -0800189 },
Herbie Ongcddf8192018-11-28 18:25:20 -0800190 want: "s_double: nan\n",
191 }, {
192 desc: "float64 positive infinity",
Herbie Ong800c9902018-12-06 15:28:53 -0800193 input: &pb3.Scalars{
Herbie Ongcddf8192018-11-28 18:25:20 -0800194 SDouble: math.Inf(1),
Herbie Ong800c9902018-12-06 15:28:53 -0800195 },
Herbie Ongcddf8192018-11-28 18:25:20 -0800196 want: "s_double: inf\n",
197 }, {
198 desc: "float64 negative infinity",
Herbie Ong800c9902018-12-06 15:28:53 -0800199 input: &pb3.Scalars{
Herbie Ongcddf8192018-11-28 18:25:20 -0800200 SDouble: math.Inf(-1),
Herbie Ong800c9902018-12-06 15:28:53 -0800201 },
Herbie Ongcddf8192018-11-28 18:25:20 -0800202 want: "s_double: -inf\n",
203 }, {
204 desc: "proto2 bytes set to empty string",
Herbie Ong800c9902018-12-06 15:28:53 -0800205 input: &pb2.Scalars{
Herbie Ongcddf8192018-11-28 18:25:20 -0800206 OptBytes: []byte(""),
Herbie Ong800c9902018-12-06 15:28:53 -0800207 },
Herbie Ongcddf8192018-11-28 18:25:20 -0800208 want: "opt_bytes: \"\"\n",
209 }, {
210 desc: "proto3 bytes set to empty string",
Herbie Ong800c9902018-12-06 15:28:53 -0800211 input: &pb3.Scalars{
Herbie Ongcddf8192018-11-28 18:25:20 -0800212 SBytes: []byte(""),
Herbie Ong800c9902018-12-06 15:28:53 -0800213 },
Herbie Ongcddf8192018-11-28 18:25:20 -0800214 want: "\n",
215 }, {
Herbie Ong800c9902018-12-06 15:28:53 -0800216 desc: "proto2 enum not set",
217 input: &pb2.Enums{},
Herbie Ongcddf8192018-11-28 18:25:20 -0800218 want: "\n",
219 }, {
Herbie Ong800c9902018-12-06 15:28:53 -0800220 desc: "proto2 enum set to zero value",
221 input: &pb2.Enums{
222 OptEnum: pb2.Enum_UNKNOWN.Enum(),
223 OptNestedEnum: pb2Enums_NestedEnum(0),
224 },
225 want: `opt_enum: UNKNOWN
226opt_nested_enum: 0
227`,
228 }, {
229 desc: "proto2 enum",
230 input: &pb2.Enums{
231 OptEnum: pb2.Enum_FIRST.Enum(),
232 OptNestedEnum: pb2.Enums_UNO.Enum(),
233 },
234 want: `opt_enum: FIRST
235opt_nested_enum: UNO
236`,
237 }, {
238 desc: "proto2 enum set to numeric values",
239 input: &pb2.Enums{
240 OptEnum: pb2Enum(1),
241 OptNestedEnum: pb2Enums_NestedEnum(2),
242 },
243 want: `opt_enum: FIRST
244opt_nested_enum: DOS
245`,
246 }, {
247 desc: "proto2 enum set to unnamed numeric values",
248 input: &pb2.Enums{
249 OptEnum: pb2Enum(101),
250 OptNestedEnum: pb2Enums_NestedEnum(-101),
251 },
252 want: `opt_enum: 101
253opt_nested_enum: -101
254`,
255 }, {
256 desc: "proto3 enum not set",
257 input: &pb3.Enums{},
258 want: "\n",
259 }, {
260 desc: "proto3 enum set to zero value",
261 input: &pb3.Enums{
262 SEnum: pb3.Enum_ZERO,
263 SNestedEnum: pb3.Enums_CERO,
264 },
265 want: "\n",
266 }, {
267 desc: "proto3 enum",
268 input: &pb3.Enums{
269 SEnum: pb3.Enum_ONE,
270 SNestedEnum: pb3.Enums_DIEZ,
271 },
272 want: `s_enum: ONE
273s_nested_enum: DIEZ
274`,
275 }, {
276 desc: "proto3 enum set to numeric values",
277 input: &pb3.Enums{
278 SEnum: 2,
279 SNestedEnum: 1,
280 },
281 want: `s_enum: TWO
282s_nested_enum: UNO
283`,
284 }, {
285 desc: "proto3 enum set to unnamed numeric values",
286 input: &pb3.Enums{
287 SEnum: -47,
288 SNestedEnum: 47,
289 },
290 want: `s_enum: -47
291s_nested_enum: 47
292`,
293 }, {
294 desc: "proto2 nested message not set",
295 input: &pb2.Nests{},
296 want: "\n",
297 }, {
298 desc: "proto2 nested message set to empty",
299 input: &pb2.Nests{
300 OptNested: &pb2.Nested{},
301 Optgroup: &pb2.Nests_OptGroup{},
302 },
303 want: `opt_nested: {}
304optgroup: {}
305`,
306 }, {
307 desc: "proto2 nested messages",
308 input: &pb2.Nests{
309 OptNested: &pb2.Nested{
310 OptString: scalar.String("nested message"),
311 OptNested: &pb2.Nested{
312 OptString: scalar.String("another nested message"),
313 },
314 },
315 },
316 want: `opt_nested: {
317 opt_string: "nested message"
318 opt_nested: {
319 opt_string: "another nested message"
320 }
321}
322`,
323 }, {
324 desc: "proto2 group fields",
325 input: &pb2.Nests{
326 Optgroup: &pb2.Nests_OptGroup{
327 OptBool: scalar.Bool(true),
328 OptString: scalar.String("inside a group"),
329 OptNested: &pb2.Nested{
330 OptString: scalar.String("nested message inside a group"),
331 },
332 Optnestedgroup: &pb2.Nests_OptGroup_OptNestedGroup{
333 OptEnum: pb2.Enum_TENTH.Enum(),
334 },
335 },
336 },
337 want: `optgroup: {
338 opt_bool: true
339 opt_string: "inside a group"
340 opt_nested: {
341 opt_string: "nested message inside a group"
342 }
343 optnestedgroup: {
344 opt_enum: TENTH
345 }
346}
347`,
348 }, {
349 desc: "proto3 nested message not set",
350 input: &pb3.Nests{},
351 want: "\n",
352 }, {
353 desc: "proto3 nested message",
354 input: &pb3.Nests{
355 SNested: &pb3.Nested{
356 SString: "nested message",
357 SNested: &pb3.Nested{
358 SString: "another nested message",
359 },
360 },
361 },
362 want: `s_nested: {
363 s_string: "nested message"
364 s_nested: {
365 s_string: "another nested message"
366 }
367}
368`,
369 }, {
370 desc: "oneof fields",
371 input: &pb2.Oneofs{},
372 want: "\n",
373 }, {
374 desc: "oneof field set to empty string",
375 input: &pb2.Oneofs{
376 Union: &pb2.Oneofs_Str{},
377 },
378 want: "str: \"\"\n",
379 }, {
380 desc: "oneof field set to string",
381 input: &pb2.Oneofs{
382 Union: &pb2.Oneofs_Str{
383 Str: "hello",
384 },
385 },
386 want: "str: \"hello\"\n",
387 }, {
388 desc: "oneof field set to empty message",
389 input: &pb2.Oneofs{
390 Union: &pb2.Oneofs_Msg{
391 Msg: &pb2.Nested{},
392 },
393 },
394 want: "msg: {}\n",
395 }, {
396 desc: "oneof field set to message",
397 input: &pb2.Oneofs{
398 Union: &pb2.Oneofs_Msg{
399 Msg: &pb2.Nested{
400 OptString: scalar.String("nested message"),
401 },
402 },
403 },
404 want: `msg: {
405 opt_string: "nested message"
406}
407`,
408 }, {
409 desc: "repeated not set",
410 input: &pb2.Repeats{},
411 want: "\n",
412 }, {
413 desc: "repeated set to empty slices",
414 input: &pb2.Repeats{
Herbie Ongcddf8192018-11-28 18:25:20 -0800415 RptBool: []bool{},
416 RptInt32: []int32{},
417 RptInt64: []int64{},
418 RptUint32: []uint32{},
419 RptUint64: []uint64{},
420 RptFloat: []float32{},
421 RptDouble: []float64{},
422 RptBytes: [][]byte{},
Herbie Ong800c9902018-12-06 15:28:53 -0800423 },
Herbie Ongcddf8192018-11-28 18:25:20 -0800424 want: "\n",
425 }, {
Herbie Ong800c9902018-12-06 15:28:53 -0800426 desc: "repeated set to some values",
427 input: &pb2.Repeats{
Herbie Ongcddf8192018-11-28 18:25:20 -0800428 RptBool: []bool{true, false, true, true},
429 RptInt32: []int32{1, 6, 0, 0},
430 RptInt64: []int64{-64, 47},
431 RptUint32: []uint32{0xff, 0xffff},
432 RptUint64: []uint64{0xdeadbeef},
433 // TODO: add float32 examples.
434 RptDouble: []float64{math.NaN(), math.Inf(1), math.Inf(-1), 1.23e-308},
435 RptString: []string{"hello", "世界"},
436 RptBytes: [][]byte{
437 []byte("hello"),
438 []byte("\xe4\xb8\x96\xe7\x95\x8c"),
439 },
Herbie Ong800c9902018-12-06 15:28:53 -0800440 },
Herbie Ongcddf8192018-11-28 18:25:20 -0800441 want: `rpt_bool: true
442rpt_bool: false
443rpt_bool: true
444rpt_bool: true
445rpt_int32: 1
446rpt_int32: 6
447rpt_int32: 0
448rpt_int32: 0
449rpt_int64: -64
450rpt_int64: 47
451rpt_uint32: 255
452rpt_uint32: 65535
453rpt_uint64: 3735928559
454rpt_double: nan
455rpt_double: inf
456rpt_double: -inf
457rpt_double: 1.23e-308
458rpt_string: "hello"
459rpt_string: "世界"
460rpt_bytes: "hello"
461rpt_bytes: "世界"
462`,
463 }, {
Herbie Ong800c9902018-12-06 15:28:53 -0800464 desc: "repeated enum",
465 input: &pb2.Enums{
Herbie Ongcddf8192018-11-28 18:25:20 -0800466 RptEnum: []pb2.Enum{pb2.Enum_FIRST, 2, pb2.Enum_TENTH, 42},
Herbie Ongcddf8192018-11-28 18:25:20 -0800467 RptNestedEnum: []pb2.Enums_NestedEnum{2, 47, 10},
Herbie Ong800c9902018-12-06 15:28:53 -0800468 },
469 want: `rpt_enum: FIRST
Herbie Ongcddf8192018-11-28 18:25:20 -0800470rpt_enum: SECOND
471rpt_enum: TENTH
472rpt_enum: 42
Herbie Ongcddf8192018-11-28 18:25:20 -0800473rpt_nested_enum: DOS
474rpt_nested_enum: 47
475rpt_nested_enum: DIEZ
476`,
477 }, {
Herbie Ong800c9902018-12-06 15:28:53 -0800478 desc: "repeated nested message set to empty",
479 input: &pb2.Nests{
Herbie Ongcddf8192018-11-28 18:25:20 -0800480 RptNested: []*pb2.Nested{},
481 Rptgroup: []*pb2.Nests_RptGroup{},
Herbie Ong800c9902018-12-06 15:28:53 -0800482 },
483 want: "\n",
Herbie Ongcddf8192018-11-28 18:25:20 -0800484 }, {
Herbie Ong800c9902018-12-06 15:28:53 -0800485 desc: "repeated nested messages",
486 input: &pb2.Nests{
Herbie Ongcddf8192018-11-28 18:25:20 -0800487 RptNested: []*pb2.Nested{
488 {
489 OptString: scalar.String("repeat nested one"),
490 },
491 {
492 OptString: scalar.String("repeat nested two"),
493 OptNested: &pb2.Nested{
494 OptString: scalar.String("inside repeat nested two"),
495 },
496 },
497 {},
498 },
Herbie Ong800c9902018-12-06 15:28:53 -0800499 },
500 want: `rpt_nested: {
Herbie Ongcddf8192018-11-28 18:25:20 -0800501 opt_string: "repeat nested one"
502}
503rpt_nested: {
504 opt_string: "repeat nested two"
505 opt_nested: {
506 opt_string: "inside repeat nested two"
507 }
508}
509rpt_nested: {}
510`,
511 }, {
Herbie Ong800c9902018-12-06 15:28:53 -0800512 desc: "repeated group fields",
513 input: &pb2.Nests{
Herbie Ongcddf8192018-11-28 18:25:20 -0800514 Rptgroup: []*pb2.Nests_RptGroup{
515 {
516 RptBool: []bool{true, false},
517 },
518 {},
519 },
Herbie Ong800c9902018-12-06 15:28:53 -0800520 },
521 want: `rptgroup: {
Herbie Ongcddf8192018-11-28 18:25:20 -0800522 rpt_bool: true
523 rpt_bool: false
524}
525rptgroup: {}
526`,
527 }, {
Herbie Ongcddf8192018-11-28 18:25:20 -0800528 desc: "map fields empty",
Herbie Ong800c9902018-12-06 15:28:53 -0800529 input: &pb2.Maps{},
Herbie Ongcddf8192018-11-28 18:25:20 -0800530 want: "\n",
531 }, {
532 desc: "map fields set to empty maps",
Herbie Ong800c9902018-12-06 15:28:53 -0800533 input: &pb2.Maps{
Herbie Ongcddf8192018-11-28 18:25:20 -0800534 Int32ToStr: map[int32]string{},
535 Sfixed64ToBool: map[int64]bool{},
536 BoolToUint32: map[bool]uint32{},
537 Uint64ToEnum: map[uint64]pb2.Enum{},
538 StrToNested: map[string]*pb2.Nested{},
539 StrToOneofs: map[string]*pb2.Oneofs{},
Herbie Ong800c9902018-12-06 15:28:53 -0800540 },
Herbie Ongcddf8192018-11-28 18:25:20 -0800541 want: "\n",
542 }, {
543 desc: "map fields 1",
Herbie Ong800c9902018-12-06 15:28:53 -0800544 input: &pb2.Maps{
Herbie Ongcddf8192018-11-28 18:25:20 -0800545 Int32ToStr: map[int32]string{
546 -101: "-101",
547 0xff: "0xff",
548 0: "zero",
549 },
550 Sfixed64ToBool: map[int64]bool{
551 0xcafe: true,
552 0: false,
553 },
554 BoolToUint32: map[bool]uint32{
555 true: 42,
556 false: 101,
557 },
Herbie Ong800c9902018-12-06 15:28:53 -0800558 },
Herbie Ongcddf8192018-11-28 18:25:20 -0800559 want: `int32_to_str: {
560 key: -101
561 value: "-101"
562}
563int32_to_str: {
564 key: 0
565 value: "zero"
566}
567int32_to_str: {
568 key: 255
569 value: "0xff"
570}
571sfixed64_to_bool: {
572 key: 0
573 value: false
574}
575sfixed64_to_bool: {
576 key: 51966
577 value: true
578}
579bool_to_uint32: {
580 key: false
581 value: 101
582}
583bool_to_uint32: {
584 key: true
585 value: 42
586}
587`,
588 }, {
589 desc: "map fields 2",
Herbie Ong800c9902018-12-06 15:28:53 -0800590 input: &pb2.Maps{
Herbie Ongcddf8192018-11-28 18:25:20 -0800591 Uint64ToEnum: map[uint64]pb2.Enum{
592 1: pb2.Enum_FIRST,
593 2: pb2.Enum_SECOND,
594 10: pb2.Enum_TENTH,
595 },
Herbie Ong800c9902018-12-06 15:28:53 -0800596 },
Herbie Ongcddf8192018-11-28 18:25:20 -0800597 want: `uint64_to_enum: {
598 key: 1
599 value: FIRST
600}
601uint64_to_enum: {
602 key: 2
603 value: SECOND
604}
605uint64_to_enum: {
606 key: 10
607 value: TENTH
608}
609`,
610 }, {
611 desc: "map fields 3",
Herbie Ong800c9902018-12-06 15:28:53 -0800612 input: &pb2.Maps{
Herbie Ongcddf8192018-11-28 18:25:20 -0800613 StrToNested: map[string]*pb2.Nested{
614 "nested_one": &pb2.Nested{
615 OptString: scalar.String("nested in a map"),
616 },
617 },
Herbie Ong800c9902018-12-06 15:28:53 -0800618 },
Herbie Ongcddf8192018-11-28 18:25:20 -0800619 want: `str_to_nested: {
620 key: "nested_one"
621 value: {
622 opt_string: "nested in a map"
623 }
624}
625`,
626 }, {
627 desc: "map fields 4",
Herbie Ong800c9902018-12-06 15:28:53 -0800628 input: &pb2.Maps{
Herbie Ongcddf8192018-11-28 18:25:20 -0800629 StrToOneofs: map[string]*pb2.Oneofs{
630 "string": &pb2.Oneofs{
631 Union: &pb2.Oneofs_Str{
632 Str: "hello",
633 },
634 },
635 "nested": &pb2.Oneofs{
636 Union: &pb2.Oneofs_Msg{
637 Msg: &pb2.Nested{
638 OptString: scalar.String("nested oneof in map field value"),
639 },
640 },
641 },
642 },
Herbie Ong800c9902018-12-06 15:28:53 -0800643 },
Herbie Ongcddf8192018-11-28 18:25:20 -0800644 want: `str_to_oneofs: {
645 key: "nested"
646 value: {
647 msg: {
648 opt_string: "nested oneof in map field value"
649 }
650 }
651}
652str_to_oneofs: {
653 key: "string"
654 value: {
655 str: "hello"
656 }
657}
658`,
659 }, {
Herbie Ong800c9902018-12-06 15:28:53 -0800660 desc: "proto2 required fields not set",
661 input: &pb2.Requireds{},
662 want: "\n",
663 wantErr: true,
Herbie Ongcddf8192018-11-28 18:25:20 -0800664 }, {
Herbie Ong800c9902018-12-06 15:28:53 -0800665 desc: "proto2 required fields partially set",
666 input: &pb2.Requireds{
667 ReqBool: scalar.Bool(false),
668 ReqFixed32: scalar.Uint32(47),
669 ReqSfixed64: scalar.Int64(0xbeefcafe),
670 ReqDouble: scalar.Float64(math.NaN()),
671 ReqString: scalar.String("hello"),
672 ReqEnum: pb2.Enum_FIRST.Enum(),
673 },
674 want: `req_bool: false
675req_fixed32: 47
676req_sfixed64: 3203386110
677req_double: nan
678req_string: "hello"
679req_enum: FIRST
680`,
681 wantErr: true,
682 }, {
683 desc: "proto2 required fields all set",
684 input: &pb2.Requireds{
685 ReqBool: scalar.Bool(false),
686 ReqFixed32: scalar.Uint32(0),
687 ReqFixed64: scalar.Uint64(0),
688 ReqSfixed32: scalar.Int32(0),
689 ReqSfixed64: scalar.Int64(0),
690 ReqFloat: scalar.Float32(0),
691 ReqDouble: scalar.Float64(0),
692 ReqString: scalar.String(""),
693 ReqEnum: pb2.Enum_UNKNOWN.Enum(),
694 ReqBytes: []byte{},
695 ReqNested: &pb2.Nested{},
696 },
697 want: `req_bool: false
698req_fixed32: 0
699req_fixed64: 0
700req_sfixed32: 0
701req_sfixed64: 0
702req_float: 0
703req_double: 0
704req_string: ""
705req_bytes: ""
706req_enum: UNKNOWN
707req_nested: {}
Herbie Ongcddf8192018-11-28 18:25:20 -0800708`,
709 }, {
Herbie Ong800c9902018-12-06 15:28:53 -0800710 desc: "indirect required field",
711 input: &pb2.IndirectRequired{
712 OptNested: &pb2.NestedWithRequired{},
713 },
714 want: "opt_nested: {}\n",
715 wantErr: true,
Herbie Ongcddf8192018-11-28 18:25:20 -0800716 }, {
Herbie Ong800c9902018-12-06 15:28:53 -0800717 desc: "indirect required field in empty repeated",
718 input: &pb2.IndirectRequired{
719 RptNested: []*pb2.NestedWithRequired{},
720 },
721 want: "\n",
Herbie Ongcddf8192018-11-28 18:25:20 -0800722 }, {
Herbie Ong800c9902018-12-06 15:28:53 -0800723 desc: "indirect required field in repeated",
724 input: &pb2.IndirectRequired{
725 RptNested: []*pb2.NestedWithRequired{
726 &pb2.NestedWithRequired{},
Herbie Ongcddf8192018-11-28 18:25:20 -0800727 },
Herbie Ong800c9902018-12-06 15:28:53 -0800728 },
729 want: "rpt_nested: {}\n",
730 wantErr: true,
731 }, {
732 desc: "indirect required field in empty map",
733 input: &pb2.IndirectRequired{
734 StrToNested: map[string]*pb2.NestedWithRequired{},
735 },
736 want: "\n",
737 }, {
738 desc: "indirect required field in map",
739 input: &pb2.IndirectRequired{
740 StrToNested: map[string]*pb2.NestedWithRequired{
741 "fail": &pb2.NestedWithRequired{},
742 },
743 },
744 want: `str_to_nested: {
745 key: "fail"
746 value: {}
Herbie Ongcddf8192018-11-28 18:25:20 -0800747}
748`,
Herbie Ong800c9902018-12-06 15:28:53 -0800749 wantErr: true,
Herbie Ong20a1d312018-12-11 21:08:58 -0800750 }, {
751 desc: "unknown varint and fixed types",
752 input: &pb2.Scalars{
753 OptString: scalar.String("this message contains unknown fields"),
754 XXX_unrecognized: pack.Message{
755 pack.Tag{101, pack.VarintType}, pack.Bool(true),
756 pack.Tag{102, pack.VarintType}, pack.Varint(0xff),
757 pack.Tag{103, pack.Fixed32Type}, pack.Uint32(47),
758 pack.Tag{104, pack.Fixed64Type}, pack.Int64(0xdeadbeef),
759 }.Marshal(),
760 },
761 want: `opt_string: "this message contains unknown fields"
762101: 1
763102: 255
764103: 47
765104: 3735928559
766`,
767 }, {
768 desc: "unknown length-delimited",
769 input: &pb2.Scalars{
770 XXX_unrecognized: pack.Message{
771 pack.Tag{101, pack.BytesType}, pack.LengthPrefix{pack.Bool(true), pack.Bool(false)},
772 pack.Tag{102, pack.BytesType}, pack.String("hello world"),
773 pack.Tag{103, pack.BytesType}, pack.Bytes("\xe4\xb8\x96\xe7\x95\x8c"),
774 }.Marshal(),
775 },
776 want: `101: "\x01\x00"
777102: "hello world"
778103: "世界"
779`,
780 }, {
781 desc: "unknown group type",
782 input: &pb2.Scalars{
783 XXX_unrecognized: pack.Message{
784 pack.Tag{101, pack.StartGroupType}, pack.Tag{101, pack.EndGroupType},
785 pack.Tag{102, pack.StartGroupType},
786 pack.Tag{101, pack.VarintType}, pack.Bool(false),
787 pack.Tag{102, pack.BytesType}, pack.String("inside a group"),
788 pack.Tag{102, pack.EndGroupType},
789 }.Marshal(),
790 },
791 want: `101: {}
792102: {
793 101: 0
794 102: "inside a group"
795}
796`,
797 }, {
798 desc: "unknown unpack repeated field",
799 input: &pb2.Scalars{
800 XXX_unrecognized: pack.Message{
801 pack.Tag{101, pack.BytesType}, pack.LengthPrefix{pack.Bool(true), pack.Bool(false), pack.Bool(true)},
802 pack.Tag{102, pack.BytesType}, pack.String("hello"),
803 pack.Tag{101, pack.VarintType}, pack.Bool(true),
804 pack.Tag{102, pack.BytesType}, pack.String("世界"),
805 }.Marshal(),
806 },
807 want: `101: "\x01\x00\x01"
808101: 1
809102: "hello"
810102: "世界"
811`,
Herbie Ongcf253082018-12-17 17:13:07 -0800812 }, {
813 desc: "extensions of non-repeated fields",
814 input: func() proto.Message {
815 m := &pb2.Extensions{
816 OptString: scalar.String("non-extension field"),
817 OptBool: scalar.Bool(true),
818 OptInt32: scalar.Int32(42),
819 }
820 setExtension(m, pb2.E_OptExtBool, true)
821 setExtension(m, pb2.E_OptExtString, "extension field")
822 setExtension(m, pb2.E_OptExtEnum, pb2.Enum_TENTH)
823 setExtension(m, pb2.E_OptExtNested, &pb2.Nested{
824 OptString: scalar.String("nested in an extension"),
825 OptNested: &pb2.Nested{
826 OptString: scalar.String("another nested in an extension"),
827 },
828 })
829 return m
830 }(),
831 want: `opt_string: "non-extension field"
832opt_bool: true
833opt_int32: 42
834[pb2.opt_ext_bool]: true
835[pb2.opt_ext_enum]: TENTH
836[pb2.opt_ext_nested]: {
837 opt_string: "nested in an extension"
838 opt_nested: {
839 opt_string: "another nested in an extension"
840 }
841}
842[pb2.opt_ext_string]: "extension field"
843`,
844 }, {
845 desc: "registered extension but not set",
846 input: func() proto.Message {
847 m := &pb2.Extensions{}
848 setExtension(m, pb2.E_OptExtNested, nil)
849 return m
850 }(),
851 want: "\n",
852 }, {
853 desc: "extensions of repeated fields",
854 input: func() proto.Message {
855 m := &pb2.Extensions{}
856 setExtension(m, pb2.E_RptExtEnum, &[]pb2.Enum{pb2.Enum_TENTH, 101, pb2.Enum_FIRST})
857 setExtension(m, pb2.E_RptExtFixed32, &[]uint32{42, 47})
858 setExtension(m, pb2.E_RptExtNested, &[]*pb2.Nested{
859 &pb2.Nested{OptString: scalar.String("one")},
860 &pb2.Nested{OptString: scalar.String("two")},
861 &pb2.Nested{OptString: scalar.String("three")},
862 })
863 return m
864 }(),
865 want: `[pb2.rpt_ext_enum]: TENTH
866[pb2.rpt_ext_enum]: 101
867[pb2.rpt_ext_enum]: FIRST
868[pb2.rpt_ext_fixed32]: 42
869[pb2.rpt_ext_fixed32]: 47
870[pb2.rpt_ext_nested]: {
871 opt_string: "one"
872}
873[pb2.rpt_ext_nested]: {
874 opt_string: "two"
875}
876[pb2.rpt_ext_nested]: {
877 opt_string: "three"
878}
879`,
880 }, {
881 desc: "extensions of non-repeated fields in another message",
882 input: func() proto.Message {
883 m := &pb2.Extensions{}
884 setExtension(m, pb2.E_ExtensionsContainer_OptExtBool, true)
885 setExtension(m, pb2.E_ExtensionsContainer_OptExtString, "extension field")
886 setExtension(m, pb2.E_ExtensionsContainer_OptExtEnum, pb2.Enum_TENTH)
887 setExtension(m, pb2.E_ExtensionsContainer_OptExtNested, &pb2.Nested{
888 OptString: scalar.String("nested in an extension"),
889 OptNested: &pb2.Nested{
890 OptString: scalar.String("another nested in an extension"),
891 },
892 })
893 return m
894 }(),
895 want: `[pb2.ExtensionsContainer.opt_ext_bool]: true
896[pb2.ExtensionsContainer.opt_ext_enum]: TENTH
897[pb2.ExtensionsContainer.opt_ext_nested]: {
898 opt_string: "nested in an extension"
899 opt_nested: {
900 opt_string: "another nested in an extension"
901 }
902}
903[pb2.ExtensionsContainer.opt_ext_string]: "extension field"
904`,
905 }, {
906 desc: "extensions of repeated fields in another message",
907 input: func() proto.Message {
908 m := &pb2.Extensions{
909 OptString: scalar.String("non-extension field"),
910 OptBool: scalar.Bool(true),
911 OptInt32: scalar.Int32(42),
912 }
913 setExtension(m, pb2.E_ExtensionsContainer_RptExtEnum, &[]pb2.Enum{pb2.Enum_TENTH, 101, pb2.Enum_FIRST})
914 setExtension(m, pb2.E_ExtensionsContainer_RptExtString, &[]string{"hello", "world"})
915 setExtension(m, pb2.E_ExtensionsContainer_RptExtNested, &[]*pb2.Nested{
916 &pb2.Nested{OptString: scalar.String("one")},
917 &pb2.Nested{OptString: scalar.String("two")},
918 &pb2.Nested{OptString: scalar.String("three")},
919 })
920 return m
921 }(),
922 want: `opt_string: "non-extension field"
923opt_bool: true
924opt_int32: 42
925[pb2.ExtensionsContainer.rpt_ext_enum]: TENTH
926[pb2.ExtensionsContainer.rpt_ext_enum]: 101
927[pb2.ExtensionsContainer.rpt_ext_enum]: FIRST
928[pb2.ExtensionsContainer.rpt_ext_nested]: {
929 opt_string: "one"
930}
931[pb2.ExtensionsContainer.rpt_ext_nested]: {
932 opt_string: "two"
933}
934[pb2.ExtensionsContainer.rpt_ext_nested]: {
935 opt_string: "three"
936}
937[pb2.ExtensionsContainer.rpt_ext_string]: "hello"
938[pb2.ExtensionsContainer.rpt_ext_string]: "world"
939`,
940 /* TODO: test for MessageSet
941 }, {
942 desc: "MessageSet",
943 input: func() proto.Message {
944 m := &pb2.MessageSet{}
945 setExtension(m, pb2.E_MessageSetExtension_MessageSetExtension, &pb2.MessageSetExtension{
946 OptString: scalar.String("a messageset extension"),
947 })
948 setExtension(m, pb2.E_MessageSetExtension_NotMessageSetExtension, &pb2.MessageSetExtension{
949 OptString: scalar.String("not a messageset extension"),
950 })
951 setExtension(m, pb2.E_MessageSetExtension_ExtNested, &pb2.Nested{
952 OptString: scalar.String("just a regular extension"),
953 })
954 return m
955 }(),
956 want: `[pb2.MessageSetExtension]: {
957 opt_string: "a messageset extension"
958 }
959 [pb2.MessageSetExtension.ext_nested]: {
960 opt_string: "just a regular extension"
961 }
962 [pb2.MessageSetExtension.not_message_set_extension]: {
963 opt_string: "not a messageset extension"
964 }
965 `,
966 */
Herbie Ongcddf8192018-11-28 18:25:20 -0800967 }}
968
969 for _, tt := range tests {
970 tt := tt
971 t.Run(tt.desc, func(t *testing.T) {
972 t.Parallel()
Herbie Ong70651952018-12-13 14:19:50 -0800973 b, err := textpb.Marshal(tt.input)
Herbie Ongcddf8192018-11-28 18:25:20 -0800974 if err != nil && !tt.wantErr {
975 t.Errorf("Marshal() returned error: %v\n\n", err)
976 }
Herbie Ong800c9902018-12-06 15:28:53 -0800977 if err == nil && tt.wantErr {
978 t.Error("Marshal() got nil error, want error\n\n")
Herbie Ongcddf8192018-11-28 18:25:20 -0800979 }
Herbie Ong800c9902018-12-06 15:28:53 -0800980 got := string(b)
981 if tt.want != "" && got != tt.want {
982 t.Errorf("Marshal()\n<got>\n%v\n<want>\n%v\n", got, tt.want)
983 if diff := cmp.Diff(tt.want, got, splitLines); diff != "" {
Herbie Ongcddf8192018-11-28 18:25:20 -0800984 t.Errorf("Marshal() diff -want +got\n%v\n", diff)
985 }
986 }
987 })
988 }
989}