encode_test.go 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281
  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",
  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. }, {
  1214. desc: "Any with invalid UTF-8",
  1215. mo: prototext.MarshalOptions{
  1216. Resolver: preg.NewTypes(pimpl.Export{}.MessageTypeOf(&pb3.Nested{})),
  1217. },
  1218. input: func() proto.Message {
  1219. m := &pb3.Nested{
  1220. SString: "abcd",
  1221. }
  1222. b, err := proto.MarshalOptions{Deterministic: true}.Marshal(m)
  1223. if err != nil {
  1224. t.Fatalf("error in binary marshaling message for Any.value: %v", err)
  1225. }
  1226. return &anypb.Any{
  1227. TypeUrl: string(m.ProtoReflect().Descriptor().FullName()),
  1228. Value: bytes.Replace(b, []byte("abcd"), []byte("abc\xff"), -1),
  1229. }
  1230. }(),
  1231. want: `[pb3.Nested]: {
  1232. s_string: "abc\xff"
  1233. }
  1234. `,
  1235. wantErr: true,
  1236. }, {
  1237. desc: "Any with invalid value",
  1238. mo: prototext.MarshalOptions{
  1239. Resolver: preg.NewTypes(pimpl.Export{}.MessageTypeOf(&pb2.Nested{})),
  1240. },
  1241. input: &anypb.Any{
  1242. TypeUrl: "foo/pb2.Nested",
  1243. Value: dhex("80"),
  1244. },
  1245. want: `type_url: "foo/pb2.Nested"
  1246. value: "\x80"
  1247. `,
  1248. }}
  1249. for _, tt := range tests {
  1250. tt := tt
  1251. t.Run(tt.desc, func(t *testing.T) {
  1252. // Use 2-space indentation on all MarshalOptions.
  1253. tt.mo.Indent = " "
  1254. b, err := tt.mo.Marshal(tt.input)
  1255. if err != nil && !tt.wantErr {
  1256. t.Errorf("Marshal() returned error: %v\n", err)
  1257. }
  1258. if err == nil && tt.wantErr {
  1259. t.Error("Marshal() got nil error, want error\n")
  1260. }
  1261. got := string(b)
  1262. if tt.want != "" && got != tt.want {
  1263. t.Errorf("Marshal()\n<got>\n%v\n<want>\n%v\n", got, tt.want)
  1264. if diff := cmp.Diff(tt.want, got); diff != "" {
  1265. t.Errorf("Marshal() diff -want +got\n%v\n", diff)
  1266. }
  1267. }
  1268. })
  1269. }
  1270. }