encode_test.go 29 KB

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