blob: 9871e7576b55ec707d537e9c912064270ba1a568 [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 (
Herbie Onga94f78c2019-01-03 15:39:58 -08008 "encoding/hex"
Herbie Ongcddf8192018-11-28 18:25:20 -08009 "math"
10 "strings"
11 "testing"
12
Herbie Ongf42b55f2019-01-02 15:46:07 -080013 protoV1 "github.com/golang/protobuf/proto"
Herbie Ongcf253082018-12-17 17:13:07 -080014 "github.com/golang/protobuf/protoapi"
Herbie Ongcddf8192018-11-28 18:25:20 -080015 "github.com/golang/protobuf/v2/encoding/textpb"
Herbie Ongcddf8192018-11-28 18:25:20 -080016 "github.com/golang/protobuf/v2/internal/detrand"
Herbie Ong20a1d312018-12-11 21:08:58 -080017 "github.com/golang/protobuf/v2/internal/encoding/pack"
Herbie Ongcf253082018-12-17 17:13:07 -080018 "github.com/golang/protobuf/v2/internal/encoding/wire"
Herbie Ongf42b55f2019-01-02 15:46:07 -080019 "github.com/golang/protobuf/v2/internal/impl"
Herbie Ongcf253082018-12-17 17:13:07 -080020 "github.com/golang/protobuf/v2/internal/legacy"
Herbie Ongcddf8192018-11-28 18:25:20 -080021 "github.com/golang/protobuf/v2/internal/scalar"
22 "github.com/golang/protobuf/v2/proto"
Herbie Ongf42b55f2019-01-02 15:46:07 -080023 preg "github.com/golang/protobuf/v2/reflect/protoregistry"
Herbie Ongcddf8192018-11-28 18:25:20 -080024 "github.com/google/go-cmp/cmp"
25 "github.com/google/go-cmp/cmp/cmpopts"
26
Joe Tsai08e00302018-11-26 22:32:06 -080027 // The legacy package must be imported prior to use of any legacy messages.
28 // TODO: Remove this when protoV1 registers these hooks for you.
29 _ "github.com/golang/protobuf/v2/internal/legacy"
30
Herbie Ongf42b55f2019-01-02 15:46:07 -080031 anypb "github.com/golang/protobuf/ptypes/any"
Joe Tsai08e00302018-11-26 22:32:06 -080032 "github.com/golang/protobuf/v2/encoding/textpb/testprotos/pb2"
33 "github.com/golang/protobuf/v2/encoding/textpb/testprotos/pb3"
Herbie Ongcddf8192018-11-28 18:25:20 -080034)
35
36func init() {
37 // Disable detrand to enable direct comparisons on outputs.
38 detrand.Disable()
39}
40
Herbie Ongcddf8192018-11-28 18:25:20 -080041// splitLines is a cmpopts.Option for comparing strings with line breaks.
42var splitLines = cmpopts.AcyclicTransformer("SplitLines", func(s string) []string {
43 return strings.Split(s, "\n")
44})
45
Herbie Ong800c9902018-12-06 15:28:53 -080046func pb2Enum(i int32) *pb2.Enum {
47 p := new(pb2.Enum)
48 *p = pb2.Enum(i)
49 return p
50}
51
52func pb2Enums_NestedEnum(i int32) *pb2.Enums_NestedEnum {
53 p := new(pb2.Enums_NestedEnum)
54 *p = pb2.Enums_NestedEnum(i)
55 return p
56}
57
Herbie Ongcf253082018-12-17 17:13:07 -080058func setExtension(m proto.Message, xd *protoapi.ExtensionDesc, val interface{}) {
59 xt := legacy.Export{}.ExtensionTypeFromDesc(xd)
60 knownFields := m.ProtoReflect().KnownFields()
61 extTypes := knownFields.ExtensionTypes()
62 extTypes.Register(xt)
63 if val == nil {
64 return
65 }
66 pval := xt.ValueOf(val)
67 knownFields.Set(wire.Number(xd.Field), pval)
68}
69
Herbie Onga94f78c2019-01-03 15:39:58 -080070// dhex decodes a hex-string and returns the bytes and panics if s is invalid.
71func dhex(s string) []byte {
72 b, err := hex.DecodeString(s)
73 if err != nil {
74 panic(err)
75 }
76 return b
77}
78
Herbie Ongcddf8192018-11-28 18:25:20 -080079func TestMarshal(t *testing.T) {
80 tests := []struct {
81 desc string
Herbie Ongf42b55f2019-01-02 15:46:07 -080082 mo textpb.MarshalOptions
Herbie Ong70651952018-12-13 14:19:50 -080083 input proto.Message
Herbie Ongcddf8192018-11-28 18:25:20 -080084 want string
85 wantErr bool
86 }{{
Herbie Ongcddf8192018-11-28 18:25:20 -080087 desc: "proto2 optional scalar fields not set",
Herbie Ong800c9902018-12-06 15:28:53 -080088 input: &pb2.Scalars{},
Herbie Ongcddf8192018-11-28 18:25:20 -080089 want: "\n",
90 }, {
91 desc: "proto3 scalar fields not set",
Herbie Ong800c9902018-12-06 15:28:53 -080092 input: &pb3.Scalars{},
Herbie Ongcddf8192018-11-28 18:25:20 -080093 want: "\n",
94 }, {
95 desc: "proto2 optional scalar fields set to zero values",
Herbie Ong800c9902018-12-06 15:28:53 -080096 input: &pb2.Scalars{
Herbie Ongcddf8192018-11-28 18:25:20 -080097 OptBool: scalar.Bool(false),
98 OptInt32: scalar.Int32(0),
99 OptInt64: scalar.Int64(0),
100 OptUint32: scalar.Uint32(0),
101 OptUint64: scalar.Uint64(0),
102 OptSint32: scalar.Int32(0),
103 OptSint64: scalar.Int64(0),
104 OptFixed32: scalar.Uint32(0),
105 OptFixed64: scalar.Uint64(0),
106 OptSfixed32: scalar.Int32(0),
107 OptSfixed64: scalar.Int64(0),
108 OptFloat: scalar.Float32(0),
109 OptDouble: scalar.Float64(0),
110 OptBytes: []byte{},
111 OptString: scalar.String(""),
Herbie Ong800c9902018-12-06 15:28:53 -0800112 },
Herbie Ongcddf8192018-11-28 18:25:20 -0800113 want: `opt_bool: false
114opt_int32: 0
115opt_int64: 0
116opt_uint32: 0
117opt_uint64: 0
118opt_sint32: 0
119opt_sint64: 0
120opt_fixed32: 0
121opt_fixed64: 0
122opt_sfixed32: 0
123opt_sfixed64: 0
124opt_float: 0
125opt_double: 0
126opt_bytes: ""
127opt_string: ""
128`,
129 }, {
130 desc: "proto3 scalar fields set to zero values",
Herbie Ong800c9902018-12-06 15:28:53 -0800131 input: &pb3.Scalars{
Herbie Ongcddf8192018-11-28 18:25:20 -0800132 SBool: false,
133 SInt32: 0,
134 SInt64: 0,
135 SUint32: 0,
136 SUint64: 0,
137 SSint32: 0,
138 SSint64: 0,
139 SFixed32: 0,
140 SFixed64: 0,
141 SSfixed32: 0,
142 SSfixed64: 0,
143 SFloat: 0,
144 SDouble: 0,
145 SBytes: []byte{},
146 SString: "",
Herbie Ong800c9902018-12-06 15:28:53 -0800147 },
Herbie Ongcddf8192018-11-28 18:25:20 -0800148 want: "\n",
149 }, {
150 desc: "proto2 optional scalar fields set to some values",
Herbie Ong800c9902018-12-06 15:28:53 -0800151 input: &pb2.Scalars{
Herbie Ongcddf8192018-11-28 18:25:20 -0800152 OptBool: scalar.Bool(true),
153 OptInt32: scalar.Int32(0xff),
154 OptInt64: scalar.Int64(0xdeadbeef),
155 OptUint32: scalar.Uint32(47),
156 OptUint64: scalar.Uint64(0xdeadbeef),
157 OptSint32: scalar.Int32(-1001),
158 OptSint64: scalar.Int64(-0xffff),
159 OptFixed64: scalar.Uint64(64),
160 OptSfixed32: scalar.Int32(-32),
161 // TODO: Update encoder to output same decimals.
162 OptFloat: scalar.Float32(1.02),
163 OptDouble: scalar.Float64(1.23e100),
164 // TODO: Update encoder to not output UTF8 for bytes.
165 OptBytes: []byte("\xe8\xb0\xb7\xe6\xad\x8c"),
166 OptString: scalar.String("谷歌"),
Herbie Ong800c9902018-12-06 15:28:53 -0800167 },
Herbie Ongcddf8192018-11-28 18:25:20 -0800168 want: `opt_bool: true
169opt_int32: 255
170opt_int64: 3735928559
171opt_uint32: 47
172opt_uint64: 3735928559
173opt_sint32: -1001
174opt_sint64: -65535
175opt_fixed64: 64
176opt_sfixed32: -32
177opt_float: 1.0199999809265137
178opt_double: 1.23e+100
179opt_bytes: "谷歌"
180opt_string: "谷歌"
181`,
182 }, {
Herbie Ongcddf8192018-11-28 18:25:20 -0800183 desc: "float32 nan",
Herbie Ong800c9902018-12-06 15:28:53 -0800184 input: &pb3.Scalars{
Herbie Ongcddf8192018-11-28 18:25:20 -0800185 SFloat: float32(math.NaN()),
Herbie Ong800c9902018-12-06 15:28:53 -0800186 },
Herbie Ongcddf8192018-11-28 18:25:20 -0800187 want: "s_float: nan\n",
188 }, {
189 desc: "float32 positive infinity",
Herbie Ong800c9902018-12-06 15:28:53 -0800190 input: &pb3.Scalars{
Herbie Ongcddf8192018-11-28 18:25:20 -0800191 SFloat: float32(math.Inf(1)),
Herbie Ong800c9902018-12-06 15:28:53 -0800192 },
Herbie Ongcddf8192018-11-28 18:25:20 -0800193 want: "s_float: inf\n",
194 }, {
195 desc: "float32 negative infinity",
Herbie Ong800c9902018-12-06 15:28:53 -0800196 input: &pb3.Scalars{
Herbie Ongcddf8192018-11-28 18:25:20 -0800197 SFloat: float32(math.Inf(-1)),
Herbie Ong800c9902018-12-06 15:28:53 -0800198 },
Herbie Ongcddf8192018-11-28 18:25:20 -0800199 want: "s_float: -inf\n",
200 }, {
201 desc: "float64 nan",
Herbie Ong800c9902018-12-06 15:28:53 -0800202 input: &pb3.Scalars{
Herbie Ongcddf8192018-11-28 18:25:20 -0800203 SDouble: math.NaN(),
Herbie Ong800c9902018-12-06 15:28:53 -0800204 },
Herbie Ongcddf8192018-11-28 18:25:20 -0800205 want: "s_double: nan\n",
206 }, {
207 desc: "float64 positive infinity",
Herbie Ong800c9902018-12-06 15:28:53 -0800208 input: &pb3.Scalars{
Herbie Ongcddf8192018-11-28 18:25:20 -0800209 SDouble: math.Inf(1),
Herbie Ong800c9902018-12-06 15:28:53 -0800210 },
Herbie Ongcddf8192018-11-28 18:25:20 -0800211 want: "s_double: inf\n",
212 }, {
213 desc: "float64 negative infinity",
Herbie Ong800c9902018-12-06 15:28:53 -0800214 input: &pb3.Scalars{
Herbie Ongcddf8192018-11-28 18:25:20 -0800215 SDouble: math.Inf(-1),
Herbie Ong800c9902018-12-06 15:28:53 -0800216 },
Herbie Ongcddf8192018-11-28 18:25:20 -0800217 want: "s_double: -inf\n",
218 }, {
219 desc: "proto2 bytes set to empty string",
Herbie Ong800c9902018-12-06 15:28:53 -0800220 input: &pb2.Scalars{
Herbie Ongcddf8192018-11-28 18:25:20 -0800221 OptBytes: []byte(""),
Herbie Ong800c9902018-12-06 15:28:53 -0800222 },
Herbie Ongcddf8192018-11-28 18:25:20 -0800223 want: "opt_bytes: \"\"\n",
224 }, {
225 desc: "proto3 bytes set to empty string",
Herbie Ong800c9902018-12-06 15:28:53 -0800226 input: &pb3.Scalars{
Herbie Ongcddf8192018-11-28 18:25:20 -0800227 SBytes: []byte(""),
Herbie Ong800c9902018-12-06 15:28:53 -0800228 },
Herbie Ongcddf8192018-11-28 18:25:20 -0800229 want: "\n",
230 }, {
Herbie Ong800c9902018-12-06 15:28:53 -0800231 desc: "proto2 enum not set",
232 input: &pb2.Enums{},
Herbie Ongcddf8192018-11-28 18:25:20 -0800233 want: "\n",
234 }, {
Herbie Ong800c9902018-12-06 15:28:53 -0800235 desc: "proto2 enum set to zero value",
236 input: &pb2.Enums{
237 OptEnum: pb2.Enum_UNKNOWN.Enum(),
238 OptNestedEnum: pb2Enums_NestedEnum(0),
239 },
240 want: `opt_enum: UNKNOWN
241opt_nested_enum: 0
242`,
243 }, {
244 desc: "proto2 enum",
245 input: &pb2.Enums{
246 OptEnum: pb2.Enum_FIRST.Enum(),
247 OptNestedEnum: pb2.Enums_UNO.Enum(),
248 },
249 want: `opt_enum: FIRST
250opt_nested_enum: UNO
251`,
252 }, {
253 desc: "proto2 enum set to numeric values",
254 input: &pb2.Enums{
255 OptEnum: pb2Enum(1),
256 OptNestedEnum: pb2Enums_NestedEnum(2),
257 },
258 want: `opt_enum: FIRST
259opt_nested_enum: DOS
260`,
261 }, {
262 desc: "proto2 enum set to unnamed numeric values",
263 input: &pb2.Enums{
264 OptEnum: pb2Enum(101),
265 OptNestedEnum: pb2Enums_NestedEnum(-101),
266 },
267 want: `opt_enum: 101
268opt_nested_enum: -101
269`,
270 }, {
271 desc: "proto3 enum not set",
272 input: &pb3.Enums{},
273 want: "\n",
274 }, {
275 desc: "proto3 enum set to zero value",
276 input: &pb3.Enums{
277 SEnum: pb3.Enum_ZERO,
278 SNestedEnum: pb3.Enums_CERO,
279 },
280 want: "\n",
281 }, {
282 desc: "proto3 enum",
283 input: &pb3.Enums{
284 SEnum: pb3.Enum_ONE,
285 SNestedEnum: pb3.Enums_DIEZ,
286 },
287 want: `s_enum: ONE
288s_nested_enum: DIEZ
289`,
290 }, {
291 desc: "proto3 enum set to numeric values",
292 input: &pb3.Enums{
293 SEnum: 2,
294 SNestedEnum: 1,
295 },
296 want: `s_enum: TWO
297s_nested_enum: UNO
298`,
299 }, {
300 desc: "proto3 enum set to unnamed numeric values",
301 input: &pb3.Enums{
302 SEnum: -47,
303 SNestedEnum: 47,
304 },
305 want: `s_enum: -47
306s_nested_enum: 47
307`,
308 }, {
309 desc: "proto2 nested message not set",
310 input: &pb2.Nests{},
311 want: "\n",
312 }, {
313 desc: "proto2 nested message set to empty",
314 input: &pb2.Nests{
315 OptNested: &pb2.Nested{},
316 Optgroup: &pb2.Nests_OptGroup{},
317 },
318 want: `opt_nested: {}
Herbie Ong0dcfb9a2019-01-14 15:32:26 -0800319OptGroup: {}
Herbie Ong800c9902018-12-06 15:28:53 -0800320`,
321 }, {
322 desc: "proto2 nested messages",
323 input: &pb2.Nests{
324 OptNested: &pb2.Nested{
325 OptString: scalar.String("nested message"),
326 OptNested: &pb2.Nested{
327 OptString: scalar.String("another nested message"),
328 },
329 },
330 },
331 want: `opt_nested: {
332 opt_string: "nested message"
333 opt_nested: {
334 opt_string: "another nested message"
335 }
336}
337`,
338 }, {
339 desc: "proto2 group fields",
340 input: &pb2.Nests{
341 Optgroup: &pb2.Nests_OptGroup{
342 OptBool: scalar.Bool(true),
343 OptString: scalar.String("inside a group"),
344 OptNested: &pb2.Nested{
345 OptString: scalar.String("nested message inside a group"),
346 },
347 Optnestedgroup: &pb2.Nests_OptGroup_OptNestedGroup{
348 OptEnum: pb2.Enum_TENTH.Enum(),
349 },
350 },
351 },
Herbie Ong0dcfb9a2019-01-14 15:32:26 -0800352 want: `OptGroup: {
Herbie Ong800c9902018-12-06 15:28:53 -0800353 opt_bool: true
354 opt_string: "inside a group"
355 opt_nested: {
356 opt_string: "nested message inside a group"
357 }
Herbie Ong0dcfb9a2019-01-14 15:32:26 -0800358 OptNestedGroup: {
Herbie Ong800c9902018-12-06 15:28:53 -0800359 opt_enum: TENTH
360 }
361}
362`,
363 }, {
364 desc: "proto3 nested message not set",
365 input: &pb3.Nests{},
366 want: "\n",
367 }, {
368 desc: "proto3 nested message",
369 input: &pb3.Nests{
370 SNested: &pb3.Nested{
371 SString: "nested message",
372 SNested: &pb3.Nested{
373 SString: "another nested message",
374 },
375 },
376 },
377 want: `s_nested: {
378 s_string: "nested message"
379 s_nested: {
380 s_string: "another nested message"
381 }
382}
383`,
384 }, {
385 desc: "oneof fields",
386 input: &pb2.Oneofs{},
387 want: "\n",
388 }, {
389 desc: "oneof field set to empty string",
390 input: &pb2.Oneofs{
391 Union: &pb2.Oneofs_Str{},
392 },
393 want: "str: \"\"\n",
394 }, {
395 desc: "oneof field set to string",
396 input: &pb2.Oneofs{
397 Union: &pb2.Oneofs_Str{
398 Str: "hello",
399 },
400 },
401 want: "str: \"hello\"\n",
402 }, {
403 desc: "oneof field set to empty message",
404 input: &pb2.Oneofs{
405 Union: &pb2.Oneofs_Msg{
406 Msg: &pb2.Nested{},
407 },
408 },
409 want: "msg: {}\n",
410 }, {
411 desc: "oneof field set to message",
412 input: &pb2.Oneofs{
413 Union: &pb2.Oneofs_Msg{
414 Msg: &pb2.Nested{
415 OptString: scalar.String("nested message"),
416 },
417 },
418 },
419 want: `msg: {
420 opt_string: "nested message"
421}
422`,
423 }, {
424 desc: "repeated not set",
425 input: &pb2.Repeats{},
426 want: "\n",
427 }, {
428 desc: "repeated set to empty slices",
429 input: &pb2.Repeats{
Herbie Ongcddf8192018-11-28 18:25:20 -0800430 RptBool: []bool{},
431 RptInt32: []int32{},
432 RptInt64: []int64{},
433 RptUint32: []uint32{},
434 RptUint64: []uint64{},
435 RptFloat: []float32{},
436 RptDouble: []float64{},
437 RptBytes: [][]byte{},
Herbie Ong800c9902018-12-06 15:28:53 -0800438 },
Herbie Ongcddf8192018-11-28 18:25:20 -0800439 want: "\n",
440 }, {
Herbie Ong800c9902018-12-06 15:28:53 -0800441 desc: "repeated set to some values",
442 input: &pb2.Repeats{
Herbie Ongcddf8192018-11-28 18:25:20 -0800443 RptBool: []bool{true, false, true, true},
444 RptInt32: []int32{1, 6, 0, 0},
445 RptInt64: []int64{-64, 47},
446 RptUint32: []uint32{0xff, 0xffff},
447 RptUint64: []uint64{0xdeadbeef},
448 // TODO: add float32 examples.
449 RptDouble: []float64{math.NaN(), math.Inf(1), math.Inf(-1), 1.23e-308},
450 RptString: []string{"hello", "世界"},
451 RptBytes: [][]byte{
452 []byte("hello"),
453 []byte("\xe4\xb8\x96\xe7\x95\x8c"),
454 },
Herbie Ong800c9902018-12-06 15:28:53 -0800455 },
Herbie Ongcddf8192018-11-28 18:25:20 -0800456 want: `rpt_bool: true
457rpt_bool: false
458rpt_bool: true
459rpt_bool: true
460rpt_int32: 1
461rpt_int32: 6
462rpt_int32: 0
463rpt_int32: 0
464rpt_int64: -64
465rpt_int64: 47
466rpt_uint32: 255
467rpt_uint32: 65535
468rpt_uint64: 3735928559
469rpt_double: nan
470rpt_double: inf
471rpt_double: -inf
472rpt_double: 1.23e-308
473rpt_string: "hello"
474rpt_string: "世界"
475rpt_bytes: "hello"
476rpt_bytes: "世界"
477`,
478 }, {
Herbie Ong800c9902018-12-06 15:28:53 -0800479 desc: "repeated enum",
480 input: &pb2.Enums{
Herbie Ongcddf8192018-11-28 18:25:20 -0800481 RptEnum: []pb2.Enum{pb2.Enum_FIRST, 2, pb2.Enum_TENTH, 42},
Herbie Ongcddf8192018-11-28 18:25:20 -0800482 RptNestedEnum: []pb2.Enums_NestedEnum{2, 47, 10},
Herbie Ong800c9902018-12-06 15:28:53 -0800483 },
484 want: `rpt_enum: FIRST
Herbie Ongcddf8192018-11-28 18:25:20 -0800485rpt_enum: SECOND
486rpt_enum: TENTH
487rpt_enum: 42
Herbie Ongcddf8192018-11-28 18:25:20 -0800488rpt_nested_enum: DOS
489rpt_nested_enum: 47
490rpt_nested_enum: DIEZ
491`,
492 }, {
Herbie Ong800c9902018-12-06 15:28:53 -0800493 desc: "repeated nested message set to empty",
494 input: &pb2.Nests{
Herbie Ongcddf8192018-11-28 18:25:20 -0800495 RptNested: []*pb2.Nested{},
496 Rptgroup: []*pb2.Nests_RptGroup{},
Herbie Ong800c9902018-12-06 15:28:53 -0800497 },
498 want: "\n",
Herbie Ongcddf8192018-11-28 18:25:20 -0800499 }, {
Herbie Ong800c9902018-12-06 15:28:53 -0800500 desc: "repeated nested messages",
501 input: &pb2.Nests{
Herbie Ongcddf8192018-11-28 18:25:20 -0800502 RptNested: []*pb2.Nested{
503 {
504 OptString: scalar.String("repeat nested one"),
505 },
506 {
507 OptString: scalar.String("repeat nested two"),
508 OptNested: &pb2.Nested{
509 OptString: scalar.String("inside repeat nested two"),
510 },
511 },
512 {},
513 },
Herbie Ong800c9902018-12-06 15:28:53 -0800514 },
515 want: `rpt_nested: {
Herbie Ongcddf8192018-11-28 18:25:20 -0800516 opt_string: "repeat nested one"
517}
518rpt_nested: {
519 opt_string: "repeat nested two"
520 opt_nested: {
521 opt_string: "inside repeat nested two"
522 }
523}
524rpt_nested: {}
525`,
526 }, {
Herbie Ong800c9902018-12-06 15:28:53 -0800527 desc: "repeated group fields",
528 input: &pb2.Nests{
Herbie Ongcddf8192018-11-28 18:25:20 -0800529 Rptgroup: []*pb2.Nests_RptGroup{
530 {
531 RptBool: []bool{true, false},
532 },
533 {},
534 },
Herbie Ong800c9902018-12-06 15:28:53 -0800535 },
536 want: `rptgroup: {
Herbie Ongcddf8192018-11-28 18:25:20 -0800537 rpt_bool: true
538 rpt_bool: false
539}
540rptgroup: {}
541`,
542 }, {
Herbie Ongcddf8192018-11-28 18:25:20 -0800543 desc: "map fields empty",
Herbie Ong800c9902018-12-06 15:28:53 -0800544 input: &pb2.Maps{},
Herbie Ongcddf8192018-11-28 18:25:20 -0800545 want: "\n",
546 }, {
547 desc: "map fields set to empty maps",
Herbie Ong800c9902018-12-06 15:28:53 -0800548 input: &pb2.Maps{
Herbie Ongcddf8192018-11-28 18:25:20 -0800549 Int32ToStr: map[int32]string{},
550 Sfixed64ToBool: map[int64]bool{},
551 BoolToUint32: map[bool]uint32{},
552 Uint64ToEnum: map[uint64]pb2.Enum{},
553 StrToNested: map[string]*pb2.Nested{},
554 StrToOneofs: map[string]*pb2.Oneofs{},
Herbie Ong800c9902018-12-06 15:28:53 -0800555 },
Herbie Ongcddf8192018-11-28 18:25:20 -0800556 want: "\n",
557 }, {
558 desc: "map fields 1",
Herbie Ong800c9902018-12-06 15:28:53 -0800559 input: &pb2.Maps{
Herbie Ongcddf8192018-11-28 18:25:20 -0800560 Int32ToStr: map[int32]string{
561 -101: "-101",
562 0xff: "0xff",
563 0: "zero",
564 },
565 Sfixed64ToBool: map[int64]bool{
566 0xcafe: true,
567 0: false,
568 },
569 BoolToUint32: map[bool]uint32{
570 true: 42,
571 false: 101,
572 },
Herbie Ong800c9902018-12-06 15:28:53 -0800573 },
Herbie Ongcddf8192018-11-28 18:25:20 -0800574 want: `int32_to_str: {
575 key: -101
576 value: "-101"
577}
578int32_to_str: {
579 key: 0
580 value: "zero"
581}
582int32_to_str: {
583 key: 255
584 value: "0xff"
585}
586sfixed64_to_bool: {
587 key: 0
588 value: false
589}
590sfixed64_to_bool: {
591 key: 51966
592 value: true
593}
594bool_to_uint32: {
595 key: false
596 value: 101
597}
598bool_to_uint32: {
599 key: true
600 value: 42
601}
602`,
603 }, {
604 desc: "map fields 2",
Herbie Ong800c9902018-12-06 15:28:53 -0800605 input: &pb2.Maps{
Herbie Ongcddf8192018-11-28 18:25:20 -0800606 Uint64ToEnum: map[uint64]pb2.Enum{
607 1: pb2.Enum_FIRST,
608 2: pb2.Enum_SECOND,
609 10: pb2.Enum_TENTH,
610 },
Herbie Ong800c9902018-12-06 15:28:53 -0800611 },
Herbie Ongcddf8192018-11-28 18:25:20 -0800612 want: `uint64_to_enum: {
613 key: 1
614 value: FIRST
615}
616uint64_to_enum: {
617 key: 2
618 value: SECOND
619}
620uint64_to_enum: {
621 key: 10
622 value: TENTH
623}
624`,
625 }, {
626 desc: "map fields 3",
Herbie Ong800c9902018-12-06 15:28:53 -0800627 input: &pb2.Maps{
Herbie Ongcddf8192018-11-28 18:25:20 -0800628 StrToNested: map[string]*pb2.Nested{
629 "nested_one": &pb2.Nested{
630 OptString: scalar.String("nested in a map"),
631 },
632 },
Herbie Ong800c9902018-12-06 15:28:53 -0800633 },
Herbie Ongcddf8192018-11-28 18:25:20 -0800634 want: `str_to_nested: {
635 key: "nested_one"
636 value: {
637 opt_string: "nested in a map"
638 }
639}
640`,
641 }, {
642 desc: "map fields 4",
Herbie Ong800c9902018-12-06 15:28:53 -0800643 input: &pb2.Maps{
Herbie Ongcddf8192018-11-28 18:25:20 -0800644 StrToOneofs: map[string]*pb2.Oneofs{
645 "string": &pb2.Oneofs{
646 Union: &pb2.Oneofs_Str{
647 Str: "hello",
648 },
649 },
650 "nested": &pb2.Oneofs{
651 Union: &pb2.Oneofs_Msg{
652 Msg: &pb2.Nested{
653 OptString: scalar.String("nested oneof in map field value"),
654 },
655 },
656 },
657 },
Herbie Ong800c9902018-12-06 15:28:53 -0800658 },
Herbie Ongcddf8192018-11-28 18:25:20 -0800659 want: `str_to_oneofs: {
660 key: "nested"
661 value: {
662 msg: {
663 opt_string: "nested oneof in map field value"
664 }
665 }
666}
667str_to_oneofs: {
668 key: "string"
669 value: {
670 str: "hello"
671 }
672}
673`,
674 }, {
Herbie Ong800c9902018-12-06 15:28:53 -0800675 desc: "proto2 required fields not set",
676 input: &pb2.Requireds{},
677 want: "\n",
678 wantErr: true,
Herbie Ongcddf8192018-11-28 18:25:20 -0800679 }, {
Herbie Ong800c9902018-12-06 15:28:53 -0800680 desc: "proto2 required fields partially set",
681 input: &pb2.Requireds{
682 ReqBool: scalar.Bool(false),
683 ReqFixed32: scalar.Uint32(47),
684 ReqSfixed64: scalar.Int64(0xbeefcafe),
685 ReqDouble: scalar.Float64(math.NaN()),
686 ReqString: scalar.String("hello"),
687 ReqEnum: pb2.Enum_FIRST.Enum(),
688 },
689 want: `req_bool: false
690req_fixed32: 47
691req_sfixed64: 3203386110
692req_double: nan
693req_string: "hello"
694req_enum: FIRST
695`,
696 wantErr: true,
697 }, {
698 desc: "proto2 required fields all set",
699 input: &pb2.Requireds{
700 ReqBool: scalar.Bool(false),
701 ReqFixed32: scalar.Uint32(0),
702 ReqFixed64: scalar.Uint64(0),
703 ReqSfixed32: scalar.Int32(0),
704 ReqSfixed64: scalar.Int64(0),
705 ReqFloat: scalar.Float32(0),
706 ReqDouble: scalar.Float64(0),
707 ReqString: scalar.String(""),
708 ReqEnum: pb2.Enum_UNKNOWN.Enum(),
709 ReqBytes: []byte{},
710 ReqNested: &pb2.Nested{},
711 },
712 want: `req_bool: false
713req_fixed32: 0
714req_fixed64: 0
715req_sfixed32: 0
716req_sfixed64: 0
717req_float: 0
718req_double: 0
719req_string: ""
720req_bytes: ""
721req_enum: UNKNOWN
722req_nested: {}
Herbie Ongcddf8192018-11-28 18:25:20 -0800723`,
724 }, {
Herbie Ong800c9902018-12-06 15:28:53 -0800725 desc: "indirect required field",
726 input: &pb2.IndirectRequired{
727 OptNested: &pb2.NestedWithRequired{},
728 },
729 want: "opt_nested: {}\n",
730 wantErr: true,
Herbie Ongcddf8192018-11-28 18:25:20 -0800731 }, {
Herbie Ong800c9902018-12-06 15:28:53 -0800732 desc: "indirect required field in empty repeated",
733 input: &pb2.IndirectRequired{
734 RptNested: []*pb2.NestedWithRequired{},
735 },
736 want: "\n",
Herbie Ongcddf8192018-11-28 18:25:20 -0800737 }, {
Herbie Ong800c9902018-12-06 15:28:53 -0800738 desc: "indirect required field in repeated",
739 input: &pb2.IndirectRequired{
740 RptNested: []*pb2.NestedWithRequired{
741 &pb2.NestedWithRequired{},
Herbie Ongcddf8192018-11-28 18:25:20 -0800742 },
Herbie Ong800c9902018-12-06 15:28:53 -0800743 },
744 want: "rpt_nested: {}\n",
745 wantErr: true,
746 }, {
747 desc: "indirect required field in empty map",
748 input: &pb2.IndirectRequired{
749 StrToNested: map[string]*pb2.NestedWithRequired{},
750 },
751 want: "\n",
752 }, {
753 desc: "indirect required field in map",
754 input: &pb2.IndirectRequired{
755 StrToNested: map[string]*pb2.NestedWithRequired{
756 "fail": &pb2.NestedWithRequired{},
757 },
758 },
759 want: `str_to_nested: {
760 key: "fail"
761 value: {}
Herbie Ongcddf8192018-11-28 18:25:20 -0800762}
763`,
Herbie Ong800c9902018-12-06 15:28:53 -0800764 wantErr: true,
Herbie Ong20a1d312018-12-11 21:08:58 -0800765 }, {
766 desc: "unknown varint and fixed types",
767 input: &pb2.Scalars{
768 OptString: scalar.String("this message contains unknown fields"),
769 XXX_unrecognized: pack.Message{
770 pack.Tag{101, pack.VarintType}, pack.Bool(true),
771 pack.Tag{102, pack.VarintType}, pack.Varint(0xff),
772 pack.Tag{103, pack.Fixed32Type}, pack.Uint32(47),
773 pack.Tag{104, pack.Fixed64Type}, pack.Int64(0xdeadbeef),
774 }.Marshal(),
775 },
776 want: `opt_string: "this message contains unknown fields"
777101: 1
778102: 255
779103: 47
780104: 3735928559
781`,
782 }, {
783 desc: "unknown length-delimited",
784 input: &pb2.Scalars{
785 XXX_unrecognized: pack.Message{
786 pack.Tag{101, pack.BytesType}, pack.LengthPrefix{pack.Bool(true), pack.Bool(false)},
787 pack.Tag{102, pack.BytesType}, pack.String("hello world"),
788 pack.Tag{103, pack.BytesType}, pack.Bytes("\xe4\xb8\x96\xe7\x95\x8c"),
789 }.Marshal(),
790 },
791 want: `101: "\x01\x00"
792102: "hello world"
793103: "世界"
794`,
795 }, {
796 desc: "unknown group type",
797 input: &pb2.Scalars{
798 XXX_unrecognized: pack.Message{
799 pack.Tag{101, pack.StartGroupType}, pack.Tag{101, pack.EndGroupType},
800 pack.Tag{102, pack.StartGroupType},
801 pack.Tag{101, pack.VarintType}, pack.Bool(false),
802 pack.Tag{102, pack.BytesType}, pack.String("inside a group"),
803 pack.Tag{102, pack.EndGroupType},
804 }.Marshal(),
805 },
806 want: `101: {}
807102: {
808 101: 0
809 102: "inside a group"
810}
811`,
812 }, {
813 desc: "unknown unpack repeated field",
814 input: &pb2.Scalars{
815 XXX_unrecognized: pack.Message{
816 pack.Tag{101, pack.BytesType}, pack.LengthPrefix{pack.Bool(true), pack.Bool(false), pack.Bool(true)},
817 pack.Tag{102, pack.BytesType}, pack.String("hello"),
818 pack.Tag{101, pack.VarintType}, pack.Bool(true),
819 pack.Tag{102, pack.BytesType}, pack.String("世界"),
820 }.Marshal(),
821 },
822 want: `101: "\x01\x00\x01"
823101: 1
824102: "hello"
825102: "世界"
826`,
Herbie Ongcf253082018-12-17 17:13:07 -0800827 }, {
828 desc: "extensions of non-repeated fields",
829 input: func() proto.Message {
830 m := &pb2.Extensions{
831 OptString: scalar.String("non-extension field"),
832 OptBool: scalar.Bool(true),
833 OptInt32: scalar.Int32(42),
834 }
835 setExtension(m, pb2.E_OptExtBool, true)
836 setExtension(m, pb2.E_OptExtString, "extension field")
837 setExtension(m, pb2.E_OptExtEnum, pb2.Enum_TENTH)
838 setExtension(m, pb2.E_OptExtNested, &pb2.Nested{
839 OptString: scalar.String("nested in an extension"),
840 OptNested: &pb2.Nested{
841 OptString: scalar.String("another nested in an extension"),
842 },
843 })
844 return m
845 }(),
846 want: `opt_string: "non-extension field"
847opt_bool: true
848opt_int32: 42
849[pb2.opt_ext_bool]: true
850[pb2.opt_ext_enum]: TENTH
851[pb2.opt_ext_nested]: {
852 opt_string: "nested in an extension"
853 opt_nested: {
854 opt_string: "another nested in an extension"
855 }
856}
857[pb2.opt_ext_string]: "extension field"
858`,
859 }, {
860 desc: "registered extension but not set",
861 input: func() proto.Message {
862 m := &pb2.Extensions{}
863 setExtension(m, pb2.E_OptExtNested, nil)
864 return m
865 }(),
866 want: "\n",
867 }, {
868 desc: "extensions of repeated fields",
869 input: func() proto.Message {
870 m := &pb2.Extensions{}
871 setExtension(m, pb2.E_RptExtEnum, &[]pb2.Enum{pb2.Enum_TENTH, 101, pb2.Enum_FIRST})
872 setExtension(m, pb2.E_RptExtFixed32, &[]uint32{42, 47})
873 setExtension(m, pb2.E_RptExtNested, &[]*pb2.Nested{
874 &pb2.Nested{OptString: scalar.String("one")},
875 &pb2.Nested{OptString: scalar.String("two")},
876 &pb2.Nested{OptString: scalar.String("three")},
877 })
878 return m
879 }(),
880 want: `[pb2.rpt_ext_enum]: TENTH
881[pb2.rpt_ext_enum]: 101
882[pb2.rpt_ext_enum]: FIRST
883[pb2.rpt_ext_fixed32]: 42
884[pb2.rpt_ext_fixed32]: 47
885[pb2.rpt_ext_nested]: {
886 opt_string: "one"
887}
888[pb2.rpt_ext_nested]: {
889 opt_string: "two"
890}
891[pb2.rpt_ext_nested]: {
892 opt_string: "three"
893}
894`,
895 }, {
896 desc: "extensions of non-repeated fields in another message",
897 input: func() proto.Message {
898 m := &pb2.Extensions{}
899 setExtension(m, pb2.E_ExtensionsContainer_OptExtBool, true)
900 setExtension(m, pb2.E_ExtensionsContainer_OptExtString, "extension field")
901 setExtension(m, pb2.E_ExtensionsContainer_OptExtEnum, pb2.Enum_TENTH)
902 setExtension(m, pb2.E_ExtensionsContainer_OptExtNested, &pb2.Nested{
903 OptString: scalar.String("nested in an extension"),
904 OptNested: &pb2.Nested{
905 OptString: scalar.String("another nested in an extension"),
906 },
907 })
908 return m
909 }(),
910 want: `[pb2.ExtensionsContainer.opt_ext_bool]: true
911[pb2.ExtensionsContainer.opt_ext_enum]: TENTH
912[pb2.ExtensionsContainer.opt_ext_nested]: {
913 opt_string: "nested in an extension"
914 opt_nested: {
915 opt_string: "another nested in an extension"
916 }
917}
918[pb2.ExtensionsContainer.opt_ext_string]: "extension field"
919`,
920 }, {
921 desc: "extensions of repeated fields in another message",
922 input: func() proto.Message {
923 m := &pb2.Extensions{
924 OptString: scalar.String("non-extension field"),
925 OptBool: scalar.Bool(true),
926 OptInt32: scalar.Int32(42),
927 }
928 setExtension(m, pb2.E_ExtensionsContainer_RptExtEnum, &[]pb2.Enum{pb2.Enum_TENTH, 101, pb2.Enum_FIRST})
929 setExtension(m, pb2.E_ExtensionsContainer_RptExtString, &[]string{"hello", "world"})
930 setExtension(m, pb2.E_ExtensionsContainer_RptExtNested, &[]*pb2.Nested{
931 &pb2.Nested{OptString: scalar.String("one")},
932 &pb2.Nested{OptString: scalar.String("two")},
933 &pb2.Nested{OptString: scalar.String("three")},
934 })
935 return m
936 }(),
937 want: `opt_string: "non-extension field"
938opt_bool: true
939opt_int32: 42
940[pb2.ExtensionsContainer.rpt_ext_enum]: TENTH
941[pb2.ExtensionsContainer.rpt_ext_enum]: 101
942[pb2.ExtensionsContainer.rpt_ext_enum]: FIRST
943[pb2.ExtensionsContainer.rpt_ext_nested]: {
944 opt_string: "one"
945}
946[pb2.ExtensionsContainer.rpt_ext_nested]: {
947 opt_string: "two"
948}
949[pb2.ExtensionsContainer.rpt_ext_nested]: {
950 opt_string: "three"
951}
952[pb2.ExtensionsContainer.rpt_ext_string]: "hello"
953[pb2.ExtensionsContainer.rpt_ext_string]: "world"
954`,
955 /* TODO: test for MessageSet
956 }, {
957 desc: "MessageSet",
958 input: func() proto.Message {
959 m := &pb2.MessageSet{}
960 setExtension(m, pb2.E_MessageSetExtension_MessageSetExtension, &pb2.MessageSetExtension{
961 OptString: scalar.String("a messageset extension"),
962 })
963 setExtension(m, pb2.E_MessageSetExtension_NotMessageSetExtension, &pb2.MessageSetExtension{
964 OptString: scalar.String("not a messageset extension"),
965 })
966 setExtension(m, pb2.E_MessageSetExtension_ExtNested, &pb2.Nested{
967 OptString: scalar.String("just a regular extension"),
968 })
969 return m
970 }(),
971 want: `[pb2.MessageSetExtension]: {
972 opt_string: "a messageset extension"
973 }
974 [pb2.MessageSetExtension.ext_nested]: {
975 opt_string: "just a regular extension"
976 }
977 [pb2.MessageSetExtension.not_message_set_extension]: {
978 opt_string: "not a messageset extension"
979 }
980 `,
981 */
Herbie Ongf42b55f2019-01-02 15:46:07 -0800982 }, {
983 desc: "google.protobuf.Any message not expanded",
984 mo: textpb.MarshalOptions{Resolver: preg.NewTypes()},
985 input: func() proto.Message {
986 m := &pb2.Nested{
987 OptString: scalar.String("embedded inside Any"),
988 OptNested: &pb2.Nested{
989 OptString: scalar.String("inception"),
990 },
991 }
992 // TODO: Switch to V2 marshal when ready.
993 b, err := protoV1.Marshal(m)
994 if err != nil {
995 t.Fatalf("error in binary marshaling message for Any.value: %v", err)
996 }
997 return impl.Export{}.MessageOf(&anypb.Any{
998 TypeUrl: string(m.ProtoReflect().Type().FullName()),
999 Value: b,
1000 }).Interface()
1001 }(),
1002 want: `type_url: "pb2.Nested"
1003value: "\n\x13embedded inside Any\x12\x0b\n\tinception"
1004`,
1005 }, {
1006 desc: "google.protobuf.Any message expanded",
1007 mo: func() textpb.MarshalOptions {
1008 m := &pb2.Nested{}
1009 resolver := preg.NewTypes(m.ProtoReflect().Type())
1010 return textpb.MarshalOptions{Resolver: resolver}
1011 }(),
1012 input: func() proto.Message {
1013 m := &pb2.Nested{
1014 OptString: scalar.String("embedded inside Any"),
1015 OptNested: &pb2.Nested{
1016 OptString: scalar.String("inception"),
1017 },
1018 }
1019 // TODO: Switch to V2 marshal when ready.
1020 b, err := protoV1.Marshal(m)
1021 if err != nil {
1022 t.Fatalf("error in binary marshaling message for Any.value: %v", err)
1023 }
1024 return impl.Export{}.MessageOf(&anypb.Any{
1025 TypeUrl: string(m.ProtoReflect().Type().FullName()),
1026 Value: b,
1027 }).Interface()
1028 }(),
1029 want: `[pb2.Nested]: {
1030 opt_string: "embedded inside Any"
1031 opt_nested: {
1032 opt_string: "inception"
1033 }
1034}
1035`,
1036 }, {
1037 desc: "google.protobuf.Any message expanded with missing required error",
1038 mo: func() textpb.MarshalOptions {
1039 m := &pb2.PartialRequired{}
1040 resolver := preg.NewTypes(m.ProtoReflect().Type())
1041 return textpb.MarshalOptions{Resolver: resolver}
1042 }(),
1043 input: func() proto.Message {
1044 m := &pb2.PartialRequired{
1045 OptString: scalar.String("embedded inside Any"),
1046 }
1047 // TODO: Switch to V2 marshal when ready.
1048 b, err := protoV1.Marshal(m)
1049 // Ignore required not set error.
1050 if _, ok := err.(*protoV1.RequiredNotSetError); !ok {
1051 t.Fatalf("error in binary marshaling message for Any.value: %v", err)
1052 }
1053 return impl.Export{}.MessageOf(&anypb.Any{
1054 TypeUrl: string(m.ProtoReflect().Type().FullName()),
1055 Value: b,
1056 }).Interface()
1057 }(),
1058 want: `[pb2.PartialRequired]: {
1059 opt_string: "embedded inside Any"
1060}
1061`,
1062 wantErr: true,
1063 }, {
Herbie Onga94f78c2019-01-03 15:39:58 -08001064 desc: "google.protobuf.Any message with invalid value",
1065 mo: func() textpb.MarshalOptions {
1066 m := &pb2.Nested{}
1067 resolver := preg.NewTypes(m.ProtoReflect().Type())
1068 return textpb.MarshalOptions{Resolver: resolver}
1069 }(),
1070 input: func() proto.Message {
1071 m := &pb2.Nested{}
1072 return impl.Export{}.MessageOf(&anypb.Any{
1073 TypeUrl: string(m.ProtoReflect().Type().FullName()),
1074 Value: dhex("80"),
1075 }).Interface()
1076 }(),
1077 want: `type_url: "pb2.Nested"
1078value: "\x80"
1079`,
1080 }, {
Herbie Ongf42b55f2019-01-02 15:46:07 -08001081 desc: "google.protobuf.Any field",
1082 mo: textpb.MarshalOptions{Resolver: preg.NewTypes()},
1083 input: func() proto.Message {
1084 m := &pb2.Nested{
1085 OptString: scalar.String("embedded inside Any"),
1086 OptNested: &pb2.Nested{
1087 OptString: scalar.String("inception"),
1088 },
1089 }
1090 // TODO: Switch to V2 marshal when ready.
1091 b, err := protoV1.Marshal(m)
1092 if err != nil {
1093 t.Fatalf("error in binary marshaling message for Any.value: %v", err)
1094 }
1095 return &pb2.KnownTypes{
1096 OptAny: &anypb.Any{
1097 TypeUrl: string(m.ProtoReflect().Type().FullName()),
1098 Value: b,
1099 },
1100 }
1101 }(),
1102 want: `opt_any: {
1103 type_url: "pb2.Nested"
1104 value: "\n\x13embedded inside Any\x12\x0b\n\tinception"
1105}
1106`,
1107 }, {
1108 desc: "google.protobuf.Any field expanded using given types registry",
1109 mo: func() textpb.MarshalOptions {
1110 m := &pb2.Nested{}
1111 resolver := preg.NewTypes(m.ProtoReflect().Type())
1112 return textpb.MarshalOptions{Resolver: resolver}
1113 }(),
1114 input: func() proto.Message {
1115 m := &pb2.Nested{
1116 OptString: scalar.String("embedded inside Any"),
1117 OptNested: &pb2.Nested{
1118 OptString: scalar.String("inception"),
1119 },
1120 }
1121 // TODO: Switch to V2 marshal when ready.
1122 b, err := protoV1.Marshal(m)
1123 if err != nil {
1124 t.Fatalf("error in binary marshaling message for Any.value: %v", err)
1125 }
1126 return &pb2.KnownTypes{
1127 OptAny: &anypb.Any{
1128 TypeUrl: string(m.ProtoReflect().Type().FullName()),
1129 Value: b,
1130 },
1131 }
1132 }(),
1133 want: `opt_any: {
1134 [pb2.Nested]: {
1135 opt_string: "embedded inside Any"
1136 opt_nested: {
1137 opt_string: "inception"
1138 }
1139 }
1140}
1141`,
Herbie Ongcddf8192018-11-28 18:25:20 -08001142 }}
1143
1144 for _, tt := range tests {
1145 tt := tt
1146 t.Run(tt.desc, func(t *testing.T) {
1147 t.Parallel()
Herbie Ongf42b55f2019-01-02 15:46:07 -08001148 b, err := tt.mo.Marshal(tt.input)
Herbie Ongcddf8192018-11-28 18:25:20 -08001149 if err != nil && !tt.wantErr {
Herbie Ongf42b55f2019-01-02 15:46:07 -08001150 t.Errorf("Marshal() returned error: %v\n", err)
Herbie Ongcddf8192018-11-28 18:25:20 -08001151 }
Herbie Ong800c9902018-12-06 15:28:53 -08001152 if err == nil && tt.wantErr {
Herbie Ongf42b55f2019-01-02 15:46:07 -08001153 t.Error("Marshal() got nil error, want error\n")
Herbie Ongcddf8192018-11-28 18:25:20 -08001154 }
Herbie Ong800c9902018-12-06 15:28:53 -08001155 got := string(b)
1156 if tt.want != "" && got != tt.want {
1157 t.Errorf("Marshal()\n<got>\n%v\n<want>\n%v\n", got, tt.want)
1158 if diff := cmp.Diff(tt.want, got, splitLines); diff != "" {
Herbie Ongcddf8192018-11-28 18:25:20 -08001159 t.Errorf("Marshal() diff -want +got\n%v\n", diff)
1160 }
1161 }
1162 })
1163 }
1164}