encode_test.go 28 KB

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