encode_test.go 30 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303
  1. // 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. package textpb_test
  5. import (
  6. "bytes"
  7. "encoding/hex"
  8. "math"
  9. "strings"
  10. "testing"
  11. "github.com/golang/protobuf/v2/encoding/textpb"
  12. "github.com/golang/protobuf/v2/internal/detrand"
  13. "github.com/golang/protobuf/v2/internal/encoding/pack"
  14. "github.com/golang/protobuf/v2/internal/encoding/wire"
  15. "github.com/golang/protobuf/v2/internal/scalar"
  16. "github.com/golang/protobuf/v2/proto"
  17. preg "github.com/golang/protobuf/v2/reflect/protoregistry"
  18. "github.com/golang/protobuf/v2/runtime/protoiface"
  19. "github.com/google/go-cmp/cmp"
  20. "github.com/google/go-cmp/cmp/cmpopts"
  21. "github.com/golang/protobuf/v2/encoding/testprotos/pb2"
  22. "github.com/golang/protobuf/v2/encoding/testprotos/pb3"
  23. knownpb "github.com/golang/protobuf/v2/types/known"
  24. )
  25. func init() {
  26. // Disable detrand to enable direct comparisons on outputs.
  27. detrand.Disable()
  28. }
  29. // splitLines is a cmpopts.Option for comparing strings with line breaks.
  30. var splitLines = cmpopts.AcyclicTransformer("SplitLines", func(s string) []string {
  31. return strings.Split(s, "\n")
  32. })
  33. func pb2Enum(i int32) *pb2.Enum {
  34. p := new(pb2.Enum)
  35. *p = pb2.Enum(i)
  36. return p
  37. }
  38. func pb2Enums_NestedEnum(i int32) *pb2.Enums_NestedEnum {
  39. p := new(pb2.Enums_NestedEnum)
  40. *p = pb2.Enums_NestedEnum(i)
  41. return p
  42. }
  43. func setExtension(m proto.Message, xd *protoiface.ExtensionDescV1, val interface{}) {
  44. knownFields := m.ProtoReflect().KnownFields()
  45. extTypes := knownFields.ExtensionTypes()
  46. extTypes.Register(xd.Type)
  47. if val == nil {
  48. return
  49. }
  50. pval := xd.Type.ValueOf(val)
  51. knownFields.Set(wire.Number(xd.Field), pval)
  52. }
  53. // dhex decodes a hex-string and returns the bytes and panics if s is invalid.
  54. func dhex(s string) []byte {
  55. b, err := hex.DecodeString(s)
  56. if err != nil {
  57. panic(err)
  58. }
  59. return b
  60. }
  61. func TestMarshal(t *testing.T) {
  62. tests := []struct {
  63. desc string
  64. mo textpb.MarshalOptions
  65. input proto.Message
  66. want string
  67. wantErr bool // TODO: Verify error message content.
  68. }{{
  69. desc: "proto2 optional scalars not set",
  70. input: &pb2.Scalars{},
  71. want: "\n",
  72. }, {
  73. desc: "proto3 scalars not set",
  74. input: &pb3.Scalars{},
  75. want: "\n",
  76. }, {
  77. desc: "proto2 optional scalars set to zero values",
  78. input: &pb2.Scalars{
  79. OptBool: scalar.Bool(false),
  80. OptInt32: scalar.Int32(0),
  81. OptInt64: scalar.Int64(0),
  82. OptUint32: scalar.Uint32(0),
  83. OptUint64: scalar.Uint64(0),
  84. OptSint32: scalar.Int32(0),
  85. OptSint64: scalar.Int64(0),
  86. OptFixed32: scalar.Uint32(0),
  87. OptFixed64: scalar.Uint64(0),
  88. OptSfixed32: scalar.Int32(0),
  89. OptSfixed64: scalar.Int64(0),
  90. OptFloat: scalar.Float32(0),
  91. OptDouble: scalar.Float64(0),
  92. OptBytes: []byte{},
  93. OptString: scalar.String(""),
  94. },
  95. want: `opt_bool: false
  96. opt_int32: 0
  97. opt_int64: 0
  98. opt_uint32: 0
  99. opt_uint64: 0
  100. opt_sint32: 0
  101. opt_sint64: 0
  102. opt_fixed32: 0
  103. opt_fixed64: 0
  104. opt_sfixed32: 0
  105. opt_sfixed64: 0
  106. opt_float: 0
  107. opt_double: 0
  108. opt_bytes: ""
  109. opt_string: ""
  110. `,
  111. }, {
  112. desc: "proto3 scalars set to zero values",
  113. input: &pb3.Scalars{
  114. SBool: false,
  115. SInt32: 0,
  116. SInt64: 0,
  117. SUint32: 0,
  118. SUint64: 0,
  119. SSint32: 0,
  120. SSint64: 0,
  121. SFixed32: 0,
  122. SFixed64: 0,
  123. SSfixed32: 0,
  124. SSfixed64: 0,
  125. SFloat: 0,
  126. SDouble: 0,
  127. SBytes: []byte{},
  128. SString: "",
  129. },
  130. want: "\n",
  131. }, {
  132. desc: "proto2 optional scalars set to some values",
  133. input: &pb2.Scalars{
  134. OptBool: scalar.Bool(true),
  135. OptInt32: scalar.Int32(0xff),
  136. OptInt64: scalar.Int64(0xdeadbeef),
  137. OptUint32: scalar.Uint32(47),
  138. OptUint64: scalar.Uint64(0xdeadbeef),
  139. OptSint32: scalar.Int32(-1001),
  140. OptSint64: scalar.Int64(-0xffff),
  141. OptFixed64: scalar.Uint64(64),
  142. OptSfixed32: scalar.Int32(-32),
  143. OptFloat: scalar.Float32(1.02),
  144. OptDouble: scalar.Float64(1.0199999809265137),
  145. OptBytes: []byte("\xe8\xb0\xb7\xe6\xad\x8c"),
  146. OptString: scalar.String("谷歌"),
  147. },
  148. want: `opt_bool: true
  149. opt_int32: 255
  150. opt_int64: 3735928559
  151. opt_uint32: 47
  152. opt_uint64: 3735928559
  153. opt_sint32: -1001
  154. opt_sint64: -65535
  155. opt_fixed64: 64
  156. opt_sfixed32: -32
  157. opt_float: 1.02
  158. opt_double: 1.0199999809265137
  159. opt_bytes: "谷歌"
  160. opt_string: "谷歌"
  161. `,
  162. }, {
  163. desc: "string with invalid UTF-8",
  164. input: &pb3.Scalars{
  165. SString: "abc\xff",
  166. },
  167. want: `s_string: "abc\xff"
  168. `,
  169. wantErr: true,
  170. }, {
  171. desc: "float nan",
  172. input: &pb3.Scalars{
  173. SFloat: float32(math.NaN()),
  174. },
  175. want: "s_float: nan\n",
  176. }, {
  177. desc: "float positive infinity",
  178. input: &pb3.Scalars{
  179. SFloat: float32(math.Inf(1)),
  180. },
  181. want: "s_float: inf\n",
  182. }, {
  183. desc: "float negative infinity",
  184. input: &pb3.Scalars{
  185. SFloat: float32(math.Inf(-1)),
  186. },
  187. want: "s_float: -inf\n",
  188. }, {
  189. desc: "double nan",
  190. input: &pb3.Scalars{
  191. SDouble: math.NaN(),
  192. },
  193. want: "s_double: nan\n",
  194. }, {
  195. desc: "double positive infinity",
  196. input: &pb3.Scalars{
  197. SDouble: math.Inf(1),
  198. },
  199. want: "s_double: inf\n",
  200. }, {
  201. desc: "double negative infinity",
  202. input: &pb3.Scalars{
  203. SDouble: math.Inf(-1),
  204. },
  205. want: "s_double: -inf\n",
  206. }, {
  207. desc: "proto2 enum not set",
  208. input: &pb2.Enums{},
  209. want: "\n",
  210. }, {
  211. desc: "proto2 enum set to zero value",
  212. input: &pb2.Enums{
  213. OptEnum: pb2Enum(0),
  214. OptNestedEnum: pb2Enums_NestedEnum(0),
  215. },
  216. want: `opt_enum: 0
  217. opt_nested_enum: 0
  218. `,
  219. }, {
  220. desc: "proto2 enum",
  221. input: &pb2.Enums{
  222. OptEnum: pb2.Enum_ONE.Enum(),
  223. OptNestedEnum: pb2.Enums_UNO.Enum(),
  224. },
  225. want: `opt_enum: ONE
  226. opt_nested_enum: UNO
  227. `,
  228. }, {
  229. desc: "proto2 enum set to numeric values",
  230. input: &pb2.Enums{
  231. OptEnum: pb2Enum(2),
  232. OptNestedEnum: pb2Enums_NestedEnum(2),
  233. },
  234. want: `opt_enum: TWO
  235. opt_nested_enum: DOS
  236. `,
  237. }, {
  238. desc: "proto2 enum set to unnamed numeric values",
  239. input: &pb2.Enums{
  240. OptEnum: pb2Enum(101),
  241. OptNestedEnum: pb2Enums_NestedEnum(-101),
  242. },
  243. want: `opt_enum: 101
  244. opt_nested_enum: -101
  245. `,
  246. }, {
  247. desc: "proto3 enum not set",
  248. input: &pb3.Enums{},
  249. want: "\n",
  250. }, {
  251. desc: "proto3 enum set to zero value",
  252. input: &pb3.Enums{
  253. SEnum: pb3.Enum_ZERO,
  254. SNestedEnum: pb3.Enums_CERO,
  255. },
  256. want: "\n",
  257. }, {
  258. desc: "proto3 enum",
  259. input: &pb3.Enums{
  260. SEnum: pb3.Enum_ONE,
  261. SNestedEnum: pb3.Enums_UNO,
  262. },
  263. want: `s_enum: ONE
  264. s_nested_enum: UNO
  265. `,
  266. }, {
  267. desc: "proto3 enum set to numeric values",
  268. input: &pb3.Enums{
  269. SEnum: 2,
  270. SNestedEnum: 2,
  271. },
  272. want: `s_enum: TWO
  273. s_nested_enum: DOS
  274. `,
  275. }, {
  276. desc: "proto3 enum set to unnamed numeric values",
  277. input: &pb3.Enums{
  278. SEnum: -47,
  279. SNestedEnum: 47,
  280. },
  281. want: `s_enum: -47
  282. s_nested_enum: 47
  283. `,
  284. }, {
  285. desc: "proto2 nested message not set",
  286. input: &pb2.Nests{},
  287. want: "\n",
  288. }, {
  289. desc: "proto2 nested message set to empty",
  290. input: &pb2.Nests{
  291. OptNested: &pb2.Nested{},
  292. Optgroup: &pb2.Nests_OptGroup{},
  293. },
  294. want: `opt_nested: {}
  295. OptGroup: {}
  296. `,
  297. }, {
  298. desc: "proto2 nested messages",
  299. input: &pb2.Nests{
  300. OptNested: &pb2.Nested{
  301. OptString: scalar.String("nested message"),
  302. OptNested: &pb2.Nested{
  303. OptString: scalar.String("another nested message"),
  304. },
  305. },
  306. },
  307. want: `opt_nested: {
  308. opt_string: "nested message"
  309. opt_nested: {
  310. opt_string: "another nested message"
  311. }
  312. }
  313. `,
  314. }, {
  315. desc: "proto2 groups",
  316. input: &pb2.Nests{
  317. Optgroup: &pb2.Nests_OptGroup{
  318. OptString: scalar.String("inside a group"),
  319. OptNested: &pb2.Nested{
  320. OptString: scalar.String("nested message inside a group"),
  321. },
  322. Optnestedgroup: &pb2.Nests_OptGroup_OptNestedGroup{
  323. OptFixed32: scalar.Uint32(47),
  324. },
  325. },
  326. },
  327. want: `OptGroup: {
  328. opt_string: "inside a group"
  329. opt_nested: {
  330. opt_string: "nested message inside a group"
  331. }
  332. OptNestedGroup: {
  333. opt_fixed32: 47
  334. }
  335. }
  336. `,
  337. }, {
  338. desc: "proto3 nested message not set",
  339. input: &pb3.Nests{},
  340. want: "\n",
  341. }, {
  342. desc: "proto3 nested message set to empty",
  343. input: &pb3.Nests{
  344. SNested: &pb3.Nested{},
  345. },
  346. want: "s_nested: {}\n",
  347. }, {
  348. desc: "proto3 nested message",
  349. input: &pb3.Nests{
  350. SNested: &pb3.Nested{
  351. SString: "nested message",
  352. SNested: &pb3.Nested{
  353. SString: "another nested message",
  354. },
  355. },
  356. },
  357. want: `s_nested: {
  358. s_string: "nested message"
  359. s_nested: {
  360. s_string: "another nested message"
  361. }
  362. }
  363. `,
  364. }, {
  365. desc: "proto3 nested message contains invalid UTF-8",
  366. input: &pb3.Nests{
  367. SNested: &pb3.Nested{
  368. SString: "abc\xff",
  369. },
  370. },
  371. want: `s_nested: {
  372. s_string: "abc\xff"
  373. }
  374. `,
  375. wantErr: true,
  376. }, {
  377. desc: "oneof not set",
  378. input: &pb3.Oneofs{},
  379. want: "\n",
  380. }, {
  381. desc: "oneof set to empty string",
  382. input: &pb3.Oneofs{
  383. Union: &pb3.Oneofs_OneofString{},
  384. },
  385. want: `oneof_string: ""
  386. `,
  387. }, {
  388. desc: "oneof set to string",
  389. input: &pb3.Oneofs{
  390. Union: &pb3.Oneofs_OneofString{
  391. OneofString: "hello",
  392. },
  393. },
  394. want: `oneof_string: "hello"
  395. `,
  396. }, {
  397. desc: "oneof set to enum",
  398. input: &pb3.Oneofs{
  399. Union: &pb3.Oneofs_OneofEnum{
  400. OneofEnum: pb3.Enum_ZERO,
  401. },
  402. },
  403. want: `oneof_enum: ZERO
  404. `,
  405. }, {
  406. desc: "oneof set to empty message",
  407. input: &pb3.Oneofs{
  408. Union: &pb3.Oneofs_OneofNested{
  409. OneofNested: &pb3.Nested{},
  410. },
  411. },
  412. want: "oneof_nested: {}\n",
  413. }, {
  414. desc: "oneof set to message",
  415. input: &pb3.Oneofs{
  416. Union: &pb3.Oneofs_OneofNested{
  417. OneofNested: &pb3.Nested{
  418. SString: "nested message",
  419. },
  420. },
  421. },
  422. want: `oneof_nested: {
  423. s_string: "nested message"
  424. }
  425. `,
  426. }, {
  427. desc: "repeated fields not set",
  428. input: &pb2.Repeats{},
  429. want: "\n",
  430. }, {
  431. desc: "repeated fields set to empty slices",
  432. input: &pb2.Repeats{
  433. RptBool: []bool{},
  434. RptInt32: []int32{},
  435. RptInt64: []int64{},
  436. RptUint32: []uint32{},
  437. RptUint64: []uint64{},
  438. RptFloat: []float32{},
  439. RptDouble: []float64{},
  440. RptBytes: [][]byte{},
  441. },
  442. want: "\n",
  443. }, {
  444. desc: "repeated fields set to some values",
  445. input: &pb2.Repeats{
  446. RptBool: []bool{true, false, true, true},
  447. RptInt32: []int32{1, 6, 0, 0},
  448. RptInt64: []int64{-64, 47},
  449. RptUint32: []uint32{0xff, 0xffff},
  450. RptUint64: []uint64{0xdeadbeef},
  451. RptFloat: []float32{float32(math.NaN()), float32(math.Inf(1)), float32(math.Inf(-1)), 1.034},
  452. RptDouble: []float64{math.NaN(), math.Inf(1), math.Inf(-1), 1.23e-308},
  453. RptString: []string{"hello", "世界"},
  454. RptBytes: [][]byte{
  455. []byte("hello"),
  456. []byte("\xe4\xb8\x96\xe7\x95\x8c"),
  457. },
  458. },
  459. want: `rpt_bool: true
  460. rpt_bool: false
  461. rpt_bool: true
  462. rpt_bool: true
  463. rpt_int32: 1
  464. rpt_int32: 6
  465. rpt_int32: 0
  466. rpt_int32: 0
  467. rpt_int64: -64
  468. rpt_int64: 47
  469. rpt_uint32: 255
  470. rpt_uint32: 65535
  471. rpt_uint64: 3735928559
  472. rpt_float: nan
  473. rpt_float: inf
  474. rpt_float: -inf
  475. rpt_float: 1.034
  476. rpt_double: nan
  477. rpt_double: inf
  478. rpt_double: -inf
  479. rpt_double: 1.23e-308
  480. rpt_string: "hello"
  481. rpt_string: "世界"
  482. rpt_bytes: "hello"
  483. rpt_bytes: "世界"
  484. `,
  485. }, {
  486. desc: "repeated contains invalid UTF-8",
  487. input: &pb2.Repeats{
  488. RptString: []string{"abc\xff"},
  489. },
  490. want: `rpt_string: "abc\xff"
  491. `,
  492. wantErr: true,
  493. }, {
  494. desc: "repeated enums",
  495. input: &pb2.Enums{
  496. RptEnum: []pb2.Enum{pb2.Enum_ONE, 2, pb2.Enum_TEN, 42},
  497. RptNestedEnum: []pb2.Enums_NestedEnum{2, 47, 10},
  498. },
  499. want: `rpt_enum: ONE
  500. rpt_enum: TWO
  501. rpt_enum: TEN
  502. rpt_enum: 42
  503. rpt_nested_enum: DOS
  504. rpt_nested_enum: 47
  505. rpt_nested_enum: DIEZ
  506. `,
  507. }, {
  508. desc: "repeated messages set to empty",
  509. input: &pb2.Nests{
  510. RptNested: []*pb2.Nested{},
  511. Rptgroup: []*pb2.Nests_RptGroup{},
  512. },
  513. want: "\n",
  514. }, {
  515. desc: "repeated messages",
  516. input: &pb2.Nests{
  517. RptNested: []*pb2.Nested{
  518. {
  519. OptString: scalar.String("repeat nested one"),
  520. },
  521. {
  522. OptString: scalar.String("repeat nested two"),
  523. OptNested: &pb2.Nested{
  524. OptString: scalar.String("inside repeat nested two"),
  525. },
  526. },
  527. {},
  528. },
  529. },
  530. want: `rpt_nested: {
  531. opt_string: "repeat nested one"
  532. }
  533. rpt_nested: {
  534. opt_string: "repeat nested two"
  535. opt_nested: {
  536. opt_string: "inside repeat nested two"
  537. }
  538. }
  539. rpt_nested: {}
  540. `,
  541. }, {
  542. desc: "repeated messages contains nil value",
  543. input: &pb2.Nests{
  544. RptNested: []*pb2.Nested{nil, {}},
  545. },
  546. want: `rpt_nested: {}
  547. rpt_nested: {}
  548. `,
  549. }, {
  550. desc: "repeated groups",
  551. input: &pb2.Nests{
  552. Rptgroup: []*pb2.Nests_RptGroup{
  553. {
  554. RptString: []string{"hello", "world"},
  555. },
  556. {},
  557. nil,
  558. },
  559. },
  560. want: `RptGroup: {
  561. rpt_string: "hello"
  562. rpt_string: "world"
  563. }
  564. RptGroup: {}
  565. RptGroup: {}
  566. `,
  567. }, {
  568. desc: "map fields not set",
  569. input: &pb3.Maps{},
  570. want: "\n",
  571. }, {
  572. desc: "map fields set to empty",
  573. input: &pb3.Maps{
  574. Int32ToStr: map[int32]string{},
  575. BoolToUint32: map[bool]uint32{},
  576. Uint64ToEnum: map[uint64]pb3.Enum{},
  577. StrToNested: map[string]*pb3.Nested{},
  578. StrToOneofs: map[string]*pb3.Oneofs{},
  579. },
  580. want: "\n",
  581. }, {
  582. desc: "map fields 1",
  583. input: &pb3.Maps{
  584. Int32ToStr: map[int32]string{
  585. -101: "-101",
  586. 0xff: "0xff",
  587. 0: "zero",
  588. },
  589. BoolToUint32: map[bool]uint32{
  590. true: 42,
  591. false: 101,
  592. },
  593. },
  594. want: `int32_to_str: {
  595. key: -101
  596. value: "-101"
  597. }
  598. int32_to_str: {
  599. key: 0
  600. value: "zero"
  601. }
  602. int32_to_str: {
  603. key: 255
  604. value: "0xff"
  605. }
  606. bool_to_uint32: {
  607. key: false
  608. value: 101
  609. }
  610. bool_to_uint32: {
  611. key: true
  612. value: 42
  613. }
  614. `,
  615. }, {
  616. desc: "map fields 2",
  617. input: &pb3.Maps{
  618. Uint64ToEnum: map[uint64]pb3.Enum{
  619. 1: pb3.Enum_ONE,
  620. 2: pb3.Enum_TWO,
  621. 10: pb3.Enum_TEN,
  622. 47: 47,
  623. },
  624. },
  625. want: `uint64_to_enum: {
  626. key: 1
  627. value: ONE
  628. }
  629. uint64_to_enum: {
  630. key: 2
  631. value: TWO
  632. }
  633. uint64_to_enum: {
  634. key: 10
  635. value: TEN
  636. }
  637. uint64_to_enum: {
  638. key: 47
  639. value: 47
  640. }
  641. `,
  642. }, {
  643. desc: "map fields 3",
  644. input: &pb3.Maps{
  645. StrToNested: map[string]*pb3.Nested{
  646. "nested": &pb3.Nested{
  647. SString: "nested in a map",
  648. },
  649. },
  650. },
  651. want: `str_to_nested: {
  652. key: "nested"
  653. value: {
  654. s_string: "nested in a map"
  655. }
  656. }
  657. `,
  658. }, {
  659. desc: "map fields 4",
  660. input: &pb3.Maps{
  661. StrToOneofs: map[string]*pb3.Oneofs{
  662. "string": &pb3.Oneofs{
  663. Union: &pb3.Oneofs_OneofString{
  664. OneofString: "hello",
  665. },
  666. },
  667. "nested": &pb3.Oneofs{
  668. Union: &pb3.Oneofs_OneofNested{
  669. OneofNested: &pb3.Nested{
  670. SString: "nested oneof in map field value",
  671. },
  672. },
  673. },
  674. },
  675. },
  676. want: `str_to_oneofs: {
  677. key: "nested"
  678. value: {
  679. oneof_nested: {
  680. s_string: "nested oneof in map field value"
  681. }
  682. }
  683. }
  684. str_to_oneofs: {
  685. key: "string"
  686. value: {
  687. oneof_string: "hello"
  688. }
  689. }
  690. `,
  691. }, {
  692. desc: "map field value contains invalid UTF-8",
  693. input: &pb3.Maps{
  694. Int32ToStr: map[int32]string{
  695. 101: "abc\xff",
  696. },
  697. },
  698. want: `int32_to_str: {
  699. key: 101
  700. value: "abc\xff"
  701. }
  702. `,
  703. wantErr: true,
  704. }, {
  705. desc: "map field key contains invalid UTF-8",
  706. input: &pb3.Maps{
  707. StrToNested: map[string]*pb3.Nested{
  708. "abc\xff": {},
  709. },
  710. },
  711. want: `str_to_nested: {
  712. key: "abc\xff"
  713. value: {}
  714. }
  715. `,
  716. wantErr: true,
  717. }, {
  718. desc: "map field contains nil value",
  719. input: &pb3.Maps{
  720. StrToNested: map[string]*pb3.Nested{
  721. "nil": nil,
  722. },
  723. },
  724. want: `str_to_nested: {
  725. key: "nil"
  726. value: {}
  727. }
  728. `,
  729. }, {
  730. desc: "required fields not set",
  731. input: &pb2.Requireds{},
  732. want: "\n",
  733. wantErr: true,
  734. }, {
  735. desc: "required fields partially set",
  736. input: &pb2.Requireds{
  737. ReqBool: scalar.Bool(false),
  738. ReqSfixed64: scalar.Int64(0xbeefcafe),
  739. ReqDouble: scalar.Float64(math.NaN()),
  740. ReqString: scalar.String("hello"),
  741. ReqEnum: pb2.Enum_ONE.Enum(),
  742. },
  743. want: `req_bool: false
  744. req_sfixed64: 3203386110
  745. req_double: nan
  746. req_string: "hello"
  747. req_enum: ONE
  748. `,
  749. wantErr: true,
  750. }, {
  751. desc: "required fields not set with AllowPartial",
  752. mo: textpb.MarshalOptions{AllowPartial: true},
  753. input: &pb2.Requireds{
  754. ReqBool: scalar.Bool(false),
  755. ReqSfixed64: scalar.Int64(0xbeefcafe),
  756. ReqDouble: scalar.Float64(math.NaN()),
  757. ReqString: scalar.String("hello"),
  758. ReqEnum: pb2.Enum_ONE.Enum(),
  759. },
  760. want: `req_bool: false
  761. req_sfixed64: 3203386110
  762. req_double: nan
  763. req_string: "hello"
  764. req_enum: ONE
  765. `,
  766. }, {
  767. desc: "required fields all set",
  768. input: &pb2.Requireds{
  769. ReqBool: scalar.Bool(false),
  770. ReqSfixed64: scalar.Int64(0),
  771. ReqDouble: scalar.Float64(1.23),
  772. ReqString: scalar.String(""),
  773. ReqEnum: pb2.Enum_ONE.Enum(),
  774. ReqNested: &pb2.Nested{},
  775. },
  776. want: `req_bool: false
  777. req_sfixed64: 0
  778. req_double: 1.23
  779. req_string: ""
  780. req_enum: ONE
  781. req_nested: {}
  782. `,
  783. }, {
  784. desc: "indirect required field",
  785. input: &pb2.IndirectRequired{
  786. OptNested: &pb2.NestedWithRequired{},
  787. },
  788. want: "opt_nested: {}\n",
  789. wantErr: true,
  790. }, {
  791. desc: "indirect required field with AllowPartial",
  792. mo: textpb.MarshalOptions{AllowPartial: true},
  793. input: &pb2.IndirectRequired{
  794. OptNested: &pb2.NestedWithRequired{},
  795. },
  796. want: "opt_nested: {}\n",
  797. }, {
  798. desc: "indirect required field in empty repeated",
  799. input: &pb2.IndirectRequired{
  800. RptNested: []*pb2.NestedWithRequired{},
  801. },
  802. want: "\n",
  803. }, {
  804. desc: "indirect required field in repeated",
  805. input: &pb2.IndirectRequired{
  806. RptNested: []*pb2.NestedWithRequired{
  807. &pb2.NestedWithRequired{},
  808. },
  809. },
  810. want: "rpt_nested: {}\n",
  811. wantErr: true,
  812. }, {
  813. desc: "indirect required field in repeated with AllowPartial",
  814. mo: textpb.MarshalOptions{AllowPartial: true},
  815. input: &pb2.IndirectRequired{
  816. RptNested: []*pb2.NestedWithRequired{
  817. &pb2.NestedWithRequired{},
  818. },
  819. },
  820. want: "rpt_nested: {}\n",
  821. }, {
  822. desc: "indirect required field in empty map",
  823. input: &pb2.IndirectRequired{
  824. StrToNested: map[string]*pb2.NestedWithRequired{},
  825. },
  826. want: "\n",
  827. }, {
  828. desc: "indirect required field in map",
  829. input: &pb2.IndirectRequired{
  830. StrToNested: map[string]*pb2.NestedWithRequired{
  831. "fail": &pb2.NestedWithRequired{},
  832. },
  833. },
  834. want: `str_to_nested: {
  835. key: "fail"
  836. value: {}
  837. }
  838. `,
  839. wantErr: true,
  840. }, {
  841. desc: "indirect required field in map with AllowPartial",
  842. mo: textpb.MarshalOptions{AllowPartial: true},
  843. input: &pb2.IndirectRequired{
  844. StrToNested: map[string]*pb2.NestedWithRequired{
  845. "fail": &pb2.NestedWithRequired{},
  846. },
  847. },
  848. want: `str_to_nested: {
  849. key: "fail"
  850. value: {}
  851. }
  852. `,
  853. }, {
  854. desc: "indirect required field in oneof",
  855. input: &pb2.IndirectRequired{
  856. Union: &pb2.IndirectRequired_OneofNested{
  857. OneofNested: &pb2.NestedWithRequired{},
  858. },
  859. },
  860. want: "oneof_nested: {}\n",
  861. wantErr: true,
  862. }, {
  863. desc: "indirect required field in oneof with AllowPartial",
  864. mo: textpb.MarshalOptions{AllowPartial: true},
  865. input: &pb2.IndirectRequired{
  866. Union: &pb2.IndirectRequired_OneofNested{
  867. OneofNested: &pb2.NestedWithRequired{},
  868. },
  869. },
  870. want: "oneof_nested: {}\n",
  871. }, {
  872. desc: "unknown varint and fixed types",
  873. input: &pb2.Scalars{
  874. OptString: scalar.String("this message contains unknown fields"),
  875. XXX_unrecognized: pack.Message{
  876. pack.Tag{101, pack.VarintType}, pack.Bool(true),
  877. pack.Tag{102, pack.VarintType}, pack.Varint(0xff),
  878. pack.Tag{103, pack.Fixed32Type}, pack.Uint32(47),
  879. pack.Tag{104, pack.Fixed64Type}, pack.Int64(0xdeadbeef),
  880. }.Marshal(),
  881. },
  882. want: `opt_string: "this message contains unknown fields"
  883. 101: 1
  884. 102: 255
  885. 103: 47
  886. 104: 3735928559
  887. `,
  888. }, {
  889. desc: "unknown length-delimited",
  890. input: &pb2.Scalars{
  891. XXX_unrecognized: pack.Message{
  892. pack.Tag{101, pack.BytesType}, pack.LengthPrefix{pack.Bool(true), pack.Bool(false)},
  893. pack.Tag{102, pack.BytesType}, pack.String("hello world"),
  894. pack.Tag{103, pack.BytesType}, pack.Bytes("\xe4\xb8\x96\xe7\x95\x8c"),
  895. }.Marshal(),
  896. },
  897. want: `101: "\x01\x00"
  898. 102: "hello world"
  899. 103: "世界"
  900. `,
  901. }, {
  902. desc: "unknown group type",
  903. input: &pb2.Scalars{
  904. XXX_unrecognized: pack.Message{
  905. pack.Tag{101, pack.StartGroupType}, pack.Tag{101, pack.EndGroupType},
  906. pack.Tag{102, pack.StartGroupType},
  907. pack.Tag{101, pack.VarintType}, pack.Bool(false),
  908. pack.Tag{102, pack.BytesType}, pack.String("inside a group"),
  909. pack.Tag{102, pack.EndGroupType},
  910. }.Marshal(),
  911. },
  912. want: `101: {}
  913. 102: {
  914. 101: 0
  915. 102: "inside a group"
  916. }
  917. `,
  918. }, {
  919. desc: "unknown unpack repeated field",
  920. input: &pb2.Scalars{
  921. XXX_unrecognized: pack.Message{
  922. pack.Tag{101, pack.BytesType}, pack.LengthPrefix{pack.Bool(true), pack.Bool(false), pack.Bool(true)},
  923. pack.Tag{102, pack.BytesType}, pack.String("hello"),
  924. pack.Tag{101, pack.VarintType}, pack.Bool(true),
  925. pack.Tag{102, pack.BytesType}, pack.String("世界"),
  926. }.Marshal(),
  927. },
  928. want: `101: "\x01\x00\x01"
  929. 101: 1
  930. 102: "hello"
  931. 102: "世界"
  932. `,
  933. }, {
  934. desc: "extensions of non-repeated fields",
  935. input: func() proto.Message {
  936. m := &pb2.Extensions{
  937. OptString: scalar.String("non-extension field"),
  938. OptBool: scalar.Bool(true),
  939. OptInt32: scalar.Int32(42),
  940. }
  941. setExtension(m, pb2.E_OptExtBool, true)
  942. setExtension(m, pb2.E_OptExtString, "extension field")
  943. setExtension(m, pb2.E_OptExtEnum, pb2.Enum_TEN)
  944. setExtension(m, pb2.E_OptExtNested, &pb2.Nested{
  945. OptString: scalar.String("nested in an extension"),
  946. OptNested: &pb2.Nested{
  947. OptString: scalar.String("another nested in an extension"),
  948. },
  949. })
  950. return m
  951. }(),
  952. want: `opt_string: "non-extension field"
  953. opt_bool: true
  954. opt_int32: 42
  955. [pb2.opt_ext_bool]: true
  956. [pb2.opt_ext_enum]: TEN
  957. [pb2.opt_ext_nested]: {
  958. opt_string: "nested in an extension"
  959. opt_nested: {
  960. opt_string: "another nested in an extension"
  961. }
  962. }
  963. [pb2.opt_ext_string]: "extension field"
  964. `,
  965. }, {
  966. desc: "extension field contains invalid UTF-8",
  967. input: func() proto.Message {
  968. m := &pb2.Extensions{}
  969. setExtension(m, pb2.E_OptExtString, "abc\xff")
  970. return m
  971. }(),
  972. want: `[pb2.opt_ext_string]: "abc\xff"
  973. `,
  974. wantErr: true,
  975. }, {
  976. desc: "extension partial returns error",
  977. input: func() proto.Message {
  978. m := &pb2.Extensions{}
  979. setExtension(m, pb2.E_OptExtPartial, &pb2.PartialRequired{
  980. OptString: scalar.String("partial1"),
  981. })
  982. setExtension(m, pb2.E_ExtensionsContainer_OptExtPartial, &pb2.PartialRequired{
  983. OptString: scalar.String("partial2"),
  984. })
  985. return m
  986. }(),
  987. want: `[pb2.ExtensionsContainer.opt_ext_partial]: {
  988. opt_string: "partial2"
  989. }
  990. [pb2.opt_ext_partial]: {
  991. opt_string: "partial1"
  992. }
  993. `,
  994. wantErr: true,
  995. }, {
  996. desc: "extension partial with AllowPartial",
  997. mo: textpb.MarshalOptions{AllowPartial: true},
  998. input: func() proto.Message {
  999. m := &pb2.Extensions{}
  1000. setExtension(m, pb2.E_OptExtPartial, &pb2.PartialRequired{
  1001. OptString: scalar.String("partial1"),
  1002. })
  1003. return m
  1004. }(),
  1005. want: `[pb2.opt_ext_partial]: {
  1006. opt_string: "partial1"
  1007. }
  1008. `,
  1009. }, {
  1010. desc: "extension message field set to nil",
  1011. input: func() proto.Message {
  1012. m := &pb2.Extensions{}
  1013. setExtension(m, pb2.E_OptExtNested, nil)
  1014. return m
  1015. }(),
  1016. want: "\n",
  1017. }, {
  1018. desc: "extensions of repeated fields",
  1019. input: func() proto.Message {
  1020. m := &pb2.Extensions{}
  1021. setExtension(m, pb2.E_RptExtEnum, &[]pb2.Enum{pb2.Enum_TEN, 101, pb2.Enum_ONE})
  1022. setExtension(m, pb2.E_RptExtFixed32, &[]uint32{42, 47})
  1023. setExtension(m, pb2.E_RptExtNested, &[]*pb2.Nested{
  1024. &pb2.Nested{OptString: scalar.String("one")},
  1025. &pb2.Nested{OptString: scalar.String("two")},
  1026. &pb2.Nested{OptString: scalar.String("three")},
  1027. })
  1028. return m
  1029. }(),
  1030. want: `[pb2.rpt_ext_enum]: TEN
  1031. [pb2.rpt_ext_enum]: 101
  1032. [pb2.rpt_ext_enum]: ONE
  1033. [pb2.rpt_ext_fixed32]: 42
  1034. [pb2.rpt_ext_fixed32]: 47
  1035. [pb2.rpt_ext_nested]: {
  1036. opt_string: "one"
  1037. }
  1038. [pb2.rpt_ext_nested]: {
  1039. opt_string: "two"
  1040. }
  1041. [pb2.rpt_ext_nested]: {
  1042. opt_string: "three"
  1043. }
  1044. `,
  1045. }, {
  1046. desc: "extensions of non-repeated fields in another message",
  1047. input: func() proto.Message {
  1048. m := &pb2.Extensions{}
  1049. setExtension(m, pb2.E_ExtensionsContainer_OptExtBool, true)
  1050. setExtension(m, pb2.E_ExtensionsContainer_OptExtString, "extension field")
  1051. setExtension(m, pb2.E_ExtensionsContainer_OptExtEnum, pb2.Enum_TEN)
  1052. setExtension(m, pb2.E_ExtensionsContainer_OptExtNested, &pb2.Nested{
  1053. OptString: scalar.String("nested in an extension"),
  1054. OptNested: &pb2.Nested{
  1055. OptString: scalar.String("another nested in an extension"),
  1056. },
  1057. })
  1058. return m
  1059. }(),
  1060. want: `[pb2.ExtensionsContainer.opt_ext_bool]: true
  1061. [pb2.ExtensionsContainer.opt_ext_enum]: TEN
  1062. [pb2.ExtensionsContainer.opt_ext_nested]: {
  1063. opt_string: "nested in an extension"
  1064. opt_nested: {
  1065. opt_string: "another nested in an extension"
  1066. }
  1067. }
  1068. [pb2.ExtensionsContainer.opt_ext_string]: "extension field"
  1069. `,
  1070. }, {
  1071. desc: "extensions of repeated fields in another message",
  1072. input: func() proto.Message {
  1073. m := &pb2.Extensions{
  1074. OptString: scalar.String("non-extension field"),
  1075. OptBool: scalar.Bool(true),
  1076. OptInt32: scalar.Int32(42),
  1077. }
  1078. setExtension(m, pb2.E_ExtensionsContainer_RptExtEnum, &[]pb2.Enum{pb2.Enum_TEN, 101, pb2.Enum_ONE})
  1079. setExtension(m, pb2.E_ExtensionsContainer_RptExtString, &[]string{"hello", "world"})
  1080. setExtension(m, pb2.E_ExtensionsContainer_RptExtNested, &[]*pb2.Nested{
  1081. &pb2.Nested{OptString: scalar.String("one")},
  1082. &pb2.Nested{OptString: scalar.String("two")},
  1083. &pb2.Nested{OptString: scalar.String("three")},
  1084. })
  1085. return m
  1086. }(),
  1087. want: `opt_string: "non-extension field"
  1088. opt_bool: true
  1089. opt_int32: 42
  1090. [pb2.ExtensionsContainer.rpt_ext_enum]: TEN
  1091. [pb2.ExtensionsContainer.rpt_ext_enum]: 101
  1092. [pb2.ExtensionsContainer.rpt_ext_enum]: ONE
  1093. [pb2.ExtensionsContainer.rpt_ext_nested]: {
  1094. opt_string: "one"
  1095. }
  1096. [pb2.ExtensionsContainer.rpt_ext_nested]: {
  1097. opt_string: "two"
  1098. }
  1099. [pb2.ExtensionsContainer.rpt_ext_nested]: {
  1100. opt_string: "three"
  1101. }
  1102. [pb2.ExtensionsContainer.rpt_ext_string]: "hello"
  1103. [pb2.ExtensionsContainer.rpt_ext_string]: "world"
  1104. `,
  1105. }, {
  1106. desc: "MessageSet",
  1107. input: func() proto.Message {
  1108. m := &pb2.MessageSet{}
  1109. setExtension(m, pb2.E_MessageSetExtension_MessageSetExtension, &pb2.MessageSetExtension{
  1110. OptString: scalar.String("a messageset extension"),
  1111. })
  1112. setExtension(m, pb2.E_MessageSetExtension_NotMessageSetExtension, &pb2.MessageSetExtension{
  1113. OptString: scalar.String("not a messageset extension"),
  1114. })
  1115. setExtension(m, pb2.E_MessageSetExtension_ExtNested, &pb2.Nested{
  1116. OptString: scalar.String("just a regular extension"),
  1117. })
  1118. return m
  1119. }(),
  1120. want: `[pb2.MessageSetExtension]: {
  1121. opt_string: "a messageset extension"
  1122. }
  1123. [pb2.MessageSetExtension.ext_nested]: {
  1124. opt_string: "just a regular extension"
  1125. }
  1126. [pb2.MessageSetExtension.not_message_set_extension]: {
  1127. opt_string: "not a messageset extension"
  1128. }
  1129. `,
  1130. }, {
  1131. desc: "not real MessageSet 1",
  1132. input: func() proto.Message {
  1133. m := &pb2.FakeMessageSet{}
  1134. setExtension(m, pb2.E_FakeMessageSetExtension_MessageSetExtension, &pb2.FakeMessageSetExtension{
  1135. OptString: scalar.String("not a messageset extension"),
  1136. })
  1137. return m
  1138. }(),
  1139. want: `[pb2.FakeMessageSetExtension.message_set_extension]: {
  1140. opt_string: "not a messageset extension"
  1141. }
  1142. `,
  1143. }, {
  1144. desc: "not real MessageSet 2",
  1145. input: func() proto.Message {
  1146. m := &pb2.MessageSet{}
  1147. setExtension(m, pb2.E_MessageSetExtension, &pb2.FakeMessageSetExtension{
  1148. OptString: scalar.String("another not a messageset extension"),
  1149. })
  1150. return m
  1151. }(),
  1152. want: `[pb2.message_set_extension]: {
  1153. opt_string: "another not a messageset extension"
  1154. }
  1155. `,
  1156. }, {
  1157. desc: "Any not expanded",
  1158. mo: textpb.MarshalOptions{
  1159. Resolver: preg.NewTypes(),
  1160. },
  1161. input: func() proto.Message {
  1162. m := &pb2.Nested{
  1163. OptString: scalar.String("embedded inside Any"),
  1164. OptNested: &pb2.Nested{
  1165. OptString: scalar.String("inception"),
  1166. },
  1167. }
  1168. b, err := proto.MarshalOptions{Deterministic: true}.Marshal(m)
  1169. if err != nil {
  1170. t.Fatalf("error in binary marshaling message for Any.value: %v", err)
  1171. }
  1172. return &knownpb.Any{
  1173. TypeUrl: "pb2.Nested",
  1174. Value: b,
  1175. }
  1176. }(),
  1177. want: `type_url: "pb2.Nested"
  1178. value: "\n\x13embedded inside Any\x12\x0b\n\tinception"
  1179. `,
  1180. }, {
  1181. desc: "Any expanded",
  1182. mo: textpb.MarshalOptions{
  1183. Resolver: preg.NewTypes((&pb2.Nested{}).ProtoReflect().Type()),
  1184. },
  1185. input: func() proto.Message {
  1186. m := &pb2.Nested{
  1187. OptString: scalar.String("embedded inside Any"),
  1188. OptNested: &pb2.Nested{
  1189. OptString: scalar.String("inception"),
  1190. },
  1191. }
  1192. b, err := proto.MarshalOptions{Deterministic: true}.Marshal(m)
  1193. if err != nil {
  1194. t.Fatalf("error in binary marshaling message for Any.value: %v", err)
  1195. }
  1196. return &knownpb.Any{
  1197. TypeUrl: "foo/pb2.Nested",
  1198. Value: b,
  1199. }
  1200. }(),
  1201. want: `[foo/pb2.Nested]: {
  1202. opt_string: "embedded inside Any"
  1203. opt_nested: {
  1204. opt_string: "inception"
  1205. }
  1206. }
  1207. `,
  1208. }, {
  1209. desc: "Any expanded with missing required error",
  1210. mo: textpb.MarshalOptions{
  1211. Resolver: preg.NewTypes((&pb2.PartialRequired{}).ProtoReflect().Type()),
  1212. },
  1213. input: func() proto.Message {
  1214. m := &pb2.PartialRequired{
  1215. OptString: scalar.String("embedded inside Any"),
  1216. }
  1217. b, err := proto.MarshalOptions{
  1218. AllowPartial: true,
  1219. Deterministic: true,
  1220. }.Marshal(m)
  1221. if err != nil {
  1222. t.Fatalf("error in binary marshaling message for Any.value: %v", err)
  1223. }
  1224. return &knownpb.Any{
  1225. TypeUrl: string(m.ProtoReflect().Type().FullName()),
  1226. Value: b,
  1227. }
  1228. }(),
  1229. want: `[pb2.PartialRequired]: {
  1230. opt_string: "embedded inside Any"
  1231. }
  1232. `,
  1233. wantErr: true,
  1234. }, {
  1235. desc: "Any with invalid UTF-8",
  1236. mo: textpb.MarshalOptions{
  1237. Resolver: preg.NewTypes((&pb3.Nested{}).ProtoReflect().Type()),
  1238. },
  1239. input: func() proto.Message {
  1240. m := &pb3.Nested{
  1241. SString: "abcd",
  1242. }
  1243. b, err := proto.MarshalOptions{Deterministic: true}.Marshal(m)
  1244. if err != nil {
  1245. t.Fatalf("error in binary marshaling message for Any.value: %v", err)
  1246. }
  1247. return &knownpb.Any{
  1248. TypeUrl: string(m.ProtoReflect().Type().FullName()),
  1249. Value: bytes.Replace(b, []byte("abcd"), []byte("abc\xff"), -1),
  1250. }
  1251. }(),
  1252. want: `[pb3.Nested]: {
  1253. s_string: "abc\xff"
  1254. }
  1255. `,
  1256. wantErr: true,
  1257. }, {
  1258. desc: "Any with invalid value",
  1259. mo: textpb.MarshalOptions{
  1260. Resolver: preg.NewTypes((&pb2.Nested{}).ProtoReflect().Type()),
  1261. },
  1262. input: &knownpb.Any{
  1263. TypeUrl: "foo/pb2.Nested",
  1264. Value: dhex("80"),
  1265. },
  1266. want: `type_url: "foo/pb2.Nested"
  1267. value: "\x80"
  1268. `,
  1269. }}
  1270. for _, tt := range tests {
  1271. tt := tt
  1272. t.Run(tt.desc, func(t *testing.T) {
  1273. // Use 2-space indentation on all MarshalOptions.
  1274. tt.mo.Indent = " "
  1275. b, err := tt.mo.Marshal(tt.input)
  1276. if err != nil && !tt.wantErr {
  1277. t.Errorf("Marshal() returned error: %v\n", err)
  1278. }
  1279. if err == nil && tt.wantErr {
  1280. t.Error("Marshal() got nil error, want error\n")
  1281. }
  1282. got := string(b)
  1283. if tt.want != "" && got != tt.want {
  1284. t.Errorf("Marshal()\n<got>\n%v\n<want>\n%v\n", got, tt.want)
  1285. if diff := cmp.Diff(tt.want, got, splitLines); diff != "" {
  1286. t.Errorf("Marshal() diff -want +got\n%v\n", diff)
  1287. }
  1288. }
  1289. })
  1290. }
  1291. }