encode_test.go 29 KB

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