encode_test.go 28 KB

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