encode_test.go 19 KB

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