encode_test.go 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819
  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 textpb_test
  5. import (
  6. "math"
  7. "strings"
  8. "testing"
  9. "github.com/golang/protobuf/v2/encoding/textpb"
  10. "github.com/golang/protobuf/v2/internal/detrand"
  11. "github.com/golang/protobuf/v2/internal/encoding/pack"
  12. "github.com/golang/protobuf/v2/internal/scalar"
  13. "github.com/golang/protobuf/v2/proto"
  14. "github.com/google/go-cmp/cmp"
  15. "github.com/google/go-cmp/cmp/cmpopts"
  16. // The legacy package must be imported prior to use of any legacy messages.
  17. // TODO: Remove this when protoV1 registers these hooks for you.
  18. _ "github.com/golang/protobuf/v2/internal/legacy"
  19. "github.com/golang/protobuf/v2/encoding/textpb/testprotos/pb2"
  20. "github.com/golang/protobuf/v2/encoding/textpb/testprotos/pb3"
  21. )
  22. func init() {
  23. // Disable detrand to enable direct comparisons on outputs.
  24. detrand.Disable()
  25. }
  26. // splitLines is a cmpopts.Option for comparing strings with line breaks.
  27. var splitLines = cmpopts.AcyclicTransformer("SplitLines", func(s string) []string {
  28. return strings.Split(s, "\n")
  29. })
  30. func pb2Enum(i int32) *pb2.Enum {
  31. p := new(pb2.Enum)
  32. *p = pb2.Enum(i)
  33. return p
  34. }
  35. func pb2Enums_NestedEnum(i int32) *pb2.Enums_NestedEnum {
  36. p := new(pb2.Enums_NestedEnum)
  37. *p = pb2.Enums_NestedEnum(i)
  38. return p
  39. }
  40. func TestMarshal(t *testing.T) {
  41. tests := []struct {
  42. desc string
  43. input proto.Message
  44. want string
  45. wantErr bool
  46. }{{
  47. desc: "proto2 optional scalar fields not set",
  48. input: &pb2.Scalars{},
  49. want: "\n",
  50. }, {
  51. desc: "proto3 scalar fields not set",
  52. input: &pb3.Scalars{},
  53. want: "\n",
  54. }, {
  55. desc: "proto2 optional scalar fields set to zero values",
  56. input: &pb2.Scalars{
  57. OptBool: scalar.Bool(false),
  58. OptInt32: scalar.Int32(0),
  59. OptInt64: scalar.Int64(0),
  60. OptUint32: scalar.Uint32(0),
  61. OptUint64: scalar.Uint64(0),
  62. OptSint32: scalar.Int32(0),
  63. OptSint64: scalar.Int64(0),
  64. OptFixed32: scalar.Uint32(0),
  65. OptFixed64: scalar.Uint64(0),
  66. OptSfixed32: scalar.Int32(0),
  67. OptSfixed64: scalar.Int64(0),
  68. OptFloat: scalar.Float32(0),
  69. OptDouble: scalar.Float64(0),
  70. OptBytes: []byte{},
  71. OptString: scalar.String(""),
  72. },
  73. want: `opt_bool: false
  74. opt_int32: 0
  75. opt_int64: 0
  76. opt_uint32: 0
  77. opt_uint64: 0
  78. opt_sint32: 0
  79. opt_sint64: 0
  80. opt_fixed32: 0
  81. opt_fixed64: 0
  82. opt_sfixed32: 0
  83. opt_sfixed64: 0
  84. opt_float: 0
  85. opt_double: 0
  86. opt_bytes: ""
  87. opt_string: ""
  88. `,
  89. }, {
  90. desc: "proto3 scalar fields set to zero values",
  91. input: &pb3.Scalars{
  92. SBool: false,
  93. SInt32: 0,
  94. SInt64: 0,
  95. SUint32: 0,
  96. SUint64: 0,
  97. SSint32: 0,
  98. SSint64: 0,
  99. SFixed32: 0,
  100. SFixed64: 0,
  101. SSfixed32: 0,
  102. SSfixed64: 0,
  103. SFloat: 0,
  104. SDouble: 0,
  105. SBytes: []byte{},
  106. SString: "",
  107. },
  108. want: "\n",
  109. }, {
  110. desc: "proto2 optional scalar fields set to some values",
  111. input: &pb2.Scalars{
  112. OptBool: scalar.Bool(true),
  113. OptInt32: scalar.Int32(0xff),
  114. OptInt64: scalar.Int64(0xdeadbeef),
  115. OptUint32: scalar.Uint32(47),
  116. OptUint64: scalar.Uint64(0xdeadbeef),
  117. OptSint32: scalar.Int32(-1001),
  118. OptSint64: scalar.Int64(-0xffff),
  119. OptFixed64: scalar.Uint64(64),
  120. OptSfixed32: scalar.Int32(-32),
  121. // TODO: Update encoder to output same decimals.
  122. OptFloat: scalar.Float32(1.02),
  123. OptDouble: scalar.Float64(1.23e100),
  124. // TODO: Update encoder to not output UTF8 for bytes.
  125. OptBytes: []byte("\xe8\xb0\xb7\xe6\xad\x8c"),
  126. OptString: scalar.String("谷歌"),
  127. },
  128. want: `opt_bool: true
  129. opt_int32: 255
  130. opt_int64: 3735928559
  131. opt_uint32: 47
  132. opt_uint64: 3735928559
  133. opt_sint32: -1001
  134. opt_sint64: -65535
  135. opt_fixed64: 64
  136. opt_sfixed32: -32
  137. opt_float: 1.0199999809265137
  138. opt_double: 1.23e+100
  139. opt_bytes: "谷歌"
  140. opt_string: "谷歌"
  141. `,
  142. }, {
  143. desc: "float32 nan",
  144. input: &pb3.Scalars{
  145. SFloat: float32(math.NaN()),
  146. },
  147. want: "s_float: nan\n",
  148. }, {
  149. desc: "float32 positive infinity",
  150. input: &pb3.Scalars{
  151. SFloat: float32(math.Inf(1)),
  152. },
  153. want: "s_float: inf\n",
  154. }, {
  155. desc: "float32 negative infinity",
  156. input: &pb3.Scalars{
  157. SFloat: float32(math.Inf(-1)),
  158. },
  159. want: "s_float: -inf\n",
  160. }, {
  161. desc: "float64 nan",
  162. input: &pb3.Scalars{
  163. SDouble: math.NaN(),
  164. },
  165. want: "s_double: nan\n",
  166. }, {
  167. desc: "float64 positive infinity",
  168. input: &pb3.Scalars{
  169. SDouble: math.Inf(1),
  170. },
  171. want: "s_double: inf\n",
  172. }, {
  173. desc: "float64 negative infinity",
  174. input: &pb3.Scalars{
  175. SDouble: math.Inf(-1),
  176. },
  177. want: "s_double: -inf\n",
  178. }, {
  179. desc: "proto2 bytes set to empty string",
  180. input: &pb2.Scalars{
  181. OptBytes: []byte(""),
  182. },
  183. want: "opt_bytes: \"\"\n",
  184. }, {
  185. desc: "proto3 bytes set to empty string",
  186. input: &pb3.Scalars{
  187. SBytes: []byte(""),
  188. },
  189. want: "\n",
  190. }, {
  191. desc: "proto2 enum not set",
  192. input: &pb2.Enums{},
  193. want: "\n",
  194. }, {
  195. desc: "proto2 enum set to zero value",
  196. input: &pb2.Enums{
  197. OptEnum: pb2.Enum_UNKNOWN.Enum(),
  198. OptNestedEnum: pb2Enums_NestedEnum(0),
  199. },
  200. want: `opt_enum: UNKNOWN
  201. opt_nested_enum: 0
  202. `,
  203. }, {
  204. desc: "proto2 enum",
  205. input: &pb2.Enums{
  206. OptEnum: pb2.Enum_FIRST.Enum(),
  207. OptNestedEnum: pb2.Enums_UNO.Enum(),
  208. },
  209. want: `opt_enum: FIRST
  210. opt_nested_enum: UNO
  211. `,
  212. }, {
  213. desc: "proto2 enum set to numeric values",
  214. input: &pb2.Enums{
  215. OptEnum: pb2Enum(1),
  216. OptNestedEnum: pb2Enums_NestedEnum(2),
  217. },
  218. want: `opt_enum: FIRST
  219. opt_nested_enum: DOS
  220. `,
  221. }, {
  222. desc: "proto2 enum set to unnamed numeric values",
  223. input: &pb2.Enums{
  224. OptEnum: pb2Enum(101),
  225. OptNestedEnum: pb2Enums_NestedEnum(-101),
  226. },
  227. want: `opt_enum: 101
  228. opt_nested_enum: -101
  229. `,
  230. }, {
  231. desc: "proto3 enum not set",
  232. input: &pb3.Enums{},
  233. want: "\n",
  234. }, {
  235. desc: "proto3 enum set to zero value",
  236. input: &pb3.Enums{
  237. SEnum: pb3.Enum_ZERO,
  238. SNestedEnum: pb3.Enums_CERO,
  239. },
  240. want: "\n",
  241. }, {
  242. desc: "proto3 enum",
  243. input: &pb3.Enums{
  244. SEnum: pb3.Enum_ONE,
  245. SNestedEnum: pb3.Enums_DIEZ,
  246. },
  247. want: `s_enum: ONE
  248. s_nested_enum: DIEZ
  249. `,
  250. }, {
  251. desc: "proto3 enum set to numeric values",
  252. input: &pb3.Enums{
  253. SEnum: 2,
  254. SNestedEnum: 1,
  255. },
  256. want: `s_enum: TWO
  257. s_nested_enum: UNO
  258. `,
  259. }, {
  260. desc: "proto3 enum set to unnamed numeric values",
  261. input: &pb3.Enums{
  262. SEnum: -47,
  263. SNestedEnum: 47,
  264. },
  265. want: `s_enum: -47
  266. s_nested_enum: 47
  267. `,
  268. }, {
  269. desc: "proto2 nested message not set",
  270. input: &pb2.Nests{},
  271. want: "\n",
  272. }, {
  273. desc: "proto2 nested message set to empty",
  274. input: &pb2.Nests{
  275. OptNested: &pb2.Nested{},
  276. Optgroup: &pb2.Nests_OptGroup{},
  277. },
  278. want: `opt_nested: {}
  279. optgroup: {}
  280. `,
  281. }, {
  282. desc: "proto2 nested messages",
  283. input: &pb2.Nests{
  284. OptNested: &pb2.Nested{
  285. OptString: scalar.String("nested message"),
  286. OptNested: &pb2.Nested{
  287. OptString: scalar.String("another nested message"),
  288. },
  289. },
  290. },
  291. want: `opt_nested: {
  292. opt_string: "nested message"
  293. opt_nested: {
  294. opt_string: "another nested message"
  295. }
  296. }
  297. `,
  298. }, {
  299. desc: "proto2 group fields",
  300. input: &pb2.Nests{
  301. Optgroup: &pb2.Nests_OptGroup{
  302. OptBool: scalar.Bool(true),
  303. OptString: scalar.String("inside a group"),
  304. OptNested: &pb2.Nested{
  305. OptString: scalar.String("nested message inside a group"),
  306. },
  307. Optnestedgroup: &pb2.Nests_OptGroup_OptNestedGroup{
  308. OptEnum: pb2.Enum_TENTH.Enum(),
  309. },
  310. },
  311. },
  312. want: `optgroup: {
  313. opt_bool: true
  314. opt_string: "inside a group"
  315. opt_nested: {
  316. opt_string: "nested message inside a group"
  317. }
  318. optnestedgroup: {
  319. opt_enum: TENTH
  320. }
  321. }
  322. `,
  323. }, {
  324. desc: "proto3 nested message not set",
  325. input: &pb3.Nests{},
  326. want: "\n",
  327. }, {
  328. desc: "proto3 nested message",
  329. input: &pb3.Nests{
  330. SNested: &pb3.Nested{
  331. SString: "nested message",
  332. SNested: &pb3.Nested{
  333. SString: "another nested message",
  334. },
  335. },
  336. },
  337. want: `s_nested: {
  338. s_string: "nested message"
  339. s_nested: {
  340. s_string: "another nested message"
  341. }
  342. }
  343. `,
  344. }, {
  345. desc: "oneof fields",
  346. input: &pb2.Oneofs{},
  347. want: "\n",
  348. }, {
  349. desc: "oneof field set to empty string",
  350. input: &pb2.Oneofs{
  351. Union: &pb2.Oneofs_Str{},
  352. },
  353. want: "str: \"\"\n",
  354. }, {
  355. desc: "oneof field set to string",
  356. input: &pb2.Oneofs{
  357. Union: &pb2.Oneofs_Str{
  358. Str: "hello",
  359. },
  360. },
  361. want: "str: \"hello\"\n",
  362. }, {
  363. desc: "oneof field set to empty message",
  364. input: &pb2.Oneofs{
  365. Union: &pb2.Oneofs_Msg{
  366. Msg: &pb2.Nested{},
  367. },
  368. },
  369. want: "msg: {}\n",
  370. }, {
  371. desc: "oneof field set to message",
  372. input: &pb2.Oneofs{
  373. Union: &pb2.Oneofs_Msg{
  374. Msg: &pb2.Nested{
  375. OptString: scalar.String("nested message"),
  376. },
  377. },
  378. },
  379. want: `msg: {
  380. opt_string: "nested message"
  381. }
  382. `,
  383. }, {
  384. desc: "repeated not set",
  385. input: &pb2.Repeats{},
  386. want: "\n",
  387. }, {
  388. desc: "repeated 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: "\n",
  400. }, {
  401. desc: "repeated 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. // TODO: add float32 examples.
  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_double: nan
  430. rpt_double: inf
  431. rpt_double: -inf
  432. rpt_double: 1.23e-308
  433. rpt_string: "hello"
  434. rpt_string: "世界"
  435. rpt_bytes: "hello"
  436. rpt_bytes: "世界"
  437. `,
  438. }, {
  439. desc: "repeated enum",
  440. input: &pb2.Enums{
  441. RptEnum: []pb2.Enum{pb2.Enum_FIRST, 2, pb2.Enum_TENTH, 42},
  442. RptNestedEnum: []pb2.Enums_NestedEnum{2, 47, 10},
  443. },
  444. want: `rpt_enum: FIRST
  445. rpt_enum: SECOND
  446. rpt_enum: TENTH
  447. rpt_enum: 42
  448. rpt_nested_enum: DOS
  449. rpt_nested_enum: 47
  450. rpt_nested_enum: DIEZ
  451. `,
  452. }, {
  453. desc: "repeated nested message set to empty",
  454. input: &pb2.Nests{
  455. RptNested: []*pb2.Nested{},
  456. Rptgroup: []*pb2.Nests_RptGroup{},
  457. },
  458. want: "\n",
  459. }, {
  460. desc: "repeated nested messages",
  461. input: &pb2.Nests{
  462. RptNested: []*pb2.Nested{
  463. {
  464. OptString: scalar.String("repeat nested one"),
  465. },
  466. {
  467. OptString: scalar.String("repeat nested two"),
  468. OptNested: &pb2.Nested{
  469. OptString: scalar.String("inside repeat nested two"),
  470. },
  471. },
  472. {},
  473. },
  474. },
  475. want: `rpt_nested: {
  476. opt_string: "repeat nested one"
  477. }
  478. rpt_nested: {
  479. opt_string: "repeat nested two"
  480. opt_nested: {
  481. opt_string: "inside repeat nested two"
  482. }
  483. }
  484. rpt_nested: {}
  485. `,
  486. }, {
  487. desc: "repeated group fields",
  488. input: &pb2.Nests{
  489. Rptgroup: []*pb2.Nests_RptGroup{
  490. {
  491. RptBool: []bool{true, false},
  492. },
  493. {},
  494. },
  495. },
  496. want: `rptgroup: {
  497. rpt_bool: true
  498. rpt_bool: false
  499. }
  500. rptgroup: {}
  501. `,
  502. }, {
  503. desc: "map fields empty",
  504. input: &pb2.Maps{},
  505. want: "\n",
  506. }, {
  507. desc: "map fields set to empty maps",
  508. input: &pb2.Maps{
  509. Int32ToStr: map[int32]string{},
  510. Sfixed64ToBool: map[int64]bool{},
  511. BoolToUint32: map[bool]uint32{},
  512. Uint64ToEnum: map[uint64]pb2.Enum{},
  513. StrToNested: map[string]*pb2.Nested{},
  514. StrToOneofs: map[string]*pb2.Oneofs{},
  515. },
  516. want: "\n",
  517. }, {
  518. desc: "map fields 1",
  519. input: &pb2.Maps{
  520. Int32ToStr: map[int32]string{
  521. -101: "-101",
  522. 0xff: "0xff",
  523. 0: "zero",
  524. },
  525. Sfixed64ToBool: map[int64]bool{
  526. 0xcafe: true,
  527. 0: false,
  528. },
  529. BoolToUint32: map[bool]uint32{
  530. true: 42,
  531. false: 101,
  532. },
  533. },
  534. want: `int32_to_str: {
  535. key: -101
  536. value: "-101"
  537. }
  538. int32_to_str: {
  539. key: 0
  540. value: "zero"
  541. }
  542. int32_to_str: {
  543. key: 255
  544. value: "0xff"
  545. }
  546. sfixed64_to_bool: {
  547. key: 0
  548. value: false
  549. }
  550. sfixed64_to_bool: {
  551. key: 51966
  552. value: true
  553. }
  554. bool_to_uint32: {
  555. key: false
  556. value: 101
  557. }
  558. bool_to_uint32: {
  559. key: true
  560. value: 42
  561. }
  562. `,
  563. }, {
  564. desc: "map fields 2",
  565. input: &pb2.Maps{
  566. Uint64ToEnum: map[uint64]pb2.Enum{
  567. 1: pb2.Enum_FIRST,
  568. 2: pb2.Enum_SECOND,
  569. 10: pb2.Enum_TENTH,
  570. },
  571. },
  572. want: `uint64_to_enum: {
  573. key: 1
  574. value: FIRST
  575. }
  576. uint64_to_enum: {
  577. key: 2
  578. value: SECOND
  579. }
  580. uint64_to_enum: {
  581. key: 10
  582. value: TENTH
  583. }
  584. `,
  585. }, {
  586. desc: "map fields 3",
  587. input: &pb2.Maps{
  588. StrToNested: map[string]*pb2.Nested{
  589. "nested_one": &pb2.Nested{
  590. OptString: scalar.String("nested in a map"),
  591. },
  592. },
  593. },
  594. want: `str_to_nested: {
  595. key: "nested_one"
  596. value: {
  597. opt_string: "nested in a map"
  598. }
  599. }
  600. `,
  601. }, {
  602. desc: "map fields 4",
  603. input: &pb2.Maps{
  604. StrToOneofs: map[string]*pb2.Oneofs{
  605. "string": &pb2.Oneofs{
  606. Union: &pb2.Oneofs_Str{
  607. Str: "hello",
  608. },
  609. },
  610. "nested": &pb2.Oneofs{
  611. Union: &pb2.Oneofs_Msg{
  612. Msg: &pb2.Nested{
  613. OptString: scalar.String("nested oneof in map field value"),
  614. },
  615. },
  616. },
  617. },
  618. },
  619. want: `str_to_oneofs: {
  620. key: "nested"
  621. value: {
  622. msg: {
  623. opt_string: "nested oneof in map field value"
  624. }
  625. }
  626. }
  627. str_to_oneofs: {
  628. key: "string"
  629. value: {
  630. str: "hello"
  631. }
  632. }
  633. `,
  634. }, {
  635. desc: "proto2 required fields not set",
  636. input: &pb2.Requireds{},
  637. want: "\n",
  638. wantErr: true,
  639. }, {
  640. desc: "proto2 required fields partially set",
  641. input: &pb2.Requireds{
  642. ReqBool: scalar.Bool(false),
  643. ReqFixed32: scalar.Uint32(47),
  644. ReqSfixed64: scalar.Int64(0xbeefcafe),
  645. ReqDouble: scalar.Float64(math.NaN()),
  646. ReqString: scalar.String("hello"),
  647. ReqEnum: pb2.Enum_FIRST.Enum(),
  648. },
  649. want: `req_bool: false
  650. req_fixed32: 47
  651. req_sfixed64: 3203386110
  652. req_double: nan
  653. req_string: "hello"
  654. req_enum: FIRST
  655. `,
  656. wantErr: true,
  657. }, {
  658. desc: "proto2 required fields all set",
  659. input: &pb2.Requireds{
  660. ReqBool: scalar.Bool(false),
  661. ReqFixed32: scalar.Uint32(0),
  662. ReqFixed64: scalar.Uint64(0),
  663. ReqSfixed32: scalar.Int32(0),
  664. ReqSfixed64: scalar.Int64(0),
  665. ReqFloat: scalar.Float32(0),
  666. ReqDouble: scalar.Float64(0),
  667. ReqString: scalar.String(""),
  668. ReqEnum: pb2.Enum_UNKNOWN.Enum(),
  669. ReqBytes: []byte{},
  670. ReqNested: &pb2.Nested{},
  671. },
  672. want: `req_bool: false
  673. req_fixed32: 0
  674. req_fixed64: 0
  675. req_sfixed32: 0
  676. req_sfixed64: 0
  677. req_float: 0
  678. req_double: 0
  679. req_string: ""
  680. req_bytes: ""
  681. req_enum: UNKNOWN
  682. req_nested: {}
  683. `,
  684. }, {
  685. desc: "indirect required field",
  686. input: &pb2.IndirectRequired{
  687. OptNested: &pb2.NestedWithRequired{},
  688. },
  689. want: "opt_nested: {}\n",
  690. wantErr: true,
  691. }, {
  692. desc: "indirect required field in empty repeated",
  693. input: &pb2.IndirectRequired{
  694. RptNested: []*pb2.NestedWithRequired{},
  695. },
  696. want: "\n",
  697. }, {
  698. desc: "indirect required field in repeated",
  699. input: &pb2.IndirectRequired{
  700. RptNested: []*pb2.NestedWithRequired{
  701. &pb2.NestedWithRequired{},
  702. },
  703. },
  704. want: "rpt_nested: {}\n",
  705. wantErr: true,
  706. }, {
  707. desc: "indirect required field in empty map",
  708. input: &pb2.IndirectRequired{
  709. StrToNested: map[string]*pb2.NestedWithRequired{},
  710. },
  711. want: "\n",
  712. }, {
  713. desc: "indirect required field in map",
  714. input: &pb2.IndirectRequired{
  715. StrToNested: map[string]*pb2.NestedWithRequired{
  716. "fail": &pb2.NestedWithRequired{},
  717. },
  718. },
  719. want: `str_to_nested: {
  720. key: "fail"
  721. value: {}
  722. }
  723. `,
  724. wantErr: true,
  725. }, {
  726. desc: "unknown varint and fixed types",
  727. input: &pb2.Scalars{
  728. OptString: scalar.String("this message contains unknown fields"),
  729. XXX_unrecognized: pack.Message{
  730. pack.Tag{101, pack.VarintType}, pack.Bool(true),
  731. pack.Tag{102, pack.VarintType}, pack.Varint(0xff),
  732. pack.Tag{103, pack.Fixed32Type}, pack.Uint32(47),
  733. pack.Tag{104, pack.Fixed64Type}, pack.Int64(0xdeadbeef),
  734. }.Marshal(),
  735. },
  736. want: `opt_string: "this message contains unknown fields"
  737. 101: 1
  738. 102: 255
  739. 103: 47
  740. 104: 3735928559
  741. `,
  742. }, {
  743. desc: "unknown length-delimited",
  744. input: &pb2.Scalars{
  745. XXX_unrecognized: pack.Message{
  746. pack.Tag{101, pack.BytesType}, pack.LengthPrefix{pack.Bool(true), pack.Bool(false)},
  747. pack.Tag{102, pack.BytesType}, pack.String("hello world"),
  748. pack.Tag{103, pack.BytesType}, pack.Bytes("\xe4\xb8\x96\xe7\x95\x8c"),
  749. }.Marshal(),
  750. },
  751. want: `101: "\x01\x00"
  752. 102: "hello world"
  753. 103: "世界"
  754. `,
  755. }, {
  756. desc: "unknown group type",
  757. input: &pb2.Scalars{
  758. XXX_unrecognized: pack.Message{
  759. pack.Tag{101, pack.StartGroupType}, pack.Tag{101, pack.EndGroupType},
  760. pack.Tag{102, pack.StartGroupType},
  761. pack.Tag{101, pack.VarintType}, pack.Bool(false),
  762. pack.Tag{102, pack.BytesType}, pack.String("inside a group"),
  763. pack.Tag{102, pack.EndGroupType},
  764. }.Marshal(),
  765. },
  766. want: `101: {}
  767. 102: {
  768. 101: 0
  769. 102: "inside a group"
  770. }
  771. `,
  772. }, {
  773. desc: "unknown unpack repeated field",
  774. input: &pb2.Scalars{
  775. XXX_unrecognized: pack.Message{
  776. pack.Tag{101, pack.BytesType}, pack.LengthPrefix{pack.Bool(true), pack.Bool(false), pack.Bool(true)},
  777. pack.Tag{102, pack.BytesType}, pack.String("hello"),
  778. pack.Tag{101, pack.VarintType}, pack.Bool(true),
  779. pack.Tag{102, pack.BytesType}, pack.String("世界"),
  780. }.Marshal(),
  781. },
  782. want: `101: "\x01\x00\x01"
  783. 101: 1
  784. 102: "hello"
  785. 102: "世界"
  786. `,
  787. }}
  788. for _, tt := range tests {
  789. tt := tt
  790. t.Run(tt.desc, func(t *testing.T) {
  791. t.Parallel()
  792. b, err := textpb.Marshal(tt.input)
  793. if err != nil && !tt.wantErr {
  794. t.Errorf("Marshal() returned error: %v\n\n", err)
  795. }
  796. if err == nil && tt.wantErr {
  797. t.Error("Marshal() got nil error, want error\n\n")
  798. }
  799. got := string(b)
  800. if tt.want != "" && got != tt.want {
  801. t.Errorf("Marshal()\n<got>\n%v\n<want>\n%v\n", got, tt.want)
  802. if diff := cmp.Diff(tt.want, got, splitLines); diff != "" {
  803. t.Errorf("Marshal() diff -want +got\n%v\n", diff)
  804. }
  805. }
  806. })
  807. }
  808. }