decode_test.go 28 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166
  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. "testing"
  8. protoV1 "github.com/golang/protobuf/proto"
  9. "github.com/golang/protobuf/v2/encoding/jsonpb"
  10. "github.com/golang/protobuf/v2/encoding/testprotos/pb2"
  11. "github.com/golang/protobuf/v2/encoding/testprotos/pb3"
  12. "github.com/golang/protobuf/v2/internal/scalar"
  13. "github.com/golang/protobuf/v2/proto"
  14. preg "github.com/golang/protobuf/v2/reflect/protoregistry"
  15. "github.com/golang/protobuf/v2/runtime/protoiface"
  16. )
  17. func init() {
  18. // TODO: remove these registerExtension calls when generated code registers
  19. // to V2 global registry.
  20. registerExtension(pb2.E_OptExtBool)
  21. registerExtension(pb2.E_OptExtString)
  22. registerExtension(pb2.E_OptExtEnum)
  23. registerExtension(pb2.E_OptExtNested)
  24. registerExtension(pb2.E_RptExtFixed32)
  25. registerExtension(pb2.E_RptExtEnum)
  26. registerExtension(pb2.E_RptExtNested)
  27. registerExtension(pb2.E_ExtensionsContainer_OptExtBool)
  28. registerExtension(pb2.E_ExtensionsContainer_OptExtString)
  29. registerExtension(pb2.E_ExtensionsContainer_OptExtEnum)
  30. registerExtension(pb2.E_ExtensionsContainer_OptExtNested)
  31. registerExtension(pb2.E_ExtensionsContainer_RptExtString)
  32. registerExtension(pb2.E_ExtensionsContainer_RptExtEnum)
  33. registerExtension(pb2.E_ExtensionsContainer_RptExtNested)
  34. registerExtension(pb2.E_MessageSetExtension)
  35. registerExtension(pb2.E_MessageSetExtension_MessageSetExtension)
  36. registerExtension(pb2.E_MessageSetExtension_NotMessageSetExtension)
  37. registerExtension(pb2.E_MessageSetExtension_ExtNested)
  38. registerExtension(pb2.E_FakeMessageSetExtension_MessageSetExtension)
  39. }
  40. func registerExtension(xd *protoiface.ExtensionDescV1) {
  41. preg.GlobalTypes.Register(xd.Type)
  42. }
  43. func TestUnmarshal(t *testing.T) {
  44. tests := []struct {
  45. desc string
  46. umo jsonpb.UnmarshalOptions
  47. inputMessage proto.Message
  48. inputText string
  49. wantMessage proto.Message
  50. // TODO: verify expected error message substring.
  51. wantErr bool
  52. }{{
  53. desc: "proto2 empty message",
  54. inputMessage: &pb2.Scalars{},
  55. inputText: "{}",
  56. wantMessage: &pb2.Scalars{},
  57. }, {
  58. desc: "unexpected value instead of EOF",
  59. inputMessage: &pb2.Scalars{},
  60. inputText: "{} {}",
  61. wantErr: true,
  62. }, {
  63. desc: "proto2 optional scalars set to zero values",
  64. inputMessage: &pb2.Scalars{},
  65. inputText: `{
  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. wantMessage: &pb2.Scalars{
  83. OptBool: scalar.Bool(false),
  84. OptInt32: scalar.Int32(0),
  85. OptInt64: scalar.Int64(0),
  86. OptUint32: scalar.Uint32(0),
  87. OptUint64: scalar.Uint64(0),
  88. OptSint32: scalar.Int32(0),
  89. OptSint64: scalar.Int64(0),
  90. OptFixed32: scalar.Uint32(0),
  91. OptFixed64: scalar.Uint64(0),
  92. OptSfixed32: scalar.Int32(0),
  93. OptSfixed64: scalar.Int64(0),
  94. OptFloat: scalar.Float32(0),
  95. OptDouble: scalar.Float64(0),
  96. OptBytes: []byte{},
  97. OptString: scalar.String(""),
  98. },
  99. }, {
  100. desc: "proto3 scalars set to zero values",
  101. inputMessage: &pb3.Scalars{},
  102. inputText: `{
  103. "sBool": false,
  104. "sInt32": 0,
  105. "sInt64": 0,
  106. "sUint32": 0,
  107. "sUint64": 0,
  108. "sSint32": 0,
  109. "sSint64": 0,
  110. "sFixed32": 0,
  111. "sFixed64": 0,
  112. "sSfixed32": 0,
  113. "sSfixed64": 0,
  114. "sFloat": 0,
  115. "sDouble": 0,
  116. "sBytes": "",
  117. "sString": ""
  118. }`,
  119. wantMessage: &pb3.Scalars{},
  120. }, {
  121. desc: "proto2 optional scalars set to null",
  122. inputMessage: &pb2.Scalars{},
  123. inputText: `{
  124. "optBool": null,
  125. "optInt32": null,
  126. "optInt64": null,
  127. "optUint32": null,
  128. "optUint64": null,
  129. "optSint32": null,
  130. "optSint64": null,
  131. "optFixed32": null,
  132. "optFixed64": null,
  133. "optSfixed32": null,
  134. "optSfixed64": null,
  135. "optFloat": null,
  136. "optDouble": null,
  137. "optBytes": null,
  138. "optString": null
  139. }`,
  140. wantMessage: &pb2.Scalars{},
  141. }, {
  142. desc: "proto3 scalars set to null",
  143. inputMessage: &pb3.Scalars{},
  144. inputText: `{
  145. "sBool": null,
  146. "sInt32": null,
  147. "sInt64": null,
  148. "sUint32": null,
  149. "sUint64": null,
  150. "sSint32": null,
  151. "sSint64": null,
  152. "sFixed32": null,
  153. "sFixed64": null,
  154. "sSfixed32": null,
  155. "sSfixed64": null,
  156. "sFloat": null,
  157. "sDouble": null,
  158. "sBytes": null,
  159. "sString": null
  160. }`,
  161. wantMessage: &pb3.Scalars{},
  162. }, {
  163. desc: "boolean",
  164. inputMessage: &pb3.Scalars{},
  165. inputText: `{"sBool": true}`,
  166. wantMessage: &pb3.Scalars{
  167. SBool: true,
  168. },
  169. }, {
  170. desc: "not boolean",
  171. inputMessage: &pb3.Scalars{},
  172. inputText: `{"sBool": "true"}`,
  173. wantErr: true,
  174. }, {
  175. desc: "float and double",
  176. inputMessage: &pb3.Scalars{},
  177. inputText: `{
  178. "sFloat": 1.234,
  179. "sDouble": 5.678
  180. }`,
  181. wantMessage: &pb3.Scalars{
  182. SFloat: 1.234,
  183. SDouble: 5.678,
  184. },
  185. }, {
  186. desc: "float and double in string",
  187. inputMessage: &pb3.Scalars{},
  188. inputText: `{
  189. "sFloat": "1.234",
  190. "sDouble": "5.678"
  191. }`,
  192. wantMessage: &pb3.Scalars{
  193. SFloat: 1.234,
  194. SDouble: 5.678,
  195. },
  196. }, {
  197. desc: "float and double in E notation",
  198. inputMessage: &pb3.Scalars{},
  199. inputText: `{
  200. "sFloat": 12.34E-1,
  201. "sDouble": 5.678e4
  202. }`,
  203. wantMessage: &pb3.Scalars{
  204. SFloat: 1.234,
  205. SDouble: 56780,
  206. },
  207. }, {
  208. desc: "float and double in string E notation",
  209. inputMessage: &pb3.Scalars{},
  210. inputText: `{
  211. "sFloat": "12.34E-1",
  212. "sDouble": "5.678e4"
  213. }`,
  214. wantMessage: &pb3.Scalars{
  215. SFloat: 1.234,
  216. SDouble: 56780,
  217. },
  218. }, {
  219. desc: "float exceeds limit",
  220. inputMessage: &pb3.Scalars{},
  221. inputText: `{"sFloat": 3.4e39}`,
  222. wantErr: true,
  223. }, {
  224. desc: "float in string exceeds limit",
  225. inputMessage: &pb3.Scalars{},
  226. inputText: `{"sFloat": "-3.4e39"}`,
  227. wantErr: true,
  228. }, {
  229. desc: "double exceeds limit",
  230. inputMessage: &pb3.Scalars{},
  231. inputText: `{"sFloat": -1.79e+309}`,
  232. wantErr: true,
  233. }, {
  234. desc: "double in string exceeds limit",
  235. inputMessage: &pb3.Scalars{},
  236. inputText: `{"sFloat": "1.79e+309"}`,
  237. wantErr: true,
  238. }, {
  239. desc: "infinites",
  240. inputMessage: &pb3.Scalars{},
  241. inputText: `{"sFloat": "Infinity", "sDouble": "-Infinity"}`,
  242. wantMessage: &pb3.Scalars{
  243. SFloat: float32(math.Inf(+1)),
  244. SDouble: math.Inf(-1),
  245. },
  246. }, {
  247. desc: "not float",
  248. inputMessage: &pb3.Scalars{},
  249. inputText: `{"sFloat": true}`,
  250. wantErr: true,
  251. }, {
  252. desc: "not double",
  253. inputMessage: &pb3.Scalars{},
  254. inputText: `{"sDouble": "not a number"}`,
  255. wantErr: true,
  256. }, {
  257. desc: "integers",
  258. inputMessage: &pb3.Scalars{},
  259. inputText: `{
  260. "sInt32": 1234,
  261. "sInt64": -1234,
  262. "sUint32": 1e2,
  263. "sUint64": 100E-2,
  264. "sSint32": 1.0,
  265. "sSint64": -1.0,
  266. "sFixed32": 1.234e+5,
  267. "sFixed64": 1200E-2,
  268. "sSfixed32": -1.234e05,
  269. "sSfixed64": -1200e-02
  270. }`,
  271. wantMessage: &pb3.Scalars{
  272. SInt32: 1234,
  273. SInt64: -1234,
  274. SUint32: 100,
  275. SUint64: 1,
  276. SSint32: 1,
  277. SSint64: -1,
  278. SFixed32: 123400,
  279. SFixed64: 12,
  280. SSfixed32: -123400,
  281. SSfixed64: -12,
  282. },
  283. }, {
  284. desc: "integers in string",
  285. inputMessage: &pb3.Scalars{},
  286. inputText: `{
  287. "sInt32": "1234",
  288. "sInt64": "-1234",
  289. "sUint32": "1e2",
  290. "sUint64": "100E-2",
  291. "sSint32": "1.0",
  292. "sSint64": "-1.0",
  293. "sFixed32": "1.234e+5",
  294. "sFixed64": "1200E-2",
  295. "sSfixed32": "-1.234e05",
  296. "sSfixed64": "-1200e-02"
  297. }`,
  298. wantMessage: &pb3.Scalars{
  299. SInt32: 1234,
  300. SInt64: -1234,
  301. SUint32: 100,
  302. SUint64: 1,
  303. SSint32: 1,
  304. SSint64: -1,
  305. SFixed32: 123400,
  306. SFixed64: 12,
  307. SSfixed32: -123400,
  308. SSfixed64: -12,
  309. },
  310. }, {
  311. desc: "integers in escaped string",
  312. inputMessage: &pb3.Scalars{},
  313. inputText: `{"sInt32": "\u0031\u0032"}`,
  314. wantMessage: &pb3.Scalars{
  315. SInt32: 12,
  316. },
  317. }, {
  318. desc: "number is not an integer",
  319. inputMessage: &pb3.Scalars{},
  320. inputText: `{"sInt32": 1.001}`,
  321. wantErr: true,
  322. }, {
  323. desc: "32-bit int exceeds limit",
  324. inputMessage: &pb3.Scalars{},
  325. inputText: `{"sInt32": 2e10}`,
  326. wantErr: true,
  327. }, {
  328. desc: "64-bit int exceeds limit",
  329. inputMessage: &pb3.Scalars{},
  330. inputText: `{"sSfixed64": -9e19}`,
  331. wantErr: true,
  332. }, {
  333. desc: "not integer",
  334. inputMessage: &pb3.Scalars{},
  335. inputText: `{"sInt32": "not a number"}`,
  336. wantErr: true,
  337. }, {
  338. desc: "not unsigned integer",
  339. inputMessage: &pb3.Scalars{},
  340. inputText: `{"sUint32": "not a number"}`,
  341. wantErr: true,
  342. }, {
  343. desc: "number is not an unsigned integer",
  344. inputMessage: &pb3.Scalars{},
  345. inputText: `{"sUint32": -1}`,
  346. wantErr: true,
  347. }, {
  348. desc: "string",
  349. inputMessage: &pb2.Scalars{},
  350. inputText: `{"optString": "谷歌"}`,
  351. wantMessage: &pb2.Scalars{
  352. OptString: scalar.String("谷歌"),
  353. },
  354. }, {
  355. desc: "string with invalid UTF-8",
  356. inputMessage: &pb3.Scalars{},
  357. inputText: "{\"sString\": \"\xff\"}",
  358. wantMessage: &pb3.Scalars{
  359. SString: "\xff",
  360. },
  361. wantErr: true,
  362. }, {
  363. desc: "not string",
  364. inputMessage: &pb2.Scalars{},
  365. inputText: `{"optString": 42}`,
  366. wantErr: true,
  367. }, {
  368. desc: "bytes",
  369. inputMessage: &pb3.Scalars{},
  370. inputText: `{"sBytes": "aGVsbG8gd29ybGQ"}`,
  371. wantMessage: &pb3.Scalars{
  372. SBytes: []byte("hello world"),
  373. },
  374. }, {
  375. desc: "bytes padded",
  376. inputMessage: &pb3.Scalars{},
  377. inputText: `{"sBytes": "aGVsbG8gd29ybGQ="}`,
  378. wantMessage: &pb3.Scalars{
  379. SBytes: []byte("hello world"),
  380. },
  381. }, {
  382. desc: "not bytes",
  383. inputMessage: &pb3.Scalars{},
  384. inputText: `{"sBytes": true}`,
  385. wantErr: true,
  386. }, {
  387. desc: "proto2 enum",
  388. inputMessage: &pb2.Enums{},
  389. inputText: `{
  390. "optEnum": "ONE",
  391. "optNestedEnum": "UNO"
  392. }`,
  393. wantMessage: &pb2.Enums{
  394. OptEnum: pb2.Enum_ONE.Enum(),
  395. OptNestedEnum: pb2.Enums_UNO.Enum(),
  396. },
  397. }, {
  398. desc: "proto3 enum",
  399. inputMessage: &pb3.Enums{},
  400. inputText: `{
  401. "sEnum": "ONE",
  402. "sNestedEnum": "DIEZ"
  403. }`,
  404. wantMessage: &pb3.Enums{
  405. SEnum: pb3.Enum_ONE,
  406. SNestedEnum: pb3.Enums_DIEZ,
  407. },
  408. }, {
  409. desc: "enum numeric value",
  410. inputMessage: &pb3.Enums{},
  411. inputText: `{
  412. "sEnum": 2,
  413. "sNestedEnum": 2
  414. }`,
  415. wantMessage: &pb3.Enums{
  416. SEnum: pb3.Enum_TWO,
  417. SNestedEnum: pb3.Enums_DOS,
  418. },
  419. }, {
  420. desc: "enum unnamed numeric value",
  421. inputMessage: &pb3.Enums{},
  422. inputText: `{
  423. "sEnum": 101,
  424. "sNestedEnum": -101
  425. }`,
  426. wantMessage: &pb3.Enums{
  427. SEnum: 101,
  428. SNestedEnum: -101,
  429. },
  430. }, {
  431. desc: "enum set to number string",
  432. inputMessage: &pb3.Enums{},
  433. inputText: `{
  434. "sEnum": "1",
  435. }`,
  436. wantErr: true,
  437. }, {
  438. desc: "enum set to invalid named",
  439. inputMessage: &pb3.Enums{},
  440. inputText: `{
  441. "sEnum": "UNNAMED",
  442. }`,
  443. wantErr: true,
  444. }, {
  445. desc: "enum set to not enum",
  446. inputMessage: &pb3.Enums{},
  447. inputText: `{
  448. "sEnum": true,
  449. }`,
  450. wantErr: true,
  451. }, {
  452. desc: "proto name",
  453. inputMessage: &pb3.JSONNames{},
  454. inputText: `{
  455. "s_string": "proto name used"
  456. }`,
  457. wantMessage: &pb3.JSONNames{
  458. SString: "proto name used",
  459. },
  460. }, {
  461. desc: "json_name",
  462. inputMessage: &pb3.JSONNames{},
  463. inputText: `{
  464. "foo_bar": "json_name used"
  465. }`,
  466. wantMessage: &pb3.JSONNames{
  467. SString: "json_name used",
  468. },
  469. }, {
  470. desc: "camelCase name",
  471. inputMessage: &pb3.JSONNames{},
  472. inputText: `{
  473. "sString": "camelcase used"
  474. }`,
  475. wantErr: true,
  476. }, {
  477. desc: "proto name and json_name",
  478. inputMessage: &pb3.JSONNames{},
  479. inputText: `{
  480. "foo_bar": "json_name used",
  481. "s_string": "proto name used"
  482. }`,
  483. wantErr: true,
  484. }, {
  485. desc: "duplicate field names",
  486. inputMessage: &pb3.JSONNames{},
  487. inputText: `{
  488. "foo_bar": "one",
  489. "foo_bar": "two",
  490. }`,
  491. wantErr: true,
  492. }, {
  493. desc: "null message",
  494. inputMessage: &pb2.Nests{},
  495. inputText: "null",
  496. wantErr: true,
  497. }, {
  498. desc: "proto2 nested message not set",
  499. inputMessage: &pb2.Nests{},
  500. inputText: "{}",
  501. wantMessage: &pb2.Nests{},
  502. }, {
  503. desc: "proto2 nested message set to null",
  504. inputMessage: &pb2.Nests{},
  505. inputText: `{
  506. "optNested": null,
  507. "optgroup": null
  508. }`,
  509. wantMessage: &pb2.Nests{},
  510. }, {
  511. desc: "proto2 nested message set to empty",
  512. inputMessage: &pb2.Nests{},
  513. inputText: `{
  514. "optNested": {},
  515. "optgroup": {}
  516. }`,
  517. wantMessage: &pb2.Nests{
  518. OptNested: &pb2.Nested{},
  519. Optgroup: &pb2.Nests_OptGroup{},
  520. },
  521. }, {
  522. desc: "proto2 nested messages",
  523. inputMessage: &pb2.Nests{},
  524. inputText: `{
  525. "optNested": {
  526. "optString": "nested message",
  527. "optNested": {
  528. "optString": "another nested message"
  529. }
  530. }
  531. }`,
  532. wantMessage: &pb2.Nests{
  533. OptNested: &pb2.Nested{
  534. OptString: scalar.String("nested message"),
  535. OptNested: &pb2.Nested{
  536. OptString: scalar.String("another nested message"),
  537. },
  538. },
  539. },
  540. }, {
  541. desc: "proto2 groups",
  542. inputMessage: &pb2.Nests{},
  543. inputText: `{
  544. "optgroup": {
  545. "optString": "inside a group",
  546. "optNested": {
  547. "optString": "nested message inside a group"
  548. },
  549. "optnestedgroup": {
  550. "optFixed32": 47
  551. }
  552. }
  553. }`,
  554. wantMessage: &pb2.Nests{
  555. Optgroup: &pb2.Nests_OptGroup{
  556. OptString: scalar.String("inside a group"),
  557. OptNested: &pb2.Nested{
  558. OptString: scalar.String("nested message inside a group"),
  559. },
  560. Optnestedgroup: &pb2.Nests_OptGroup_OptNestedGroup{
  561. OptFixed32: scalar.Uint32(47),
  562. },
  563. },
  564. },
  565. }, {
  566. desc: "proto3 nested message not set",
  567. inputMessage: &pb3.Nests{},
  568. inputText: "{}",
  569. wantMessage: &pb3.Nests{},
  570. }, {
  571. desc: "proto3 nested message set to null",
  572. inputMessage: &pb3.Nests{},
  573. inputText: `{"sNested": null}`,
  574. wantMessage: &pb3.Nests{},
  575. }, {
  576. desc: "proto3 nested message set to empty",
  577. inputMessage: &pb3.Nests{},
  578. inputText: `{"sNested": {}}`,
  579. wantMessage: &pb3.Nests{
  580. SNested: &pb3.Nested{},
  581. },
  582. }, {
  583. desc: "proto3 nested message",
  584. inputMessage: &pb3.Nests{},
  585. inputText: `{
  586. "sNested": {
  587. "sString": "nested message",
  588. "sNested": {
  589. "sString": "another nested message"
  590. }
  591. }
  592. }`,
  593. wantMessage: &pb3.Nests{
  594. SNested: &pb3.Nested{
  595. SString: "nested message",
  596. SNested: &pb3.Nested{
  597. SString: "another nested message",
  598. },
  599. },
  600. },
  601. }, {
  602. desc: "message set to non-message",
  603. inputMessage: &pb3.Nests{},
  604. inputText: `"not valid"`,
  605. wantErr: true,
  606. }, {
  607. desc: "nested message set to non-message",
  608. inputMessage: &pb3.Nests{},
  609. inputText: `{"sNested": true}`,
  610. wantErr: true,
  611. }, {
  612. desc: "oneof not set",
  613. inputMessage: &pb3.Oneofs{},
  614. inputText: "{}",
  615. wantMessage: &pb3.Oneofs{},
  616. }, {
  617. desc: "oneof set to empty string",
  618. inputMessage: &pb3.Oneofs{},
  619. inputText: `{"oneofString": ""}`,
  620. wantMessage: &pb3.Oneofs{
  621. Union: &pb3.Oneofs_OneofString{},
  622. },
  623. }, {
  624. desc: "oneof set to string",
  625. inputMessage: &pb3.Oneofs{},
  626. inputText: `{"oneofString": "hello"}`,
  627. wantMessage: &pb3.Oneofs{
  628. Union: &pb3.Oneofs_OneofString{
  629. OneofString: "hello",
  630. },
  631. },
  632. }, {
  633. desc: "oneof set to enum",
  634. inputMessage: &pb3.Oneofs{},
  635. inputText: `{"oneofEnum": "ZERO"}`,
  636. wantMessage: &pb3.Oneofs{
  637. Union: &pb3.Oneofs_OneofEnum{
  638. OneofEnum: pb3.Enum_ZERO,
  639. },
  640. },
  641. }, {
  642. desc: "oneof set to empty message",
  643. inputMessage: &pb3.Oneofs{},
  644. inputText: `{"oneofNested": {}}`,
  645. wantMessage: &pb3.Oneofs{
  646. Union: &pb3.Oneofs_OneofNested{
  647. OneofNested: &pb3.Nested{},
  648. },
  649. },
  650. }, {
  651. desc: "oneof set to message",
  652. inputMessage: &pb3.Oneofs{},
  653. inputText: `{
  654. "oneofNested": {
  655. "sString": "nested message"
  656. }
  657. }`,
  658. wantMessage: &pb3.Oneofs{
  659. Union: &pb3.Oneofs_OneofNested{
  660. OneofNested: &pb3.Nested{
  661. SString: "nested message",
  662. },
  663. },
  664. },
  665. }, {
  666. desc: "repeated null fields",
  667. inputMessage: &pb2.Repeats{},
  668. inputText: `{
  669. "rptString": null,
  670. "rptInt32" : null,
  671. "rptFloat" : null,
  672. "rptBytes" : null
  673. }`,
  674. wantMessage: &pb2.Repeats{},
  675. }, {
  676. desc: "repeated scalars",
  677. inputMessage: &pb2.Repeats{},
  678. inputText: `{
  679. "rptString": ["hello", "world"],
  680. "rptInt32" : [-1, 0, 1],
  681. "rptBool" : [false, true]
  682. }`,
  683. wantMessage: &pb2.Repeats{
  684. RptString: []string{"hello", "world"},
  685. RptInt32: []int32{-1, 0, 1},
  686. RptBool: []bool{false, true},
  687. },
  688. }, {
  689. desc: "repeated enums",
  690. inputMessage: &pb2.Enums{},
  691. inputText: `{
  692. "rptEnum" : ["TEN", 1, 42],
  693. "rptNestedEnum": ["DOS", 2, -47]
  694. }`,
  695. wantMessage: &pb2.Enums{
  696. RptEnum: []pb2.Enum{pb2.Enum_TEN, pb2.Enum_ONE, 42},
  697. RptNestedEnum: []pb2.Enums_NestedEnum{pb2.Enums_DOS, pb2.Enums_DOS, -47},
  698. },
  699. }, {
  700. desc: "repeated messages",
  701. inputMessage: &pb2.Nests{},
  702. inputText: `{
  703. "rptNested": [
  704. {
  705. "optString": "repeat nested one"
  706. },
  707. {
  708. "optString": "repeat nested two",
  709. "optNested": {
  710. "optString": "inside repeat nested two"
  711. }
  712. },
  713. {}
  714. ]
  715. }`,
  716. wantMessage: &pb2.Nests{
  717. RptNested: []*pb2.Nested{
  718. {
  719. OptString: scalar.String("repeat nested one"),
  720. },
  721. {
  722. OptString: scalar.String("repeat nested two"),
  723. OptNested: &pb2.Nested{
  724. OptString: scalar.String("inside repeat nested two"),
  725. },
  726. },
  727. {},
  728. },
  729. },
  730. }, {
  731. desc: "repeated groups",
  732. inputMessage: &pb2.Nests{},
  733. inputText: `{
  734. "rptgroup": [
  735. {
  736. "rptString": ["hello", "world"]
  737. },
  738. {}
  739. ]
  740. }
  741. `,
  742. wantMessage: &pb2.Nests{
  743. Rptgroup: []*pb2.Nests_RptGroup{
  744. {
  745. RptString: []string{"hello", "world"},
  746. },
  747. {},
  748. },
  749. },
  750. }, {
  751. desc: "repeated scalars containing invalid type",
  752. inputMessage: &pb2.Repeats{},
  753. inputText: `{"rptString": ["hello", null, "world"]}`,
  754. wantErr: true,
  755. }, {
  756. desc: "repeated messages containing invalid type",
  757. inputMessage: &pb2.Nests{},
  758. inputText: `{"rptNested": [{}, null]}`,
  759. wantErr: true,
  760. }, {
  761. desc: "map fields 1",
  762. inputMessage: &pb3.Maps{},
  763. inputText: `{
  764. "int32ToStr": {
  765. "-101": "-101",
  766. "0" : "zero",
  767. "255" : "0xff"
  768. },
  769. "boolToUint32": {
  770. "false": 101,
  771. "true" : "42"
  772. }
  773. }`,
  774. wantMessage: &pb3.Maps{
  775. Int32ToStr: map[int32]string{
  776. -101: "-101",
  777. 0xff: "0xff",
  778. 0: "zero",
  779. },
  780. BoolToUint32: map[bool]uint32{
  781. true: 42,
  782. false: 101,
  783. },
  784. },
  785. }, {
  786. desc: "map fields 2",
  787. inputMessage: &pb3.Maps{},
  788. inputText: `{
  789. "uint64ToEnum": {
  790. "1" : "ONE",
  791. "2" : 2,
  792. "10": 101
  793. }
  794. }`,
  795. wantMessage: &pb3.Maps{
  796. Uint64ToEnum: map[uint64]pb3.Enum{
  797. 1: pb3.Enum_ONE,
  798. 2: pb3.Enum_TWO,
  799. 10: 101,
  800. },
  801. },
  802. }, {
  803. desc: "map fields 3",
  804. inputMessage: &pb3.Maps{},
  805. inputText: `{
  806. "strToNested": {
  807. "nested_one": {
  808. "sString": "nested in a map"
  809. },
  810. "nested_two": {}
  811. }
  812. }`,
  813. wantMessage: &pb3.Maps{
  814. StrToNested: map[string]*pb3.Nested{
  815. "nested_one": {
  816. SString: "nested in a map",
  817. },
  818. "nested_two": {},
  819. },
  820. },
  821. }, {
  822. desc: "map fields 4",
  823. inputMessage: &pb3.Maps{},
  824. inputText: `{
  825. "strToOneofs": {
  826. "nested": {
  827. "oneofNested": {
  828. "sString": "nested oneof in map field value"
  829. }
  830. },
  831. "string": {
  832. "oneofString": "hello"
  833. }
  834. }
  835. }`,
  836. wantMessage: &pb3.Maps{
  837. StrToOneofs: map[string]*pb3.Oneofs{
  838. "string": {
  839. Union: &pb3.Oneofs_OneofString{
  840. OneofString: "hello",
  841. },
  842. },
  843. "nested": {
  844. Union: &pb3.Oneofs_OneofNested{
  845. OneofNested: &pb3.Nested{
  846. SString: "nested oneof in map field value",
  847. },
  848. },
  849. },
  850. },
  851. },
  852. }, {
  853. desc: "map contains duplicate keys",
  854. inputMessage: &pb3.Maps{},
  855. inputText: `{
  856. "int32ToStr": {
  857. "0": "cero",
  858. "0": "zero"
  859. }
  860. }
  861. `,
  862. wantErr: true,
  863. }, {
  864. desc: "map key empty string",
  865. inputMessage: &pb3.Maps{},
  866. inputText: `{
  867. "strToNested": {
  868. "": {}
  869. }
  870. }`,
  871. wantMessage: &pb3.Maps{
  872. StrToNested: map[string]*pb3.Nested{
  873. "": {},
  874. },
  875. },
  876. }, {
  877. desc: "map contains invalid key 1",
  878. inputMessage: &pb3.Maps{},
  879. inputText: `{
  880. "int32ToStr": {
  881. "invalid": "cero"
  882. }`,
  883. wantErr: true,
  884. }, {
  885. desc: "map contains invalid key 2",
  886. inputMessage: &pb3.Maps{},
  887. inputText: `{
  888. "int32ToStr": {
  889. "1.02": "float"
  890. }`,
  891. wantErr: true,
  892. }, {
  893. desc: "map contains invalid key 3",
  894. inputMessage: &pb3.Maps{},
  895. inputText: `{
  896. "int32ToStr": {
  897. "2147483648": "exceeds 32-bit integer max limit"
  898. }`,
  899. wantErr: true,
  900. }, {
  901. desc: "map contains invalid key 4",
  902. inputMessage: &pb3.Maps{},
  903. inputText: `{
  904. "uint64ToEnum": {
  905. "-1": 0
  906. }
  907. }`,
  908. wantErr: true,
  909. }, {
  910. desc: "map contains invalid value",
  911. inputMessage: &pb3.Maps{},
  912. inputText: `{
  913. "int32ToStr": {
  914. "101": true
  915. }`,
  916. wantErr: true,
  917. }, {
  918. desc: "map contains null for scalar value",
  919. inputMessage: &pb3.Maps{},
  920. inputText: `{
  921. "int32ToStr": {
  922. "101": null
  923. }`,
  924. wantErr: true,
  925. }, {
  926. desc: "map contains null for message value",
  927. inputMessage: &pb3.Maps{},
  928. inputText: `{
  929. "strToNested": {
  930. "hello": null
  931. }
  932. }`,
  933. wantErr: true,
  934. }, {
  935. desc: "extensions of non-repeated fields",
  936. inputMessage: &pb2.Extensions{},
  937. inputText: `{
  938. "optString": "non-extension field",
  939. "optBool": true,
  940. "optInt32": 42,
  941. "[pb2.opt_ext_bool]": true,
  942. "[pb2.opt_ext_nested]": {
  943. "optString": "nested in an extension",
  944. "opt_nested": {
  945. "opt_string": "another nested in an extension"
  946. }
  947. },
  948. "[pb2.opt_ext_string]": "extension field",
  949. "[pb2.opt_ext_enum]": "TEN"
  950. }`,
  951. wantMessage: func() proto.Message {
  952. m := &pb2.Extensions{
  953. OptString: scalar.String("non-extension field"),
  954. OptBool: scalar.Bool(true),
  955. OptInt32: scalar.Int32(42),
  956. }
  957. setExtension(m, pb2.E_OptExtBool, true)
  958. setExtension(m, pb2.E_OptExtString, "extension field")
  959. setExtension(m, pb2.E_OptExtEnum, pb2.Enum_TEN)
  960. setExtension(m, pb2.E_OptExtNested, &pb2.Nested{
  961. OptString: scalar.String("nested in an extension"),
  962. OptNested: &pb2.Nested{
  963. OptString: scalar.String("another nested in an extension"),
  964. },
  965. })
  966. return m
  967. }(),
  968. }, {
  969. desc: "extensions of repeated fields",
  970. inputMessage: &pb2.Extensions{},
  971. inputText: `{
  972. "[pb2.rpt_ext_enum]": ["TEN", 101, "ONE"],
  973. "[pb2.rpt_ext_fixed32]": [42, 47],
  974. "[pb2.rpt_ext_nested]": [
  975. {"optString": "one"},
  976. {"optString": "two"},
  977. {"optString": "three"}
  978. ]
  979. }`,
  980. wantMessage: func() proto.Message {
  981. m := &pb2.Extensions{}
  982. setExtension(m, pb2.E_RptExtEnum, &[]pb2.Enum{pb2.Enum_TEN, 101, pb2.Enum_ONE})
  983. setExtension(m, pb2.E_RptExtFixed32, &[]uint32{42, 47})
  984. setExtension(m, pb2.E_RptExtNested, &[]*pb2.Nested{
  985. &pb2.Nested{OptString: scalar.String("one")},
  986. &pb2.Nested{OptString: scalar.String("two")},
  987. &pb2.Nested{OptString: scalar.String("three")},
  988. })
  989. return m
  990. }(),
  991. }, {
  992. desc: "extensions of non-repeated fields in another message",
  993. inputMessage: &pb2.Extensions{},
  994. inputText: `{
  995. "[pb2.ExtensionsContainer.opt_ext_bool]": true,
  996. "[pb2.ExtensionsContainer.opt_ext_enum]": "TEN",
  997. "[pb2.ExtensionsContainer.opt_ext_nested]": {
  998. "optString": "nested in an extension",
  999. "optNested": {
  1000. "optString": "another nested in an extension"
  1001. }
  1002. },
  1003. "[pb2.ExtensionsContainer.opt_ext_string]": "extension field"
  1004. }`,
  1005. wantMessage: func() proto.Message {
  1006. m := &pb2.Extensions{}
  1007. setExtension(m, pb2.E_ExtensionsContainer_OptExtBool, true)
  1008. setExtension(m, pb2.E_ExtensionsContainer_OptExtString, "extension field")
  1009. setExtension(m, pb2.E_ExtensionsContainer_OptExtEnum, pb2.Enum_TEN)
  1010. setExtension(m, pb2.E_ExtensionsContainer_OptExtNested, &pb2.Nested{
  1011. OptString: scalar.String("nested in an extension"),
  1012. OptNested: &pb2.Nested{
  1013. OptString: scalar.String("another nested in an extension"),
  1014. },
  1015. })
  1016. return m
  1017. }(),
  1018. }, {
  1019. desc: "extensions of repeated fields in another message",
  1020. inputMessage: &pb2.Extensions{},
  1021. inputText: `{
  1022. "optString": "non-extension field",
  1023. "optBool": true,
  1024. "optInt32": 42,
  1025. "[pb2.ExtensionsContainer.rpt_ext_nested]": [
  1026. {"optString": "one"},
  1027. {"optString": "two"},
  1028. {"optString": "three"}
  1029. ],
  1030. "[pb2.ExtensionsContainer.rpt_ext_enum]": ["TEN", 101, "ONE"],
  1031. "[pb2.ExtensionsContainer.rpt_ext_string]": ["hello", "world"]
  1032. }`,
  1033. wantMessage: func() proto.Message {
  1034. m := &pb2.Extensions{
  1035. OptString: scalar.String("non-extension field"),
  1036. OptBool: scalar.Bool(true),
  1037. OptInt32: scalar.Int32(42),
  1038. }
  1039. setExtension(m, pb2.E_ExtensionsContainer_RptExtEnum, &[]pb2.Enum{pb2.Enum_TEN, 101, pb2.Enum_ONE})
  1040. setExtension(m, pb2.E_ExtensionsContainer_RptExtString, &[]string{"hello", "world"})
  1041. setExtension(m, pb2.E_ExtensionsContainer_RptExtNested, &[]*pb2.Nested{
  1042. &pb2.Nested{OptString: scalar.String("one")},
  1043. &pb2.Nested{OptString: scalar.String("two")},
  1044. &pb2.Nested{OptString: scalar.String("three")},
  1045. })
  1046. return m
  1047. }(),
  1048. }, {
  1049. desc: "invalid extension field name",
  1050. inputMessage: &pb2.Extensions{},
  1051. inputText: `{ "[pb2.invalid_message_field]": true }`,
  1052. wantErr: true,
  1053. }, {
  1054. desc: "MessageSet",
  1055. inputMessage: &pb2.MessageSet{},
  1056. inputText: `{
  1057. "[pb2.MessageSetExtension]": {
  1058. "optString": "a messageset extension"
  1059. },
  1060. "[pb2.MessageSetExtension.ext_nested]": {
  1061. "optString": "just a regular extension"
  1062. },
  1063. "[pb2.MessageSetExtension.not_message_set_extension]": {
  1064. "optString": "not a messageset extension"
  1065. }
  1066. }`,
  1067. wantMessage: func() proto.Message {
  1068. m := &pb2.MessageSet{}
  1069. setExtension(m, pb2.E_MessageSetExtension_MessageSetExtension, &pb2.MessageSetExtension{
  1070. OptString: scalar.String("a messageset extension"),
  1071. })
  1072. setExtension(m, pb2.E_MessageSetExtension_NotMessageSetExtension, &pb2.MessageSetExtension{
  1073. OptString: scalar.String("not a messageset extension"),
  1074. })
  1075. setExtension(m, pb2.E_MessageSetExtension_ExtNested, &pb2.Nested{
  1076. OptString: scalar.String("just a regular extension"),
  1077. })
  1078. return m
  1079. }(),
  1080. }, {
  1081. desc: "extension field set to null",
  1082. inputMessage: &pb2.Extensions{},
  1083. inputText: `{
  1084. "[pb2.ExtensionsContainer.opt_ext_bool]": null,
  1085. "[pb2.ExtensionsContainer.opt_ext_nested]": null
  1086. }`,
  1087. wantMessage: func() proto.Message {
  1088. m := &pb2.Extensions{}
  1089. setExtension(m, pb2.E_ExtensionsContainer_OptExtBool, nil)
  1090. setExtension(m, pb2.E_ExtensionsContainer_OptExtNested, nil)
  1091. return m
  1092. }(),
  1093. }, {
  1094. desc: "extensions of repeated field contains null",
  1095. inputMessage: &pb2.Extensions{},
  1096. inputText: `{
  1097. "[pb2.ExtensionsContainer.rpt_ext_nested]": [
  1098. {"optString": "one"},
  1099. null,
  1100. {"optString": "three"}
  1101. ],
  1102. }`,
  1103. wantErr: true,
  1104. }, {
  1105. desc: "not real MessageSet 1",
  1106. inputMessage: &pb2.FakeMessageSet{},
  1107. inputText: `{
  1108. "[pb2.FakeMessageSetExtension.message_set_extension]": {
  1109. "optString": "not a messageset extension"
  1110. }
  1111. }`,
  1112. wantMessage: func() proto.Message {
  1113. m := &pb2.FakeMessageSet{}
  1114. setExtension(m, pb2.E_FakeMessageSetExtension_MessageSetExtension, &pb2.FakeMessageSetExtension{
  1115. OptString: scalar.String("not a messageset extension"),
  1116. })
  1117. return m
  1118. }(),
  1119. }, {
  1120. desc: "not real MessageSet 2",
  1121. inputMessage: &pb2.FakeMessageSet{},
  1122. inputText: `{
  1123. "[pb2.FakeMessageSetExtension]": {
  1124. "optString": "not a messageset extension"
  1125. }
  1126. }`,
  1127. wantErr: true,
  1128. }, {
  1129. desc: "not real MessageSet 3",
  1130. inputMessage: &pb2.MessageSet{},
  1131. inputText: `{
  1132. "[pb2.message_set_extension]": {
  1133. "optString": "another not a messageset extension"
  1134. }
  1135. }`,
  1136. wantMessage: func() proto.Message {
  1137. m := &pb2.MessageSet{}
  1138. setExtension(m, pb2.E_MessageSetExtension, &pb2.FakeMessageSetExtension{
  1139. OptString: scalar.String("another not a messageset extension"),
  1140. })
  1141. return m
  1142. }(),
  1143. }}
  1144. for _, tt := range tests {
  1145. tt := tt
  1146. t.Run(tt.desc, func(t *testing.T) {
  1147. err := tt.umo.Unmarshal(tt.inputMessage, []byte(tt.inputText))
  1148. if err != nil && !tt.wantErr {
  1149. t.Errorf("Unmarshal() returned error: %v\n\n", err)
  1150. }
  1151. if err == nil && tt.wantErr {
  1152. t.Error("Unmarshal() got nil error, want error\n\n")
  1153. }
  1154. if tt.wantMessage != nil && !protoV1.Equal(tt.inputMessage.(protoV1.Message), tt.wantMessage.(protoV1.Message)) {
  1155. t.Errorf("Unmarshal()\n<got>\n%v\n<want>\n%v\n", tt.inputMessage, tt.wantMessage)
  1156. }
  1157. })
  1158. }
  1159. }