encode_test.go 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936
  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/protoapi"
  10. "github.com/golang/protobuf/v2/encoding/jsonpb"
  11. "github.com/golang/protobuf/v2/internal/encoding/pack"
  12. "github.com/golang/protobuf/v2/internal/encoding/wire"
  13. "github.com/golang/protobuf/v2/internal/scalar"
  14. "github.com/golang/protobuf/v2/proto"
  15. "github.com/google/go-cmp/cmp"
  16. "github.com/google/go-cmp/cmp/cmpopts"
  17. // This legacy package is still needed when importing legacy message.
  18. _ "github.com/golang/protobuf/v2/internal/legacy"
  19. "github.com/golang/protobuf/v2/encoding/testprotos/pb2"
  20. "github.com/golang/protobuf/v2/encoding/testprotos/pb3"
  21. )
  22. // splitLines is a cmpopts.Option for comparing strings with line breaks.
  23. var splitLines = cmpopts.AcyclicTransformer("SplitLines", func(s string) []string {
  24. return strings.Split(s, "\n")
  25. })
  26. func pb2Enum(i int32) *pb2.Enum {
  27. p := new(pb2.Enum)
  28. *p = pb2.Enum(i)
  29. return p
  30. }
  31. func pb2Enums_NestedEnum(i int32) *pb2.Enums_NestedEnum {
  32. p := new(pb2.Enums_NestedEnum)
  33. *p = pb2.Enums_NestedEnum(i)
  34. return p
  35. }
  36. func setExtension(m proto.Message, xd *protoapi.ExtensionDesc, val interface{}) {
  37. knownFields := m.ProtoReflect().KnownFields()
  38. extTypes := knownFields.ExtensionTypes()
  39. extTypes.Register(xd.Type)
  40. if val == nil {
  41. return
  42. }
  43. pval := xd.Type.ValueOf(val)
  44. knownFields.Set(wire.Number(xd.Field), pval)
  45. }
  46. func TestMarshal(t *testing.T) {
  47. tests := []struct {
  48. desc string
  49. mo jsonpb.MarshalOptions
  50. input proto.Message
  51. want string
  52. }{{
  53. desc: "proto2 optional scalars not set",
  54. input: &pb2.Scalars{},
  55. want: "{}",
  56. }, {
  57. desc: "proto3 scalars not set",
  58. input: &pb3.Scalars{},
  59. want: "{}",
  60. }, {
  61. desc: "proto2 optional scalars set to zero values",
  62. input: &pb2.Scalars{
  63. OptBool: scalar.Bool(false),
  64. OptInt32: scalar.Int32(0),
  65. OptInt64: scalar.Int64(0),
  66. OptUint32: scalar.Uint32(0),
  67. OptUint64: scalar.Uint64(0),
  68. OptSint32: scalar.Int32(0),
  69. OptSint64: scalar.Int64(0),
  70. OptFixed32: scalar.Uint32(0),
  71. OptFixed64: scalar.Uint64(0),
  72. OptSfixed32: scalar.Int32(0),
  73. OptSfixed64: scalar.Int64(0),
  74. OptFloat: scalar.Float32(0),
  75. OptDouble: scalar.Float64(0),
  76. OptBytes: []byte{},
  77. OptString: scalar.String(""),
  78. },
  79. want: `{
  80. "optBool": false,
  81. "optInt32": 0,
  82. "optInt64": "0",
  83. "optUint32": 0,
  84. "optUint64": "0",
  85. "optSint32": 0,
  86. "optSint64": "0",
  87. "optFixed32": 0,
  88. "optFixed64": "0",
  89. "optSfixed32": 0,
  90. "optSfixed64": "0",
  91. "optFloat": 0,
  92. "optDouble": 0,
  93. "optBytes": "",
  94. "optString": ""
  95. }`,
  96. }, {
  97. desc: "proto2 optional scalars set to some values",
  98. input: &pb2.Scalars{
  99. OptBool: scalar.Bool(true),
  100. OptInt32: scalar.Int32(0xff),
  101. OptInt64: scalar.Int64(0xdeadbeef),
  102. OptUint32: scalar.Uint32(47),
  103. OptUint64: scalar.Uint64(0xdeadbeef),
  104. OptSint32: scalar.Int32(-1001),
  105. OptSint64: scalar.Int64(-0xffff),
  106. OptFixed64: scalar.Uint64(64),
  107. OptSfixed32: scalar.Int32(-32),
  108. OptFloat: scalar.Float32(1.02),
  109. OptDouble: scalar.Float64(1.234),
  110. OptBytes: []byte("谷歌"),
  111. OptString: scalar.String("谷歌"),
  112. },
  113. want: `{
  114. "optBool": true,
  115. "optInt32": 255,
  116. "optInt64": "3735928559",
  117. "optUint32": 47,
  118. "optUint64": "3735928559",
  119. "optSint32": -1001,
  120. "optSint64": "-65535",
  121. "optFixed64": "64",
  122. "optSfixed32": -32,
  123. "optFloat": 1.02,
  124. "optDouble": 1.234,
  125. "optBytes": "6LC35q2M",
  126. "optString": "谷歌"
  127. }`,
  128. }, {
  129. desc: "float nan",
  130. input: &pb3.Scalars{
  131. SFloat: float32(math.NaN()),
  132. },
  133. want: `{
  134. "sFloat": "NaN"
  135. }`,
  136. }, {
  137. desc: "float positive infinity",
  138. input: &pb3.Scalars{
  139. SFloat: float32(math.Inf(1)),
  140. },
  141. want: `{
  142. "sFloat": "Infinity"
  143. }`,
  144. }, {
  145. desc: "float negative infinity",
  146. input: &pb3.Scalars{
  147. SFloat: float32(math.Inf(-1)),
  148. },
  149. want: `{
  150. "sFloat": "-Infinity"
  151. }`,
  152. }, {
  153. desc: "double nan",
  154. input: &pb3.Scalars{
  155. SDouble: math.NaN(),
  156. },
  157. want: `{
  158. "sDouble": "NaN"
  159. }`,
  160. }, {
  161. desc: "double positive infinity",
  162. input: &pb3.Scalars{
  163. SDouble: math.Inf(1),
  164. },
  165. want: `{
  166. "sDouble": "Infinity"
  167. }`,
  168. }, {
  169. desc: "double negative infinity",
  170. input: &pb3.Scalars{
  171. SDouble: math.Inf(-1),
  172. },
  173. want: `{
  174. "sDouble": "-Infinity"
  175. }`,
  176. }, {
  177. desc: "proto2 enum not set",
  178. input: &pb2.Enums{},
  179. want: "{}",
  180. }, {
  181. desc: "proto2 enum set to zero value",
  182. input: &pb2.Enums{
  183. OptEnum: pb2Enum(0),
  184. OptNestedEnum: pb2Enums_NestedEnum(0),
  185. },
  186. want: `{
  187. "optEnum": 0,
  188. "optNestedEnum": 0
  189. }`,
  190. }, {
  191. desc: "proto2 enum",
  192. input: &pb2.Enums{
  193. OptEnum: pb2.Enum_ONE.Enum(),
  194. OptNestedEnum: pb2.Enums_UNO.Enum(),
  195. },
  196. want: `{
  197. "optEnum": "ONE",
  198. "optNestedEnum": "UNO"
  199. }`,
  200. }, {
  201. desc: "proto2 enum set to numeric values",
  202. input: &pb2.Enums{
  203. OptEnum: pb2Enum(2),
  204. OptNestedEnum: pb2Enums_NestedEnum(2),
  205. },
  206. want: `{
  207. "optEnum": "TWO",
  208. "optNestedEnum": "DOS"
  209. }`,
  210. }, {
  211. desc: "proto2 enum set to unnamed numeric values",
  212. input: &pb2.Enums{
  213. OptEnum: pb2Enum(101),
  214. OptNestedEnum: pb2Enums_NestedEnum(-101),
  215. },
  216. want: `{
  217. "optEnum": 101,
  218. "optNestedEnum": -101
  219. }`,
  220. }, {
  221. desc: "proto3 enum not set",
  222. input: &pb3.Enums{},
  223. want: "{}",
  224. }, {
  225. desc: "proto3 enum set to zero value",
  226. input: &pb3.Enums{
  227. SEnum: pb3.Enum_ZERO,
  228. SNestedEnum: pb3.Enums_CERO,
  229. },
  230. want: "{}",
  231. }, {
  232. desc: "proto3 enum",
  233. input: &pb3.Enums{
  234. SEnum: pb3.Enum_ONE,
  235. SNestedEnum: pb3.Enums_UNO,
  236. },
  237. want: `{
  238. "sEnum": "ONE",
  239. "sNestedEnum": "UNO"
  240. }`,
  241. }, {
  242. desc: "proto3 enum set to numeric values",
  243. input: &pb3.Enums{
  244. SEnum: 2,
  245. SNestedEnum: 2,
  246. },
  247. want: `{
  248. "sEnum": "TWO",
  249. "sNestedEnum": "DOS"
  250. }`,
  251. }, {
  252. desc: "proto3 enum set to unnamed numeric values",
  253. input: &pb3.Enums{
  254. SEnum: -47,
  255. SNestedEnum: 47,
  256. },
  257. want: `{
  258. "sEnum": -47,
  259. "sNestedEnum": 47
  260. }`,
  261. }, {
  262. desc: "proto2 nested message not set",
  263. input: &pb2.Nests{},
  264. want: "{}",
  265. }, {
  266. desc: "proto2 nested message set to empty",
  267. input: &pb2.Nests{
  268. OptNested: &pb2.Nested{},
  269. Optgroup: &pb2.Nests_OptGroup{},
  270. },
  271. want: `{
  272. "optNested": {},
  273. "optgroup": {}
  274. }`,
  275. }, {
  276. desc: "proto2 nested messages",
  277. input: &pb2.Nests{
  278. OptNested: &pb2.Nested{
  279. OptString: scalar.String("nested message"),
  280. OptNested: &pb2.Nested{
  281. OptString: scalar.String("another nested message"),
  282. },
  283. },
  284. },
  285. want: `{
  286. "optNested": {
  287. "optString": "nested message",
  288. "optNested": {
  289. "optString": "another nested message"
  290. }
  291. }
  292. }`,
  293. }, {
  294. desc: "proto2 groups",
  295. input: &pb2.Nests{
  296. Optgroup: &pb2.Nests_OptGroup{
  297. OptString: scalar.String("inside a group"),
  298. OptNested: &pb2.Nested{
  299. OptString: scalar.String("nested message inside a group"),
  300. },
  301. Optnestedgroup: &pb2.Nests_OptGroup_OptNestedGroup{
  302. OptFixed32: scalar.Uint32(47),
  303. },
  304. },
  305. },
  306. want: `{
  307. "optgroup": {
  308. "optString": "inside a group",
  309. "optNested": {
  310. "optString": "nested message inside a group"
  311. },
  312. "optnestedgroup": {
  313. "optFixed32": 47
  314. }
  315. }
  316. }`,
  317. }, {
  318. desc: "proto3 nested message not set",
  319. input: &pb3.Nests{},
  320. want: "{}",
  321. }, {
  322. desc: "proto3 nested message set to empty",
  323. input: &pb3.Nests{
  324. SNested: &pb3.Nested{},
  325. },
  326. want: `{
  327. "sNested": {}
  328. }`,
  329. }, {
  330. desc: "proto3 nested message",
  331. input: &pb3.Nests{
  332. SNested: &pb3.Nested{
  333. SString: "nested message",
  334. SNested: &pb3.Nested{
  335. SString: "another nested message",
  336. },
  337. },
  338. },
  339. want: `{
  340. "sNested": {
  341. "sString": "nested message",
  342. "sNested": {
  343. "sString": "another nested message"
  344. }
  345. }
  346. }`,
  347. }, {
  348. desc: "oneof not set",
  349. input: &pb3.Oneofs{},
  350. want: "{}",
  351. }, {
  352. desc: "oneof set to empty string",
  353. input: &pb3.Oneofs{
  354. Union: &pb3.Oneofs_OneofString{},
  355. },
  356. want: `{
  357. "oneofString": ""
  358. }`,
  359. }, {
  360. desc: "oneof set to string",
  361. input: &pb3.Oneofs{
  362. Union: &pb3.Oneofs_OneofString{
  363. OneofString: "hello",
  364. },
  365. },
  366. want: `{
  367. "oneofString": "hello"
  368. }`,
  369. }, {
  370. desc: "oneof set to enum",
  371. input: &pb3.Oneofs{
  372. Union: &pb3.Oneofs_OneofEnum{
  373. OneofEnum: pb3.Enum_ZERO,
  374. },
  375. },
  376. want: `{
  377. "oneofEnum": "ZERO"
  378. }`,
  379. }, {
  380. desc: "oneof set to empty message",
  381. input: &pb3.Oneofs{
  382. Union: &pb3.Oneofs_OneofNested{
  383. OneofNested: &pb3.Nested{},
  384. },
  385. },
  386. want: `{
  387. "oneofNested": {}
  388. }`,
  389. }, {
  390. desc: "oneof set to message",
  391. input: &pb3.Oneofs{
  392. Union: &pb3.Oneofs_OneofNested{
  393. OneofNested: &pb3.Nested{
  394. SString: "nested message",
  395. },
  396. },
  397. },
  398. want: `{
  399. "oneofNested": {
  400. "sString": "nested message"
  401. }
  402. }`,
  403. }, {
  404. desc: "repeated fields not set",
  405. input: &pb2.Repeats{},
  406. want: "{}",
  407. }, {
  408. desc: "repeated fields set to empty slices",
  409. input: &pb2.Repeats{
  410. RptBool: []bool{},
  411. RptInt32: []int32{},
  412. RptInt64: []int64{},
  413. RptUint32: []uint32{},
  414. RptUint64: []uint64{},
  415. RptFloat: []float32{},
  416. RptDouble: []float64{},
  417. RptBytes: [][]byte{},
  418. },
  419. want: "{}",
  420. }, {
  421. desc: "repeated fields set to some values",
  422. input: &pb2.Repeats{
  423. RptBool: []bool{true, false, true, true},
  424. RptInt32: []int32{1, 6, 0, 0},
  425. RptInt64: []int64{-64, 47},
  426. RptUint32: []uint32{0xff, 0xffff},
  427. RptUint64: []uint64{0xdeadbeef},
  428. RptFloat: []float32{float32(math.NaN()), float32(math.Inf(1)), float32(math.Inf(-1)), 1.034},
  429. RptDouble: []float64{math.NaN(), math.Inf(1), math.Inf(-1), 1.23e-308},
  430. RptString: []string{"hello", "世界"},
  431. RptBytes: [][]byte{
  432. []byte("hello"),
  433. []byte("\xe4\xb8\x96\xe7\x95\x8c"),
  434. },
  435. },
  436. want: `{
  437. "rptBool": [
  438. true,
  439. false,
  440. true,
  441. true
  442. ],
  443. "rptInt32": [
  444. 1,
  445. 6,
  446. 0,
  447. 0
  448. ],
  449. "rptInt64": [
  450. "-64",
  451. "47"
  452. ],
  453. "rptUint32": [
  454. 255,
  455. 65535
  456. ],
  457. "rptUint64": [
  458. "3735928559"
  459. ],
  460. "rptFloat": [
  461. "NaN",
  462. "Infinity",
  463. "-Infinity",
  464. 1.034
  465. ],
  466. "rptDouble": [
  467. "NaN",
  468. "Infinity",
  469. "-Infinity",
  470. 1.23e-308
  471. ],
  472. "rptString": [
  473. "hello",
  474. "世界"
  475. ],
  476. "rptBytes": [
  477. "aGVsbG8=",
  478. "5LiW55WM"
  479. ]
  480. }`,
  481. }, {
  482. desc: "repeated enums",
  483. input: &pb2.Enums{
  484. RptEnum: []pb2.Enum{pb2.Enum_ONE, 2, pb2.Enum_TEN, 42},
  485. RptNestedEnum: []pb2.Enums_NestedEnum{2, 47, 10},
  486. },
  487. want: `{
  488. "rptEnum": [
  489. "ONE",
  490. "TWO",
  491. "TEN",
  492. 42
  493. ],
  494. "rptNestedEnum": [
  495. "DOS",
  496. 47,
  497. "DIEZ"
  498. ]
  499. }`,
  500. }, {
  501. desc: "repeated messages set to empty",
  502. input: &pb2.Nests{
  503. RptNested: []*pb2.Nested{},
  504. Rptgroup: []*pb2.Nests_RptGroup{},
  505. },
  506. want: "{}",
  507. }, {
  508. desc: "repeated messages",
  509. input: &pb2.Nests{
  510. RptNested: []*pb2.Nested{
  511. {
  512. OptString: scalar.String("repeat nested one"),
  513. },
  514. {
  515. OptString: scalar.String("repeat nested two"),
  516. OptNested: &pb2.Nested{
  517. OptString: scalar.String("inside repeat nested two"),
  518. },
  519. },
  520. {},
  521. },
  522. },
  523. want: `{
  524. "rptNested": [
  525. {
  526. "optString": "repeat nested one"
  527. },
  528. {
  529. "optString": "repeat nested two",
  530. "optNested": {
  531. "optString": "inside repeat nested two"
  532. }
  533. },
  534. {}
  535. ]
  536. }`,
  537. }, {
  538. desc: "repeated messages contains nil value",
  539. input: &pb2.Nests{
  540. RptNested: []*pb2.Nested{nil, {}},
  541. },
  542. want: `{
  543. "rptNested": [
  544. {},
  545. {}
  546. ]
  547. }`,
  548. }, {
  549. desc: "repeated groups",
  550. input: &pb2.Nests{
  551. Rptgroup: []*pb2.Nests_RptGroup{
  552. {
  553. RptString: []string{"hello", "world"},
  554. },
  555. {},
  556. nil,
  557. },
  558. },
  559. want: `{
  560. "rptgroup": [
  561. {
  562. "rptString": [
  563. "hello",
  564. "world"
  565. ]
  566. },
  567. {},
  568. {}
  569. ]
  570. }`,
  571. }, {
  572. desc: "map fields not set",
  573. input: &pb3.Maps{},
  574. want: "{}",
  575. }, {
  576. desc: "map fields set to empty",
  577. input: &pb3.Maps{
  578. Int32ToStr: map[int32]string{},
  579. BoolToUint32: map[bool]uint32{},
  580. Uint64ToEnum: map[uint64]pb3.Enum{},
  581. StrToNested: map[string]*pb3.Nested{},
  582. StrToOneofs: map[string]*pb3.Oneofs{},
  583. },
  584. want: "{}",
  585. }, {
  586. desc: "map fields 1",
  587. input: &pb3.Maps{
  588. BoolToUint32: map[bool]uint32{
  589. true: 42,
  590. false: 101,
  591. },
  592. },
  593. want: `{
  594. "boolToUint32": {
  595. "false": 101,
  596. "true": 42
  597. }
  598. }`,
  599. }, {
  600. desc: "map fields 2",
  601. input: &pb3.Maps{
  602. Int32ToStr: map[int32]string{
  603. -101: "-101",
  604. 0xff: "0xff",
  605. 0: "zero",
  606. },
  607. },
  608. want: `{
  609. "int32ToStr": {
  610. "-101": "-101",
  611. "0": "zero",
  612. "255": "0xff"
  613. }
  614. }`,
  615. }, {
  616. desc: "map fields 3",
  617. input: &pb3.Maps{
  618. Uint64ToEnum: map[uint64]pb3.Enum{
  619. 1: pb3.Enum_ONE,
  620. 2: pb3.Enum_TWO,
  621. 10: pb3.Enum_TEN,
  622. 47: 47,
  623. },
  624. },
  625. want: `{
  626. "uint64ToEnum": {
  627. "1": "ONE",
  628. "2": "TWO",
  629. "10": "TEN",
  630. "47": 47
  631. }
  632. }`,
  633. }, {
  634. desc: "map fields 4",
  635. input: &pb3.Maps{
  636. StrToNested: map[string]*pb3.Nested{
  637. "nested": &pb3.Nested{
  638. SString: "nested in a map",
  639. },
  640. },
  641. },
  642. want: `{
  643. "strToNested": {
  644. "nested": {
  645. "sString": "nested in a map"
  646. }
  647. }
  648. }`,
  649. }, {
  650. desc: "map fields 5",
  651. input: &pb3.Maps{
  652. StrToOneofs: map[string]*pb3.Oneofs{
  653. "string": &pb3.Oneofs{
  654. Union: &pb3.Oneofs_OneofString{
  655. OneofString: "hello",
  656. },
  657. },
  658. "nested": &pb3.Oneofs{
  659. Union: &pb3.Oneofs_OneofNested{
  660. OneofNested: &pb3.Nested{
  661. SString: "nested oneof in map field value",
  662. },
  663. },
  664. },
  665. },
  666. },
  667. want: `{
  668. "strToOneofs": {
  669. "nested": {
  670. "oneofNested": {
  671. "sString": "nested oneof in map field value"
  672. }
  673. },
  674. "string": {
  675. "oneofString": "hello"
  676. }
  677. }
  678. }`,
  679. }, {
  680. desc: "map field contains nil value",
  681. input: &pb3.Maps{
  682. StrToNested: map[string]*pb3.Nested{
  683. "nil": nil,
  684. },
  685. },
  686. want: `{
  687. "strToNested": {
  688. "nil": {}
  689. }
  690. }`,
  691. }, {
  692. desc: "unknown fields are ignored",
  693. input: &pb2.Scalars{
  694. OptString: scalar.String("no unknowns"),
  695. XXX_unrecognized: pack.Message{
  696. pack.Tag{101, pack.BytesType}, pack.String("hello world"),
  697. }.Marshal(),
  698. },
  699. want: `{
  700. "optString": "no unknowns"
  701. }`,
  702. }, {
  703. desc: "json_name",
  704. input: &pb3.JSONNames{
  705. SString: "json_name",
  706. },
  707. want: `{
  708. "foo_bar": "json_name"
  709. }`,
  710. }, {
  711. desc: "extensions of non-repeated fields",
  712. input: func() proto.Message {
  713. m := &pb2.Extensions{
  714. OptString: scalar.String("non-extension field"),
  715. OptBool: scalar.Bool(true),
  716. OptInt32: scalar.Int32(42),
  717. }
  718. setExtension(m, pb2.E_OptExtBool, true)
  719. setExtension(m, pb2.E_OptExtString, "extension field")
  720. setExtension(m, pb2.E_OptExtEnum, pb2.Enum_TEN)
  721. setExtension(m, pb2.E_OptExtNested, &pb2.Nested{
  722. OptString: scalar.String("nested in an extension"),
  723. OptNested: &pb2.Nested{
  724. OptString: scalar.String("another nested in an extension"),
  725. },
  726. })
  727. return m
  728. }(),
  729. want: `{
  730. "optString": "non-extension field",
  731. "optBool": true,
  732. "optInt32": 42,
  733. "[pb2.opt_ext_bool]": true,
  734. "[pb2.opt_ext_enum]": "TEN",
  735. "[pb2.opt_ext_nested]": {
  736. "optString": "nested in an extension",
  737. "optNested": {
  738. "optString": "another nested in an extension"
  739. }
  740. },
  741. "[pb2.opt_ext_string]": "extension field"
  742. }`,
  743. }, {
  744. desc: "extension message field set to nil",
  745. input: func() proto.Message {
  746. m := &pb2.Extensions{}
  747. setExtension(m, pb2.E_OptExtNested, nil)
  748. return m
  749. }(),
  750. want: "{}",
  751. }, {
  752. desc: "extensions of repeated fields",
  753. input: func() proto.Message {
  754. m := &pb2.Extensions{}
  755. setExtension(m, pb2.E_RptExtEnum, &[]pb2.Enum{pb2.Enum_TEN, 101, pb2.Enum_ONE})
  756. setExtension(m, pb2.E_RptExtFixed32, &[]uint32{42, 47})
  757. setExtension(m, pb2.E_RptExtNested, &[]*pb2.Nested{
  758. &pb2.Nested{OptString: scalar.String("one")},
  759. &pb2.Nested{OptString: scalar.String("two")},
  760. &pb2.Nested{OptString: scalar.String("three")},
  761. })
  762. return m
  763. }(),
  764. want: `{
  765. "[pb2.rpt_ext_enum]": [
  766. "TEN",
  767. 101,
  768. "ONE"
  769. ],
  770. "[pb2.rpt_ext_fixed32]": [
  771. 42,
  772. 47
  773. ],
  774. "[pb2.rpt_ext_nested]": [
  775. {
  776. "optString": "one"
  777. },
  778. {
  779. "optString": "two"
  780. },
  781. {
  782. "optString": "three"
  783. }
  784. ]
  785. }`,
  786. }, {
  787. desc: "extensions of non-repeated fields in another message",
  788. input: func() proto.Message {
  789. m := &pb2.Extensions{}
  790. setExtension(m, pb2.E_ExtensionsContainer_OptExtBool, true)
  791. setExtension(m, pb2.E_ExtensionsContainer_OptExtString, "extension field")
  792. setExtension(m, pb2.E_ExtensionsContainer_OptExtEnum, pb2.Enum_TEN)
  793. setExtension(m, pb2.E_ExtensionsContainer_OptExtNested, &pb2.Nested{
  794. OptString: scalar.String("nested in an extension"),
  795. OptNested: &pb2.Nested{
  796. OptString: scalar.String("another nested in an extension"),
  797. },
  798. })
  799. return m
  800. }(),
  801. want: `{
  802. "[pb2.ExtensionsContainer.opt_ext_bool]": true,
  803. "[pb2.ExtensionsContainer.opt_ext_enum]": "TEN",
  804. "[pb2.ExtensionsContainer.opt_ext_nested]": {
  805. "optString": "nested in an extension",
  806. "optNested": {
  807. "optString": "another nested in an extension"
  808. }
  809. },
  810. "[pb2.ExtensionsContainer.opt_ext_string]": "extension field"
  811. }`,
  812. }, {
  813. desc: "extensions of repeated fields in another message",
  814. input: func() proto.Message {
  815. m := &pb2.Extensions{
  816. OptString: scalar.String("non-extension field"),
  817. OptBool: scalar.Bool(true),
  818. OptInt32: scalar.Int32(42),
  819. }
  820. setExtension(m, pb2.E_ExtensionsContainer_RptExtEnum, &[]pb2.Enum{pb2.Enum_TEN, 101, pb2.Enum_ONE})
  821. setExtension(m, pb2.E_ExtensionsContainer_RptExtString, &[]string{"hello", "world"})
  822. setExtension(m, pb2.E_ExtensionsContainer_RptExtNested, &[]*pb2.Nested{
  823. &pb2.Nested{OptString: scalar.String("one")},
  824. &pb2.Nested{OptString: scalar.String("two")},
  825. &pb2.Nested{OptString: scalar.String("three")},
  826. })
  827. return m
  828. }(),
  829. want: `{
  830. "optString": "non-extension field",
  831. "optBool": true,
  832. "optInt32": 42,
  833. "[pb2.ExtensionsContainer.rpt_ext_enum]": [
  834. "TEN",
  835. 101,
  836. "ONE"
  837. ],
  838. "[pb2.ExtensionsContainer.rpt_ext_nested]": [
  839. {
  840. "optString": "one"
  841. },
  842. {
  843. "optString": "two"
  844. },
  845. {
  846. "optString": "three"
  847. }
  848. ],
  849. "[pb2.ExtensionsContainer.rpt_ext_string]": [
  850. "hello",
  851. "world"
  852. ]
  853. }`,
  854. }, {
  855. desc: "MessageSet",
  856. input: func() proto.Message {
  857. m := &pb2.MessageSet{}
  858. setExtension(m, pb2.E_MessageSetExtension_MessageSetExtension, &pb2.MessageSetExtension{
  859. OptString: scalar.String("a messageset extension"),
  860. })
  861. setExtension(m, pb2.E_MessageSetExtension_NotMessageSetExtension, &pb2.MessageSetExtension{
  862. OptString: scalar.String("not a messageset extension"),
  863. })
  864. setExtension(m, pb2.E_MessageSetExtension_ExtNested, &pb2.Nested{
  865. OptString: scalar.String("just a regular extension"),
  866. })
  867. return m
  868. }(),
  869. want: `{
  870. "[pb2.MessageSetExtension]": {
  871. "optString": "a messageset extension"
  872. },
  873. "[pb2.MessageSetExtension.ext_nested]": {
  874. "optString": "just a regular extension"
  875. },
  876. "[pb2.MessageSetExtension.not_message_set_extension]": {
  877. "optString": "not a messageset extension"
  878. }
  879. }`,
  880. }, {
  881. desc: "not real MessageSet 1",
  882. input: func() proto.Message {
  883. m := &pb2.FakeMessageSet{}
  884. setExtension(m, pb2.E_FakeMessageSetExtension_MessageSetExtension, &pb2.FakeMessageSetExtension{
  885. OptString: scalar.String("not a messageset extension"),
  886. })
  887. return m
  888. }(),
  889. want: `{
  890. "[pb2.FakeMessageSetExtension.message_set_extension]": {
  891. "optString": "not a messageset extension"
  892. }
  893. }`,
  894. }, {
  895. desc: "not real MessageSet 2",
  896. input: func() proto.Message {
  897. m := &pb2.MessageSet{}
  898. setExtension(m, pb2.E_MessageSetExtension, &pb2.FakeMessageSetExtension{
  899. OptString: scalar.String("another not a messageset extension"),
  900. })
  901. return m
  902. }(),
  903. want: `{
  904. "[pb2.message_set_extension]": {
  905. "optString": "another not a messageset extension"
  906. }
  907. }`,
  908. }}
  909. for _, tt := range tests {
  910. tt := tt
  911. t.Run(tt.desc, func(t *testing.T) {
  912. b, err := tt.mo.Marshal(tt.input)
  913. if err != nil {
  914. t.Errorf("Marshal() returned error: %v\n", err)
  915. }
  916. got := string(b)
  917. if got != tt.want {
  918. t.Errorf("Marshal()\n<got>\n%v\n<want>\n%v\n", got, tt.want)
  919. if diff := cmp.Diff(tt.want, got, splitLines); diff != "" {
  920. t.Errorf("Marshal() diff -want +got\n%v\n", diff)
  921. }
  922. }
  923. })
  924. }
  925. }