encode_test.go 14 KB

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