encode_test.go 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937
  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/impl"
  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. anypb "github.com/golang/protobuf/ptypes/any"
  20. durpb "github.com/golang/protobuf/ptypes/duration"
  21. emptypb "github.com/golang/protobuf/ptypes/empty"
  22. stpb "github.com/golang/protobuf/ptypes/struct"
  23. tspb "github.com/golang/protobuf/ptypes/timestamp"
  24. wpb "github.com/golang/protobuf/ptypes/wrappers"
  25. "github.com/golang/protobuf/v2/encoding/textpb/testprotos/pb2"
  26. "github.com/golang/protobuf/v2/encoding/textpb/testprotos/pb3"
  27. )
  28. func init() {
  29. // Disable detrand to enable direct comparisons on outputs.
  30. detrand.Disable()
  31. }
  32. func M(m interface{}) proto.Message {
  33. return impl.Export{}.MessageOf(m).Interface()
  34. }
  35. // splitLines is a cmpopts.Option for comparing strings with line breaks.
  36. var splitLines = cmpopts.AcyclicTransformer("SplitLines", func(s string) []string {
  37. return strings.Split(s, "\n")
  38. })
  39. func TestMarshal(t *testing.T) {
  40. tests := []struct {
  41. desc string
  42. input proto.Message
  43. want string
  44. wantErr bool
  45. }{{
  46. desc: "nil message",
  47. want: "\n",
  48. }, {
  49. desc: "proto2 optional scalar fields not set",
  50. input: M(&pb2.Scalars{}),
  51. want: "\n",
  52. }, {
  53. desc: "proto3 scalar fields not set",
  54. input: M(&pb3.Scalars{}),
  55. want: "\n",
  56. }, {
  57. desc: "proto2 optional scalar fields set to zero values",
  58. input: M(&pb2.Scalars{
  59. OptBool: scalar.Bool(false),
  60. OptInt32: scalar.Int32(0),
  61. OptInt64: scalar.Int64(0),
  62. OptUint32: scalar.Uint32(0),
  63. OptUint64: scalar.Uint64(0),
  64. OptSint32: scalar.Int32(0),
  65. OptSint64: scalar.Int64(0),
  66. OptFixed32: scalar.Uint32(0),
  67. OptFixed64: scalar.Uint64(0),
  68. OptSfixed32: scalar.Int32(0),
  69. OptSfixed64: scalar.Int64(0),
  70. OptFloat: scalar.Float32(0),
  71. OptDouble: scalar.Float64(0),
  72. OptBytes: []byte{},
  73. OptString: scalar.String(""),
  74. }),
  75. want: `opt_bool: false
  76. opt_int32: 0
  77. opt_int64: 0
  78. opt_uint32: 0
  79. opt_uint64: 0
  80. opt_sint32: 0
  81. opt_sint64: 0
  82. opt_fixed32: 0
  83. opt_fixed64: 0
  84. opt_sfixed32: 0
  85. opt_sfixed64: 0
  86. opt_float: 0
  87. opt_double: 0
  88. opt_bytes: ""
  89. opt_string: ""
  90. `,
  91. }, {
  92. desc: "proto3 scalar fields set to zero values",
  93. input: M(&pb3.Scalars{
  94. SBool: false,
  95. SInt32: 0,
  96. SInt64: 0,
  97. SUint32: 0,
  98. SUint64: 0,
  99. SSint32: 0,
  100. SSint64: 0,
  101. SFixed32: 0,
  102. SFixed64: 0,
  103. SSfixed32: 0,
  104. SSfixed64: 0,
  105. SFloat: 0,
  106. SDouble: 0,
  107. SBytes: []byte{},
  108. SString: "",
  109. }),
  110. want: "\n",
  111. }, {
  112. desc: "proto2 optional scalar fields set to some values",
  113. input: M(&pb2.Scalars{
  114. OptBool: scalar.Bool(true),
  115. OptInt32: scalar.Int32(0xff),
  116. OptInt64: scalar.Int64(0xdeadbeef),
  117. OptUint32: scalar.Uint32(47),
  118. OptUint64: scalar.Uint64(0xdeadbeef),
  119. OptSint32: scalar.Int32(-1001),
  120. OptSint64: scalar.Int64(-0xffff),
  121. OptFixed64: scalar.Uint64(64),
  122. OptSfixed32: scalar.Int32(-32),
  123. // TODO: Update encoder to output same decimals.
  124. OptFloat: scalar.Float32(1.02),
  125. OptDouble: scalar.Float64(1.23e100),
  126. // TODO: Update encoder to not output UTF8 for bytes.
  127. OptBytes: []byte("\xe8\xb0\xb7\xe6\xad\x8c"),
  128. OptString: scalar.String("谷歌"),
  129. }),
  130. want: `opt_bool: true
  131. opt_int32: 255
  132. opt_int64: 3735928559
  133. opt_uint32: 47
  134. opt_uint64: 3735928559
  135. opt_sint32: -1001
  136. opt_sint64: -65535
  137. opt_fixed64: 64
  138. opt_sfixed32: -32
  139. opt_float: 1.0199999809265137
  140. opt_double: 1.23e+100
  141. opt_bytes: "谷歌"
  142. opt_string: "谷歌"
  143. `,
  144. }, {
  145. desc: "proto3 enum empty message",
  146. input: M(&pb3.Enums{}),
  147. want: "\n",
  148. }, {
  149. desc: "proto3 enum",
  150. input: M(&pb3.Enums{
  151. SEnum: pb3.Enum_ONE,
  152. RptEnum: []pb3.Enum{pb3.Enum_ONE, 10, 0, 21, -1},
  153. SNestedEnum: pb3.Enums_DIEZ,
  154. RptNestedEnum: []pb3.Enums_NestedEnum{21, pb3.Enums_CERO, -7, 10},
  155. }),
  156. want: `s_enum: ONE
  157. rpt_enum: ONE
  158. rpt_enum: TEN
  159. rpt_enum: ZERO
  160. rpt_enum: 21
  161. rpt_enum: -1
  162. s_nested_enum: DIEZ
  163. rpt_nested_enum: 21
  164. rpt_nested_enum: CERO
  165. rpt_nested_enum: -7
  166. rpt_nested_enum: DIEZ
  167. `,
  168. }, {
  169. desc: "float32 nan",
  170. input: M(&pb3.Scalars{
  171. SFloat: float32(math.NaN()),
  172. }),
  173. want: "s_float: nan\n",
  174. }, {
  175. desc: "float32 positive infinity",
  176. input: M(&pb3.Scalars{
  177. SFloat: float32(math.Inf(1)),
  178. }),
  179. want: "s_float: inf\n",
  180. }, {
  181. desc: "float32 negative infinity",
  182. input: M(&pb3.Scalars{
  183. SFloat: float32(math.Inf(-1)),
  184. }),
  185. want: "s_float: -inf\n",
  186. }, {
  187. desc: "float64 nan",
  188. input: M(&pb3.Scalars{
  189. SDouble: math.NaN(),
  190. }),
  191. want: "s_double: nan\n",
  192. }, {
  193. desc: "float64 positive infinity",
  194. input: M(&pb3.Scalars{
  195. SDouble: math.Inf(1),
  196. }),
  197. want: "s_double: inf\n",
  198. }, {
  199. desc: "float64 negative infinity",
  200. input: M(&pb3.Scalars{
  201. SDouble: math.Inf(-1),
  202. }),
  203. want: "s_double: -inf\n",
  204. }, {
  205. desc: "proto2 bytes set to empty string",
  206. input: M(&pb2.Scalars{
  207. OptBytes: []byte(""),
  208. }),
  209. want: "opt_bytes: \"\"\n",
  210. }, {
  211. desc: "proto3 bytes set to empty string",
  212. input: M(&pb3.Scalars{
  213. SBytes: []byte(""),
  214. }),
  215. want: "\n",
  216. }, {
  217. desc: "proto2 repeated not set",
  218. input: M(&pb2.Repeats{}),
  219. want: "\n",
  220. }, {
  221. desc: "proto2 repeated set to empty slices",
  222. input: M(&pb2.Repeats{
  223. RptBool: []bool{},
  224. RptInt32: []int32{},
  225. RptInt64: []int64{},
  226. RptUint32: []uint32{},
  227. RptUint64: []uint64{},
  228. RptFloat: []float32{},
  229. RptDouble: []float64{},
  230. RptBytes: [][]byte{},
  231. }),
  232. want: "\n",
  233. }, {
  234. desc: "proto2 repeated set to some values",
  235. input: M(&pb2.Repeats{
  236. RptBool: []bool{true, false, true, true},
  237. RptInt32: []int32{1, 6, 0, 0},
  238. RptInt64: []int64{-64, 47},
  239. RptUint32: []uint32{0xff, 0xffff},
  240. RptUint64: []uint64{0xdeadbeef},
  241. // TODO: add float32 examples.
  242. RptDouble: []float64{math.NaN(), math.Inf(1), math.Inf(-1), 1.23e-308},
  243. RptString: []string{"hello", "世界"},
  244. RptBytes: [][]byte{
  245. []byte("hello"),
  246. []byte("\xe4\xb8\x96\xe7\x95\x8c"),
  247. },
  248. }),
  249. want: `rpt_bool: true
  250. rpt_bool: false
  251. rpt_bool: true
  252. rpt_bool: true
  253. rpt_int32: 1
  254. rpt_int32: 6
  255. rpt_int32: 0
  256. rpt_int32: 0
  257. rpt_int64: -64
  258. rpt_int64: 47
  259. rpt_uint32: 255
  260. rpt_uint32: 65535
  261. rpt_uint64: 3735928559
  262. rpt_double: nan
  263. rpt_double: inf
  264. rpt_double: -inf
  265. rpt_double: 1.23e-308
  266. rpt_string: "hello"
  267. rpt_string: "世界"
  268. rpt_bytes: "hello"
  269. rpt_bytes: "世界"
  270. `,
  271. }, {
  272. desc: "proto2 enum fields not set",
  273. input: M(&pb2.Enums{}),
  274. want: "\n",
  275. }, {
  276. desc: "proto2 enum fields",
  277. input: M(&pb2.Enums{
  278. OptEnum: pb2.Enum_FIRST.Enum(),
  279. RptEnum: []pb2.Enum{pb2.Enum_FIRST, 2, pb2.Enum_TENTH, 42},
  280. OptNestedEnum: pb2.Enums_UNO.Enum(),
  281. RptNestedEnum: []pb2.Enums_NestedEnum{2, 47, 10},
  282. }),
  283. want: `opt_enum: FIRST
  284. rpt_enum: FIRST
  285. rpt_enum: SECOND
  286. rpt_enum: TENTH
  287. rpt_enum: 42
  288. opt_nested_enum: UNO
  289. rpt_nested_enum: DOS
  290. rpt_nested_enum: 47
  291. rpt_nested_enum: DIEZ
  292. `,
  293. }, {
  294. desc: "proto3 enum fields set to zero value",
  295. input: M(&pb3.Enums{
  296. SEnum: pb3.Enum_ZERO,
  297. RptEnum: []pb3.Enum{},
  298. SNestedEnum: pb3.Enums_CERO,
  299. RptNestedEnum: []pb3.Enums_NestedEnum{},
  300. }),
  301. want: "\n",
  302. }, {
  303. desc: "proto3 enum fields",
  304. input: M(&pb3.Enums{
  305. SEnum: pb3.Enum_TWO,
  306. RptEnum: []pb3.Enum{1, 0, 0},
  307. SNestedEnum: pb3.Enums_DOS,
  308. RptNestedEnum: []pb3.Enums_NestedEnum{101, pb3.Enums_DIEZ, 10},
  309. }),
  310. want: `s_enum: TWO
  311. rpt_enum: ONE
  312. rpt_enum: ZERO
  313. rpt_enum: ZERO
  314. s_nested_enum: DOS
  315. rpt_nested_enum: 101
  316. rpt_nested_enum: DIEZ
  317. rpt_nested_enum: DIEZ
  318. `,
  319. }, {
  320. desc: "proto2 nested message not set",
  321. input: M(&pb2.Nests{}),
  322. want: "\n",
  323. }, {
  324. desc: "proto2 nested message set to empty",
  325. input: M(&pb2.Nests{
  326. OptNested: &pb2.Nested{},
  327. Optgroup: &pb2.Nests_OptGroup{},
  328. RptNested: []*pb2.Nested{},
  329. Rptgroup: []*pb2.Nests_RptGroup{},
  330. }),
  331. want: `opt_nested: {}
  332. optgroup: {}
  333. `,
  334. }, {
  335. desc: "proto2 nested messages",
  336. input: M(&pb2.Nests{
  337. OptNested: &pb2.Nested{
  338. OptString: scalar.String("nested message"),
  339. OptNested: &pb2.Nested{
  340. OptString: scalar.String("another nested message"),
  341. },
  342. },
  343. RptNested: []*pb2.Nested{
  344. {
  345. OptString: scalar.String("repeat nested one"),
  346. },
  347. {
  348. OptString: scalar.String("repeat nested two"),
  349. OptNested: &pb2.Nested{
  350. OptString: scalar.String("inside repeat nested two"),
  351. },
  352. },
  353. {},
  354. },
  355. }),
  356. want: `opt_nested: {
  357. opt_string: "nested message"
  358. opt_nested: {
  359. opt_string: "another nested message"
  360. }
  361. }
  362. rpt_nested: {
  363. opt_string: "repeat nested one"
  364. }
  365. rpt_nested: {
  366. opt_string: "repeat nested two"
  367. opt_nested: {
  368. opt_string: "inside repeat nested two"
  369. }
  370. }
  371. rpt_nested: {}
  372. `,
  373. }, {
  374. desc: "proto2 group fields",
  375. input: M(&pb2.Nests{
  376. Optgroup: &pb2.Nests_OptGroup{
  377. OptBool: scalar.Bool(true),
  378. OptString: scalar.String("inside a group"),
  379. OptNested: &pb2.Nested{
  380. OptString: scalar.String("nested message inside a group"),
  381. },
  382. Optnestedgroup: &pb2.Nests_OptGroup_OptNestedGroup{
  383. OptEnum: pb2.Enum_TENTH.Enum(),
  384. },
  385. },
  386. Rptgroup: []*pb2.Nests_RptGroup{
  387. {
  388. RptBool: []bool{true, false},
  389. },
  390. {},
  391. },
  392. }),
  393. want: `optgroup: {
  394. opt_bool: true
  395. opt_string: "inside a group"
  396. opt_nested: {
  397. opt_string: "nested message inside a group"
  398. }
  399. optnestedgroup: {
  400. opt_enum: TENTH
  401. }
  402. }
  403. rptgroup: {
  404. rpt_bool: true
  405. rpt_bool: false
  406. }
  407. rptgroup: {}
  408. `,
  409. }, {
  410. desc: "proto3 nested message not set",
  411. input: M(&pb3.Nests{}),
  412. want: "\n",
  413. }, {
  414. desc: "proto3 nested message",
  415. input: M(&pb3.Nests{
  416. SNested: &pb3.Nested{
  417. SString: "nested message",
  418. SNested: &pb3.Nested{
  419. SString: "another nested message",
  420. },
  421. },
  422. RptNested: []*pb3.Nested{
  423. {
  424. SString: "repeated nested one",
  425. SNested: &pb3.Nested{
  426. SString: "inside repeated nested one",
  427. },
  428. },
  429. {
  430. SString: "repeated nested two",
  431. },
  432. {},
  433. },
  434. }),
  435. want: `s_nested: {
  436. s_string: "nested message"
  437. s_nested: {
  438. s_string: "another nested message"
  439. }
  440. }
  441. rpt_nested: {
  442. s_string: "repeated nested one"
  443. s_nested: {
  444. s_string: "inside repeated nested one"
  445. }
  446. }
  447. rpt_nested: {
  448. s_string: "repeated nested two"
  449. }
  450. rpt_nested: {}
  451. `,
  452. }, {
  453. desc: "proto2 required fields not set",
  454. input: M(&pb2.Requireds{}),
  455. want: "\n",
  456. wantErr: true,
  457. }, {
  458. desc: "proto2 required fields partially set",
  459. input: M(&pb2.Requireds{
  460. ReqBool: scalar.Bool(false),
  461. ReqFixed32: scalar.Uint32(47),
  462. ReqSfixed64: scalar.Int64(0xbeefcafe),
  463. ReqDouble: scalar.Float64(math.NaN()),
  464. ReqString: scalar.String("hello"),
  465. ReqEnum: pb2.Enum_FIRST.Enum(),
  466. }),
  467. want: `req_bool: false
  468. req_fixed32: 47
  469. req_sfixed64: 3203386110
  470. req_double: nan
  471. req_string: "hello"
  472. req_enum: FIRST
  473. `,
  474. wantErr: true,
  475. }, {
  476. desc: "proto2 required fields all set",
  477. input: M(&pb2.Requireds{
  478. ReqBool: scalar.Bool(false),
  479. ReqFixed32: scalar.Uint32(0),
  480. ReqFixed64: scalar.Uint64(0),
  481. ReqSfixed32: scalar.Int32(0),
  482. ReqSfixed64: scalar.Int64(0),
  483. ReqFloat: scalar.Float32(0),
  484. ReqDouble: scalar.Float64(0),
  485. ReqString: scalar.String(""),
  486. ReqEnum: pb2.Enum_UNKNOWN.Enum(),
  487. ReqBytes: []byte{},
  488. ReqNested: &pb2.Nested{},
  489. }),
  490. want: `req_bool: false
  491. req_fixed32: 0
  492. req_fixed64: 0
  493. req_sfixed32: 0
  494. req_sfixed64: 0
  495. req_float: 0
  496. req_double: 0
  497. req_string: ""
  498. req_bytes: ""
  499. req_enum: UNKNOWN
  500. req_nested: {}
  501. `,
  502. }, {
  503. desc: "oneof fields",
  504. input: M(&pb2.Oneofs{}),
  505. want: "\n",
  506. }, {
  507. desc: "oneof field set to empty string",
  508. input: M(&pb2.Oneofs{
  509. Union: &pb2.Oneofs_Str{},
  510. }),
  511. want: "str: \"\"\n",
  512. }, {
  513. desc: "oneof field set to string",
  514. input: M(&pb2.Oneofs{
  515. Union: &pb2.Oneofs_Str{
  516. Str: "hello",
  517. },
  518. }),
  519. want: "str: \"hello\"\n",
  520. }, {
  521. desc: "oneof field set to empty message",
  522. input: M(&pb2.Oneofs{
  523. Union: &pb2.Oneofs_Msg{
  524. Msg: &pb2.Nested{},
  525. },
  526. }),
  527. want: "msg: {}\n",
  528. }, {
  529. desc: "oneof field set to message",
  530. input: M(&pb2.Oneofs{
  531. Union: &pb2.Oneofs_Msg{
  532. Msg: &pb2.Nested{
  533. OptString: scalar.String("nested message"),
  534. },
  535. },
  536. }),
  537. want: `msg: {
  538. opt_string: "nested message"
  539. }
  540. `,
  541. }, {
  542. desc: "map fields empty",
  543. input: M(&pb2.Maps{}),
  544. want: "\n",
  545. }, {
  546. desc: "map fields set to empty maps",
  547. input: M(&pb2.Maps{
  548. Int32ToStr: map[int32]string{},
  549. Sfixed64ToBool: map[int64]bool{},
  550. BoolToUint32: map[bool]uint32{},
  551. Uint64ToEnum: map[uint64]pb2.Enum{},
  552. StrToNested: map[string]*pb2.Nested{},
  553. StrToOneofs: map[string]*pb2.Oneofs{},
  554. }),
  555. want: "\n",
  556. }, {
  557. desc: "map fields 1",
  558. input: M(&pb2.Maps{
  559. Int32ToStr: map[int32]string{
  560. -101: "-101",
  561. 0xff: "0xff",
  562. 0: "zero",
  563. },
  564. Sfixed64ToBool: map[int64]bool{
  565. 0xcafe: true,
  566. 0: false,
  567. },
  568. BoolToUint32: map[bool]uint32{
  569. true: 42,
  570. false: 101,
  571. },
  572. }),
  573. want: `int32_to_str: {
  574. key: -101
  575. value: "-101"
  576. }
  577. int32_to_str: {
  578. key: 0
  579. value: "zero"
  580. }
  581. int32_to_str: {
  582. key: 255
  583. value: "0xff"
  584. }
  585. sfixed64_to_bool: {
  586. key: 0
  587. value: false
  588. }
  589. sfixed64_to_bool: {
  590. key: 51966
  591. value: true
  592. }
  593. bool_to_uint32: {
  594. key: false
  595. value: 101
  596. }
  597. bool_to_uint32: {
  598. key: true
  599. value: 42
  600. }
  601. `,
  602. }, {
  603. desc: "map fields 2",
  604. input: M(&pb2.Maps{
  605. Uint64ToEnum: map[uint64]pb2.Enum{
  606. 1: pb2.Enum_FIRST,
  607. 2: pb2.Enum_SECOND,
  608. 10: pb2.Enum_TENTH,
  609. },
  610. }),
  611. want: `uint64_to_enum: {
  612. key: 1
  613. value: FIRST
  614. }
  615. uint64_to_enum: {
  616. key: 2
  617. value: SECOND
  618. }
  619. uint64_to_enum: {
  620. key: 10
  621. value: TENTH
  622. }
  623. `,
  624. }, {
  625. desc: "map fields 3",
  626. input: M(&pb2.Maps{
  627. StrToNested: map[string]*pb2.Nested{
  628. "nested_one": &pb2.Nested{
  629. OptString: scalar.String("nested in a map"),
  630. },
  631. },
  632. }),
  633. want: `str_to_nested: {
  634. key: "nested_one"
  635. value: {
  636. opt_string: "nested in a map"
  637. }
  638. }
  639. `,
  640. }, {
  641. desc: "map fields 4",
  642. input: M(&pb2.Maps{
  643. StrToOneofs: map[string]*pb2.Oneofs{
  644. "string": &pb2.Oneofs{
  645. Union: &pb2.Oneofs_Str{
  646. Str: "hello",
  647. },
  648. },
  649. "nested": &pb2.Oneofs{
  650. Union: &pb2.Oneofs_Msg{
  651. Msg: &pb2.Nested{
  652. OptString: scalar.String("nested oneof in map field value"),
  653. },
  654. },
  655. },
  656. },
  657. }),
  658. want: `str_to_oneofs: {
  659. key: "nested"
  660. value: {
  661. msg: {
  662. opt_string: "nested oneof in map field value"
  663. }
  664. }
  665. }
  666. str_to_oneofs: {
  667. key: "string"
  668. value: {
  669. str: "hello"
  670. }
  671. }
  672. `,
  673. }, {
  674. desc: "well-known type fields not set",
  675. input: M(&pb2.KnownTypes{}),
  676. want: "\n",
  677. }, {
  678. desc: "well-known type fields set to empty messages",
  679. input: M(&pb2.KnownTypes{
  680. OptBool: &wpb.BoolValue{},
  681. OptInt32: &wpb.Int32Value{},
  682. OptInt64: &wpb.Int64Value{},
  683. OptUint32: &wpb.UInt32Value{},
  684. OptUint64: &wpb.UInt64Value{},
  685. OptFloat: &wpb.FloatValue{},
  686. OptDouble: &wpb.DoubleValue{},
  687. OptString: &wpb.StringValue{},
  688. OptBytes: &wpb.BytesValue{},
  689. OptDuration: &durpb.Duration{},
  690. OptTimestamp: &tspb.Timestamp{},
  691. OptStruct: &stpb.Struct{},
  692. OptList: &stpb.ListValue{},
  693. OptValue: &stpb.Value{},
  694. OptEmpty: &emptypb.Empty{},
  695. OptAny: &anypb.Any{},
  696. }),
  697. want: `opt_bool: {}
  698. opt_int32: {}
  699. opt_int64: {}
  700. opt_uint32: {}
  701. opt_uint64: {}
  702. opt_float: {}
  703. opt_double: {}
  704. opt_string: {}
  705. opt_bytes: {}
  706. opt_duration: {}
  707. opt_timestamp: {}
  708. opt_struct: {}
  709. opt_list: {}
  710. opt_value: {}
  711. opt_empty: {}
  712. opt_any: {}
  713. `,
  714. }, {
  715. desc: "well-known type scalar fields",
  716. input: M(&pb2.KnownTypes{
  717. OptBool: &wpb.BoolValue{
  718. Value: true,
  719. },
  720. OptInt32: &wpb.Int32Value{
  721. Value: -42,
  722. },
  723. OptInt64: &wpb.Int64Value{
  724. Value: -42,
  725. },
  726. OptUint32: &wpb.UInt32Value{
  727. Value: 0xff,
  728. },
  729. OptUint64: &wpb.UInt64Value{
  730. Value: 0xffff,
  731. },
  732. OptFloat: &wpb.FloatValue{
  733. Value: 1.234,
  734. },
  735. OptDouble: &wpb.DoubleValue{
  736. Value: 1.23e308,
  737. },
  738. OptString: &wpb.StringValue{
  739. Value: "谷歌",
  740. },
  741. OptBytes: &wpb.BytesValue{
  742. Value: []byte("\xe8\xb0\xb7\xe6\xad\x8c"),
  743. },
  744. }),
  745. want: `opt_bool: {
  746. value: true
  747. }
  748. opt_int32: {
  749. value: -42
  750. }
  751. opt_int64: {
  752. value: -42
  753. }
  754. opt_uint32: {
  755. value: 255
  756. }
  757. opt_uint64: {
  758. value: 65535
  759. }
  760. opt_float: {
  761. value: 1.2339999675750732
  762. }
  763. opt_double: {
  764. value: 1.23e+308
  765. }
  766. opt_string: {
  767. value: "谷歌"
  768. }
  769. opt_bytes: {
  770. value: "谷歌"
  771. }
  772. `,
  773. }, {
  774. desc: "well-known type time-related fields",
  775. input: M(&pb2.KnownTypes{
  776. OptDuration: &durpb.Duration{
  777. Seconds: -3600,
  778. Nanos: -123,
  779. },
  780. OptTimestamp: &tspb.Timestamp{
  781. Seconds: 1257894000,
  782. Nanos: 123,
  783. },
  784. }),
  785. want: `opt_duration: {
  786. seconds: -3600
  787. nanos: -123
  788. }
  789. opt_timestamp: {
  790. seconds: 1257894000
  791. nanos: 123
  792. }
  793. `,
  794. }, {
  795. desc: "well-known type struct field and different Value types",
  796. input: M(&pb2.KnownTypes{
  797. OptStruct: &stpb.Struct{
  798. Fields: map[string]*stpb.Value{
  799. "bool": &stpb.Value{
  800. Kind: &stpb.Value_BoolValue{
  801. BoolValue: true,
  802. },
  803. },
  804. "double": &stpb.Value{
  805. Kind: &stpb.Value_NumberValue{
  806. NumberValue: 3.1415,
  807. },
  808. },
  809. "null": &stpb.Value{
  810. Kind: &stpb.Value_NullValue{
  811. NullValue: stpb.NullValue_NULL_VALUE,
  812. },
  813. },
  814. "string": &stpb.Value{
  815. Kind: &stpb.Value_StringValue{
  816. StringValue: "string",
  817. },
  818. },
  819. "struct": &stpb.Value{
  820. Kind: &stpb.Value_StructValue{
  821. StructValue: &stpb.Struct{
  822. Fields: map[string]*stpb.Value{
  823. "bool": &stpb.Value{
  824. Kind: &stpb.Value_BoolValue{
  825. BoolValue: false,
  826. },
  827. },
  828. },
  829. },
  830. },
  831. },
  832. "list": &stpb.Value{
  833. Kind: &stpb.Value_ListValue{
  834. ListValue: &stpb.ListValue{
  835. Values: []*stpb.Value{
  836. {
  837. Kind: &stpb.Value_BoolValue{
  838. BoolValue: false,
  839. },
  840. },
  841. {
  842. Kind: &stpb.Value_StringValue{
  843. StringValue: "hello",
  844. },
  845. },
  846. },
  847. },
  848. },
  849. },
  850. },
  851. },
  852. }),
  853. want: `opt_struct: {
  854. fields: {
  855. key: "bool"
  856. value: {
  857. bool_value: true
  858. }
  859. }
  860. fields: {
  861. key: "double"
  862. value: {
  863. number_value: 3.1415
  864. }
  865. }
  866. fields: {
  867. key: "list"
  868. value: {
  869. list_value: {
  870. values: {
  871. bool_value: false
  872. }
  873. values: {
  874. string_value: "hello"
  875. }
  876. }
  877. }
  878. }
  879. fields: {
  880. key: "null"
  881. value: {
  882. null_value: NULL_VALUE
  883. }
  884. }
  885. fields: {
  886. key: "string"
  887. value: {
  888. string_value: "string"
  889. }
  890. }
  891. fields: {
  892. key: "struct"
  893. value: {
  894. struct_value: {
  895. fields: {
  896. key: "bool"
  897. value: {
  898. bool_value: false
  899. }
  900. }
  901. }
  902. }
  903. }
  904. }
  905. `,
  906. }}
  907. for _, tt := range tests {
  908. tt := tt
  909. t.Run(tt.desc, func(t *testing.T) {
  910. t.Parallel()
  911. want := tt.want
  912. b, err := textpb.Marshal(tt.input)
  913. if err != nil && !tt.wantErr {
  914. t.Errorf("Marshal() returned error: %v\n\n", err)
  915. }
  916. if tt.wantErr && err == nil {
  917. t.Errorf("Marshal() got nil error, want error\n\n")
  918. }
  919. if got := string(b); got != want {
  920. t.Errorf("Marshal()\n<got>\n%v\n<want>\n%v\n", got, want)
  921. if diff := cmp.Diff(want, got, splitLines); diff != "" {
  922. t.Errorf("Marshal() diff -want +got\n%v\n", diff)
  923. }
  924. }
  925. })
  926. }
  927. }