encode_test.go 27 KB

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