encode_test.go 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723
  1. // Copyright 2019 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 jsonpb_test
  5. import (
  6. "math"
  7. "strings"
  8. "testing"
  9. "github.com/golang/protobuf/v2/encoding/jsonpb"
  10. "github.com/golang/protobuf/v2/internal/encoding/pack"
  11. "github.com/golang/protobuf/v2/internal/scalar"
  12. "github.com/golang/protobuf/v2/proto"
  13. "github.com/google/go-cmp/cmp"
  14. "github.com/google/go-cmp/cmp/cmpopts"
  15. "github.com/golang/protobuf/v2/encoding/testprotos/pb2"
  16. "github.com/golang/protobuf/v2/encoding/testprotos/pb3"
  17. )
  18. // splitLines is a cmpopts.Option for comparing strings with line breaks.
  19. var splitLines = cmpopts.AcyclicTransformer("SplitLines", func(s string) []string {
  20. return strings.Split(s, "\n")
  21. })
  22. func pb2Enum(i int32) *pb2.Enum {
  23. p := new(pb2.Enum)
  24. *p = pb2.Enum(i)
  25. return p
  26. }
  27. func pb2Enums_NestedEnum(i int32) *pb2.Enums_NestedEnum {
  28. p := new(pb2.Enums_NestedEnum)
  29. *p = pb2.Enums_NestedEnum(i)
  30. return p
  31. }
  32. func TestMarshal(t *testing.T) {
  33. tests := []struct {
  34. desc string
  35. mo jsonpb.MarshalOptions
  36. input proto.Message
  37. want string
  38. }{{
  39. desc: "proto2 optional scalars not set",
  40. input: &pb2.Scalars{},
  41. want: "{}",
  42. }, {
  43. desc: "proto3 scalars not set",
  44. input: &pb3.Scalars{},
  45. want: "{}",
  46. }, {
  47. desc: "proto2 optional scalars set to zero values",
  48. input: &pb2.Scalars{
  49. OptBool: scalar.Bool(false),
  50. OptInt32: scalar.Int32(0),
  51. OptInt64: scalar.Int64(0),
  52. OptUint32: scalar.Uint32(0),
  53. OptUint64: scalar.Uint64(0),
  54. OptSint32: scalar.Int32(0),
  55. OptSint64: scalar.Int64(0),
  56. OptFixed32: scalar.Uint32(0),
  57. OptFixed64: scalar.Uint64(0),
  58. OptSfixed32: scalar.Int32(0),
  59. OptSfixed64: scalar.Int64(0),
  60. OptFloat: scalar.Float32(0),
  61. OptDouble: scalar.Float64(0),
  62. OptBytes: []byte{},
  63. OptString: scalar.String(""),
  64. },
  65. want: `{
  66. "optBool": false,
  67. "optInt32": 0,
  68. "optInt64": "0",
  69. "optUint32": 0,
  70. "optUint64": "0",
  71. "optSint32": 0,
  72. "optSint64": "0",
  73. "optFixed32": 0,
  74. "optFixed64": "0",
  75. "optSfixed32": 0,
  76. "optSfixed64": "0",
  77. "optFloat": 0,
  78. "optDouble": 0,
  79. "optBytes": "",
  80. "optString": ""
  81. }`,
  82. }, {
  83. desc: "proto2 optional scalars set to some values",
  84. input: &pb2.Scalars{
  85. OptBool: scalar.Bool(true),
  86. OptInt32: scalar.Int32(0xff),
  87. OptInt64: scalar.Int64(0xdeadbeef),
  88. OptUint32: scalar.Uint32(47),
  89. OptUint64: scalar.Uint64(0xdeadbeef),
  90. OptSint32: scalar.Int32(-1001),
  91. OptSint64: scalar.Int64(-0xffff),
  92. OptFixed64: scalar.Uint64(64),
  93. OptSfixed32: scalar.Int32(-32),
  94. OptFloat: scalar.Float32(1.02),
  95. OptDouble: scalar.Float64(1.234),
  96. OptBytes: []byte("\xe8\xb0\xb7\xe6\xad\x8c"),
  97. OptString: scalar.String("谷歌"),
  98. },
  99. want: `{
  100. "optBool": true,
  101. "optInt32": 255,
  102. "optInt64": "3735928559",
  103. "optUint32": 47,
  104. "optUint64": "3735928559",
  105. "optSint32": -1001,
  106. "optSint64": "-65535",
  107. "optFixed64": "64",
  108. "optSfixed32": -32,
  109. "optFloat": 1.02,
  110. "optDouble": 1.234,
  111. "optBytes": "6LC35q2M",
  112. "optString": "谷歌"
  113. }`,
  114. }, {
  115. desc: "float nan",
  116. input: &pb3.Scalars{
  117. SFloat: float32(math.NaN()),
  118. },
  119. want: `{
  120. "sFloat": "NaN"
  121. }`,
  122. }, {
  123. desc: "float positive infinity",
  124. input: &pb3.Scalars{
  125. SFloat: float32(math.Inf(1)),
  126. },
  127. want: `{
  128. "sFloat": "Infinity"
  129. }`,
  130. }, {
  131. desc: "float negative infinity",
  132. input: &pb3.Scalars{
  133. SFloat: float32(math.Inf(-1)),
  134. },
  135. want: `{
  136. "sFloat": "-Infinity"
  137. }`,
  138. }, {
  139. desc: "double nan",
  140. input: &pb3.Scalars{
  141. SDouble: math.NaN(),
  142. },
  143. want: `{
  144. "sDouble": "NaN"
  145. }`,
  146. }, {
  147. desc: "double positive infinity",
  148. input: &pb3.Scalars{
  149. SDouble: math.Inf(1),
  150. },
  151. want: `{
  152. "sDouble": "Infinity"
  153. }`,
  154. }, {
  155. desc: "double negative infinity",
  156. input: &pb3.Scalars{
  157. SDouble: math.Inf(-1),
  158. },
  159. want: `{
  160. "sDouble": "-Infinity"
  161. }`,
  162. }, {
  163. desc: "proto2 enum not set",
  164. input: &pb2.Enums{},
  165. want: "{}",
  166. }, {
  167. desc: "proto2 enum set to zero value",
  168. input: &pb2.Enums{
  169. OptEnum: pb2Enum(0),
  170. OptNestedEnum: pb2Enums_NestedEnum(0),
  171. },
  172. want: `{
  173. "optEnum": 0,
  174. "optNestedEnum": 0
  175. }`,
  176. }, {
  177. desc: "proto2 enum",
  178. input: &pb2.Enums{
  179. OptEnum: pb2.Enum_ONE.Enum(),
  180. OptNestedEnum: pb2.Enums_UNO.Enum(),
  181. },
  182. want: `{
  183. "optEnum": "ONE",
  184. "optNestedEnum": "UNO"
  185. }`,
  186. }, {
  187. desc: "proto2 enum set to numeric values",
  188. input: &pb2.Enums{
  189. OptEnum: pb2Enum(2),
  190. OptNestedEnum: pb2Enums_NestedEnum(2),
  191. },
  192. want: `{
  193. "optEnum": "TWO",
  194. "optNestedEnum": "DOS"
  195. }`,
  196. }, {
  197. desc: "proto2 enum set to unnamed numeric values",
  198. input: &pb2.Enums{
  199. OptEnum: pb2Enum(101),
  200. OptNestedEnum: pb2Enums_NestedEnum(-101),
  201. },
  202. want: `{
  203. "optEnum": 101,
  204. "optNestedEnum": -101
  205. }`,
  206. }, {
  207. desc: "proto3 enum not set",
  208. input: &pb3.Enums{},
  209. want: "{}",
  210. }, {
  211. desc: "proto3 enum set to zero value",
  212. input: &pb3.Enums{
  213. SEnum: pb3.Enum_ZERO,
  214. SNestedEnum: pb3.Enums_CERO,
  215. },
  216. want: "{}",
  217. }, {
  218. desc: "proto3 enum",
  219. input: &pb3.Enums{
  220. SEnum: pb3.Enum_ONE,
  221. SNestedEnum: pb3.Enums_UNO,
  222. },
  223. want: `{
  224. "sEnum": "ONE",
  225. "sNestedEnum": "UNO"
  226. }`,
  227. }, {
  228. desc: "proto3 enum set to numeric values",
  229. input: &pb3.Enums{
  230. SEnum: 2,
  231. SNestedEnum: 2,
  232. },
  233. want: `{
  234. "sEnum": "TWO",
  235. "sNestedEnum": "DOS"
  236. }`,
  237. }, {
  238. desc: "proto3 enum set to unnamed numeric values",
  239. input: &pb3.Enums{
  240. SEnum: -47,
  241. SNestedEnum: 47,
  242. },
  243. want: `{
  244. "sEnum": -47,
  245. "sNestedEnum": 47
  246. }`,
  247. }, {
  248. desc: "proto2 nested message not set",
  249. input: &pb2.Nests{},
  250. want: "{}",
  251. }, {
  252. desc: "proto2 nested message set to empty",
  253. input: &pb2.Nests{
  254. OptNested: &pb2.Nested{},
  255. Optgroup: &pb2.Nests_OptGroup{},
  256. },
  257. want: `{
  258. "optNested": {},
  259. "optgroup": {}
  260. }`,
  261. }, {
  262. desc: "proto2 nested messages",
  263. input: &pb2.Nests{
  264. OptNested: &pb2.Nested{
  265. OptString: scalar.String("nested message"),
  266. OptNested: &pb2.Nested{
  267. OptString: scalar.String("another nested message"),
  268. },
  269. },
  270. },
  271. want: `{
  272. "optNested": {
  273. "optString": "nested message",
  274. "optNested": {
  275. "optString": "another nested message"
  276. }
  277. }
  278. }`,
  279. }, {
  280. desc: "proto2 groups",
  281. input: &pb2.Nests{
  282. Optgroup: &pb2.Nests_OptGroup{
  283. OptString: scalar.String("inside a group"),
  284. OptNested: &pb2.Nested{
  285. OptString: scalar.String("nested message inside a group"),
  286. },
  287. Optnestedgroup: &pb2.Nests_OptGroup_OptNestedGroup{
  288. OptFixed32: scalar.Uint32(47),
  289. },
  290. },
  291. },
  292. want: `{
  293. "optgroup": {
  294. "optString": "inside a group",
  295. "optNested": {
  296. "optString": "nested message inside a group"
  297. },
  298. "optnestedgroup": {
  299. "optFixed32": 47
  300. }
  301. }
  302. }`,
  303. }, {
  304. desc: "proto3 nested message not set",
  305. input: &pb3.Nests{},
  306. want: "{}",
  307. }, {
  308. desc: "proto3 nested message set to empty",
  309. input: &pb3.Nests{
  310. SNested: &pb3.Nested{},
  311. },
  312. want: `{
  313. "sNested": {}
  314. }`,
  315. }, {
  316. desc: "proto3 nested message",
  317. input: &pb3.Nests{
  318. SNested: &pb3.Nested{
  319. SString: "nested message",
  320. SNested: &pb3.Nested{
  321. SString: "another nested message",
  322. },
  323. },
  324. },
  325. want: `{
  326. "sNested": {
  327. "sString": "nested message",
  328. "sNested": {
  329. "sString": "another nested message"
  330. }
  331. }
  332. }`,
  333. }, {
  334. desc: "oneof not set",
  335. input: &pb3.Oneofs{},
  336. want: "{}",
  337. }, {
  338. desc: "oneof set to empty string",
  339. input: &pb3.Oneofs{
  340. Union: &pb3.Oneofs_OneofString{},
  341. },
  342. want: `{
  343. "oneofString": ""
  344. }`,
  345. }, {
  346. desc: "oneof set to string",
  347. input: &pb3.Oneofs{
  348. Union: &pb3.Oneofs_OneofString{
  349. OneofString: "hello",
  350. },
  351. },
  352. want: `{
  353. "oneofString": "hello"
  354. }`,
  355. }, {
  356. desc: "oneof set to enum",
  357. input: &pb3.Oneofs{
  358. Union: &pb3.Oneofs_OneofEnum{
  359. OneofEnum: pb3.Enum_ZERO,
  360. },
  361. },
  362. want: `{
  363. "oneofEnum": "ZERO"
  364. }`,
  365. }, {
  366. desc: "oneof set to empty message",
  367. input: &pb3.Oneofs{
  368. Union: &pb3.Oneofs_OneofNested{
  369. OneofNested: &pb3.Nested{},
  370. },
  371. },
  372. want: `{
  373. "oneofNested": {}
  374. }`,
  375. }, {
  376. desc: "oneof set to message",
  377. input: &pb3.Oneofs{
  378. Union: &pb3.Oneofs_OneofNested{
  379. OneofNested: &pb3.Nested{
  380. SString: "nested message",
  381. },
  382. },
  383. },
  384. want: `{
  385. "oneofNested": {
  386. "sString": "nested message"
  387. }
  388. }`,
  389. }, {
  390. desc: "repeated fields not set",
  391. input: &pb2.Repeats{},
  392. want: "{}",
  393. }, {
  394. desc: "repeated fields set to empty slices",
  395. input: &pb2.Repeats{
  396. RptBool: []bool{},
  397. RptInt32: []int32{},
  398. RptInt64: []int64{},
  399. RptUint32: []uint32{},
  400. RptUint64: []uint64{},
  401. RptFloat: []float32{},
  402. RptDouble: []float64{},
  403. RptBytes: [][]byte{},
  404. },
  405. want: "{}",
  406. }, {
  407. desc: "repeated fields set to some values",
  408. input: &pb2.Repeats{
  409. RptBool: []bool{true, false, true, true},
  410. RptInt32: []int32{1, 6, 0, 0},
  411. RptInt64: []int64{-64, 47},
  412. RptUint32: []uint32{0xff, 0xffff},
  413. RptUint64: []uint64{0xdeadbeef},
  414. RptFloat: []float32{float32(math.NaN()), float32(math.Inf(1)), float32(math.Inf(-1)), 1.034},
  415. RptDouble: []float64{math.NaN(), math.Inf(1), math.Inf(-1), 1.23e-308},
  416. RptString: []string{"hello", "世界"},
  417. RptBytes: [][]byte{
  418. []byte("hello"),
  419. []byte("\xe4\xb8\x96\xe7\x95\x8c"),
  420. },
  421. },
  422. want: `{
  423. "rptBool": [
  424. true,
  425. false,
  426. true,
  427. true
  428. ],
  429. "rptInt32": [
  430. 1,
  431. 6,
  432. 0,
  433. 0
  434. ],
  435. "rptInt64": [
  436. "-64",
  437. "47"
  438. ],
  439. "rptUint32": [
  440. 255,
  441. 65535
  442. ],
  443. "rptUint64": [
  444. "3735928559"
  445. ],
  446. "rptFloat": [
  447. "NaN",
  448. "Infinity",
  449. "-Infinity",
  450. 1.034
  451. ],
  452. "rptDouble": [
  453. "NaN",
  454. "Infinity",
  455. "-Infinity",
  456. 1.23e-308
  457. ],
  458. "rptString": [
  459. "hello",
  460. "世界"
  461. ],
  462. "rptBytes": [
  463. "aGVsbG8=",
  464. "5LiW55WM"
  465. ]
  466. }`,
  467. }, {
  468. desc: "repeated enums",
  469. input: &pb2.Enums{
  470. RptEnum: []pb2.Enum{pb2.Enum_ONE, 2, pb2.Enum_TEN, 42},
  471. RptNestedEnum: []pb2.Enums_NestedEnum{2, 47, 10},
  472. },
  473. want: `{
  474. "rptEnum": [
  475. "ONE",
  476. "TWO",
  477. "TEN",
  478. 42
  479. ],
  480. "rptNestedEnum": [
  481. "DOS",
  482. 47,
  483. "DIEZ"
  484. ]
  485. }`,
  486. }, {
  487. desc: "repeated messages set to empty",
  488. input: &pb2.Nests{
  489. RptNested: []*pb2.Nested{},
  490. Rptgroup: []*pb2.Nests_RptGroup{},
  491. },
  492. want: "{}",
  493. }, {
  494. desc: "repeated 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: `{
  510. "rptNested": [
  511. {
  512. "optString": "repeat nested one"
  513. },
  514. {
  515. "optString": "repeat nested two",
  516. "optNested": {
  517. "optString": "inside repeat nested two"
  518. }
  519. },
  520. {}
  521. ]
  522. }`,
  523. }, {
  524. desc: "repeated messages contains nil value",
  525. input: &pb2.Nests{
  526. RptNested: []*pb2.Nested{nil, {}},
  527. },
  528. want: `{
  529. "rptNested": [
  530. {},
  531. {}
  532. ]
  533. }`,
  534. }, {
  535. desc: "repeated groups",
  536. input: &pb2.Nests{
  537. Rptgroup: []*pb2.Nests_RptGroup{
  538. {
  539. RptString: []string{"hello", "world"},
  540. },
  541. {},
  542. nil,
  543. },
  544. },
  545. want: `{
  546. "rptgroup": [
  547. {
  548. "rptString": [
  549. "hello",
  550. "world"
  551. ]
  552. },
  553. {},
  554. {}
  555. ]
  556. }`,
  557. }, {
  558. desc: "map fields not set",
  559. input: &pb3.Maps{},
  560. want: "{}",
  561. }, {
  562. desc: "map fields set to empty",
  563. input: &pb3.Maps{
  564. Int32ToStr: map[int32]string{},
  565. BoolToUint32: map[bool]uint32{},
  566. Uint64ToEnum: map[uint64]pb3.Enum{},
  567. StrToNested: map[string]*pb3.Nested{},
  568. StrToOneofs: map[string]*pb3.Oneofs{},
  569. },
  570. want: "{}",
  571. }, {
  572. desc: "map fields 1",
  573. input: &pb3.Maps{
  574. BoolToUint32: map[bool]uint32{
  575. true: 42,
  576. false: 101,
  577. },
  578. },
  579. want: `{
  580. "boolToUint32": {
  581. "false": 101,
  582. "true": 42
  583. }
  584. }`,
  585. }, {
  586. desc: "map fields 2",
  587. input: &pb3.Maps{
  588. Int32ToStr: map[int32]string{
  589. -101: "-101",
  590. 0xff: "0xff",
  591. 0: "zero",
  592. },
  593. },
  594. want: `{
  595. "int32ToStr": {
  596. "-101": "-101",
  597. "0": "zero",
  598. "255": "0xff"
  599. }
  600. }`,
  601. }, {
  602. desc: "map fields 3",
  603. input: &pb3.Maps{
  604. Uint64ToEnum: map[uint64]pb3.Enum{
  605. 1: pb3.Enum_ONE,
  606. 2: pb3.Enum_TWO,
  607. 10: pb3.Enum_TEN,
  608. 47: 47,
  609. },
  610. },
  611. want: `{
  612. "uint64ToEnum": {
  613. "1": "ONE",
  614. "2": "TWO",
  615. "10": "TEN",
  616. "47": 47
  617. }
  618. }`,
  619. }, {
  620. desc: "map fields 4",
  621. input: &pb3.Maps{
  622. StrToNested: map[string]*pb3.Nested{
  623. "nested": &pb3.Nested{
  624. SString: "nested in a map",
  625. },
  626. },
  627. },
  628. want: `{
  629. "strToNested": {
  630. "nested": {
  631. "sString": "nested in a map"
  632. }
  633. }
  634. }`,
  635. }, {
  636. desc: "map fields 5",
  637. input: &pb3.Maps{
  638. StrToOneofs: map[string]*pb3.Oneofs{
  639. "string": &pb3.Oneofs{
  640. Union: &pb3.Oneofs_OneofString{
  641. OneofString: "hello",
  642. },
  643. },
  644. "nested": &pb3.Oneofs{
  645. Union: &pb3.Oneofs_OneofNested{
  646. OneofNested: &pb3.Nested{
  647. SString: "nested oneof in map field value",
  648. },
  649. },
  650. },
  651. },
  652. },
  653. want: `{
  654. "strToOneofs": {
  655. "nested": {
  656. "oneofNested": {
  657. "sString": "nested oneof in map field value"
  658. }
  659. },
  660. "string": {
  661. "oneofString": "hello"
  662. }
  663. }
  664. }`,
  665. }, {
  666. desc: "map field contains nil value",
  667. input: &pb3.Maps{
  668. StrToNested: map[string]*pb3.Nested{
  669. "nil": nil,
  670. },
  671. },
  672. want: `{
  673. "strToNested": {
  674. "nil": {}
  675. }
  676. }`,
  677. }, {
  678. desc: "unknown fields are ignored",
  679. input: &pb2.Scalars{
  680. OptString: scalar.String("no unknowns"),
  681. XXX_unrecognized: pack.Message{
  682. pack.Tag{101, pack.BytesType}, pack.String("hello world"),
  683. }.Marshal(),
  684. },
  685. want: `{
  686. "optString": "no unknowns"
  687. }`,
  688. }, {
  689. desc: "json_name",
  690. input: &pb3.JSONNames{
  691. SString: "json_name",
  692. },
  693. want: `{
  694. "foo_bar": "json_name"
  695. }`,
  696. }}
  697. for _, tt := range tests {
  698. tt := tt
  699. t.Run(tt.desc, func(t *testing.T) {
  700. t.Parallel()
  701. b, err := tt.mo.Marshal(tt.input)
  702. if err != nil {
  703. t.Errorf("Marshal() returned error: %v\n", err)
  704. }
  705. got := string(b)
  706. if got != tt.want {
  707. t.Errorf("Marshal()\n<got>\n%v\n<want>\n%v\n", got, tt.want)
  708. if diff := cmp.Diff(tt.want, got, splitLines); diff != "" {
  709. t.Errorf("Marshal() diff -want +got\n%v\n", diff)
  710. }
  711. }
  712. })
  713. }
  714. }