encode_test.go 30 KB

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