encode_test.go 52 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248
  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 protojson_test
  5. import (
  6. "bytes"
  7. "math"
  8. "testing"
  9. "github.com/google/go-cmp/cmp"
  10. "google.golang.org/protobuf/encoding/protojson"
  11. "google.golang.org/protobuf/internal/detrand"
  12. "google.golang.org/protobuf/internal/encoding/pack"
  13. "google.golang.org/protobuf/internal/flags"
  14. pimpl "google.golang.org/protobuf/internal/impl"
  15. "google.golang.org/protobuf/proto"
  16. preg "google.golang.org/protobuf/reflect/protoregistry"
  17. "google.golang.org/protobuf/encoding/testprotos/pb2"
  18. "google.golang.org/protobuf/encoding/testprotos/pb3"
  19. "google.golang.org/protobuf/types/known/anypb"
  20. "google.golang.org/protobuf/types/known/durationpb"
  21. "google.golang.org/protobuf/types/known/emptypb"
  22. "google.golang.org/protobuf/types/known/fieldmaskpb"
  23. "google.golang.org/protobuf/types/known/structpb"
  24. "google.golang.org/protobuf/types/known/timestamppb"
  25. "google.golang.org/protobuf/types/known/wrapperspb"
  26. )
  27. // Disable detrand to enable direct comparisons on outputs.
  28. func init() { detrand.Disable() }
  29. func TestMarshal(t *testing.T) {
  30. tests := []struct {
  31. desc string
  32. mo protojson.MarshalOptions
  33. input proto.Message
  34. want string
  35. wantErr bool // TODO: Verify error message substring.
  36. skip bool
  37. }{{
  38. desc: "proto2 optional scalars not set",
  39. input: &pb2.Scalars{},
  40. want: "{}",
  41. }, {
  42. desc: "proto3 scalars not set",
  43. input: &pb3.Scalars{},
  44. want: "{}",
  45. }, {
  46. desc: "proto2 optional scalars set to zero values",
  47. input: &pb2.Scalars{
  48. OptBool: proto.Bool(false),
  49. OptInt32: proto.Int32(0),
  50. OptInt64: proto.Int64(0),
  51. OptUint32: proto.Uint32(0),
  52. OptUint64: proto.Uint64(0),
  53. OptSint32: proto.Int32(0),
  54. OptSint64: proto.Int64(0),
  55. OptFixed32: proto.Uint32(0),
  56. OptFixed64: proto.Uint64(0),
  57. OptSfixed32: proto.Int32(0),
  58. OptSfixed64: proto.Int64(0),
  59. OptFloat: proto.Float32(0),
  60. OptDouble: proto.Float64(0),
  61. OptBytes: []byte{},
  62. OptString: proto.String(""),
  63. },
  64. want: `{
  65. "optBool": false,
  66. "optInt32": 0,
  67. "optInt64": "0",
  68. "optUint32": 0,
  69. "optUint64": "0",
  70. "optSint32": 0,
  71. "optSint64": "0",
  72. "optFixed32": 0,
  73. "optFixed64": "0",
  74. "optSfixed32": 0,
  75. "optSfixed64": "0",
  76. "optFloat": 0,
  77. "optDouble": 0,
  78. "optBytes": "",
  79. "optString": ""
  80. }`,
  81. }, {
  82. desc: "proto2 optional scalars set to some values",
  83. input: &pb2.Scalars{
  84. OptBool: proto.Bool(true),
  85. OptInt32: proto.Int32(0xff),
  86. OptInt64: proto.Int64(0xdeadbeef),
  87. OptUint32: proto.Uint32(47),
  88. OptUint64: proto.Uint64(0xdeadbeef),
  89. OptSint32: proto.Int32(-1001),
  90. OptSint64: proto.Int64(-0xffff),
  91. OptFixed64: proto.Uint64(64),
  92. OptSfixed32: proto.Int32(-32),
  93. OptFloat: proto.Float32(1.02),
  94. OptDouble: proto.Float64(1.234),
  95. OptBytes: []byte("谷歌"),
  96. OptString: proto.String("谷歌"),
  97. },
  98. want: `{
  99. "optBool": true,
  100. "optInt32": 255,
  101. "optInt64": "3735928559",
  102. "optUint32": 47,
  103. "optUint64": "3735928559",
  104. "optSint32": -1001,
  105. "optSint64": "-65535",
  106. "optFixed64": "64",
  107. "optSfixed32": -32,
  108. "optFloat": 1.02,
  109. "optDouble": 1.234,
  110. "optBytes": "6LC35q2M",
  111. "optString": "谷歌"
  112. }`,
  113. }, {
  114. desc: "string",
  115. input: &pb3.Scalars{
  116. SString: "谷歌",
  117. },
  118. want: `{
  119. "sString": "谷歌"
  120. }`,
  121. }, {
  122. desc: "string with invalid UTF8",
  123. input: &pb3.Scalars{
  124. SString: "abc\xff",
  125. },
  126. wantErr: true,
  127. }, {
  128. desc: "float nan",
  129. input: &pb3.Scalars{
  130. SFloat: float32(math.NaN()),
  131. },
  132. want: `{
  133. "sFloat": "NaN"
  134. }`,
  135. }, {
  136. desc: "float positive infinity",
  137. input: &pb3.Scalars{
  138. SFloat: float32(math.Inf(1)),
  139. },
  140. want: `{
  141. "sFloat": "Infinity"
  142. }`,
  143. }, {
  144. desc: "float negative infinity",
  145. input: &pb3.Scalars{
  146. SFloat: float32(math.Inf(-1)),
  147. },
  148. want: `{
  149. "sFloat": "-Infinity"
  150. }`,
  151. }, {
  152. desc: "double nan",
  153. input: &pb3.Scalars{
  154. SDouble: math.NaN(),
  155. },
  156. want: `{
  157. "sDouble": "NaN"
  158. }`,
  159. }, {
  160. desc: "double positive infinity",
  161. input: &pb3.Scalars{
  162. SDouble: math.Inf(1),
  163. },
  164. want: `{
  165. "sDouble": "Infinity"
  166. }`,
  167. }, {
  168. desc: "double negative infinity",
  169. input: &pb3.Scalars{
  170. SDouble: math.Inf(-1),
  171. },
  172. want: `{
  173. "sDouble": "-Infinity"
  174. }`,
  175. }, {
  176. desc: "proto2 enum not set",
  177. input: &pb2.Enums{},
  178. want: "{}",
  179. }, {
  180. desc: "proto2 enum set to zero value",
  181. input: &pb2.Enums{
  182. OptEnum: pb2.Enum(0).Enum(),
  183. OptNestedEnum: pb2.Enums_NestedEnum(0).Enum(),
  184. },
  185. want: `{
  186. "optEnum": 0,
  187. "optNestedEnum": 0
  188. }`,
  189. }, {
  190. desc: "proto2 enum",
  191. input: &pb2.Enums{
  192. OptEnum: pb2.Enum_ONE.Enum(),
  193. OptNestedEnum: pb2.Enums_UNO.Enum(),
  194. },
  195. want: `{
  196. "optEnum": "ONE",
  197. "optNestedEnum": "UNO"
  198. }`,
  199. }, {
  200. desc: "proto2 enum set to numeric values",
  201. input: &pb2.Enums{
  202. OptEnum: pb2.Enum(2).Enum(),
  203. OptNestedEnum: pb2.Enums_NestedEnum(2).Enum(),
  204. },
  205. want: `{
  206. "optEnum": "TWO",
  207. "optNestedEnum": "DOS"
  208. }`,
  209. }, {
  210. desc: "proto2 enum set to unnamed numeric values",
  211. input: &pb2.Enums{
  212. OptEnum: pb2.Enum(101).Enum(),
  213. OptNestedEnum: pb2.Enums_NestedEnum(-101).Enum(),
  214. },
  215. want: `{
  216. "optEnum": 101,
  217. "optNestedEnum": -101
  218. }`,
  219. }, {
  220. desc: "proto3 enum not set",
  221. input: &pb3.Enums{},
  222. want: "{}",
  223. }, {
  224. desc: "proto3 enum set to zero value",
  225. input: &pb3.Enums{
  226. SEnum: pb3.Enum_ZERO,
  227. SNestedEnum: pb3.Enums_CERO,
  228. },
  229. want: "{}",
  230. }, {
  231. desc: "proto3 enum",
  232. input: &pb3.Enums{
  233. SEnum: pb3.Enum_ONE,
  234. SNestedEnum: pb3.Enums_UNO,
  235. },
  236. want: `{
  237. "sEnum": "ONE",
  238. "sNestedEnum": "UNO"
  239. }`,
  240. }, {
  241. desc: "proto3 enum set to numeric values",
  242. input: &pb3.Enums{
  243. SEnum: 2,
  244. SNestedEnum: 2,
  245. },
  246. want: `{
  247. "sEnum": "TWO",
  248. "sNestedEnum": "DOS"
  249. }`,
  250. }, {
  251. desc: "proto3 enum set to unnamed numeric values",
  252. input: &pb3.Enums{
  253. SEnum: -47,
  254. SNestedEnum: 47,
  255. },
  256. want: `{
  257. "sEnum": -47,
  258. "sNestedEnum": 47
  259. }`,
  260. }, {
  261. desc: "proto2 nested message not set",
  262. input: &pb2.Nests{},
  263. want: "{}",
  264. }, {
  265. desc: "proto2 nested message set to empty",
  266. input: &pb2.Nests{
  267. OptNested: &pb2.Nested{},
  268. Optgroup: &pb2.Nests_OptGroup{},
  269. },
  270. want: `{
  271. "optNested": {},
  272. "optgroup": {}
  273. }`,
  274. }, {
  275. desc: "proto2 nested messages",
  276. input: &pb2.Nests{
  277. OptNested: &pb2.Nested{
  278. OptString: proto.String("nested message"),
  279. OptNested: &pb2.Nested{
  280. OptString: proto.String("another nested message"),
  281. },
  282. },
  283. },
  284. want: `{
  285. "optNested": {
  286. "optString": "nested message",
  287. "optNested": {
  288. "optString": "another nested message"
  289. }
  290. }
  291. }`,
  292. }, {
  293. desc: "proto2 groups",
  294. input: &pb2.Nests{
  295. Optgroup: &pb2.Nests_OptGroup{
  296. OptString: proto.String("inside a group"),
  297. OptNested: &pb2.Nested{
  298. OptString: proto.String("nested message inside a group"),
  299. },
  300. Optnestedgroup: &pb2.Nests_OptGroup_OptNestedGroup{
  301. OptFixed32: proto.Uint32(47),
  302. },
  303. },
  304. },
  305. want: `{
  306. "optgroup": {
  307. "optString": "inside a group",
  308. "optNested": {
  309. "optString": "nested message inside a group"
  310. },
  311. "optnestedgroup": {
  312. "optFixed32": 47
  313. }
  314. }
  315. }`,
  316. }, {
  317. desc: "proto3 nested message not set",
  318. input: &pb3.Nests{},
  319. want: "{}",
  320. }, {
  321. desc: "proto3 nested message set to empty",
  322. input: &pb3.Nests{
  323. SNested: &pb3.Nested{},
  324. },
  325. want: `{
  326. "sNested": {}
  327. }`,
  328. }, {
  329. desc: "proto3 nested message",
  330. input: &pb3.Nests{
  331. SNested: &pb3.Nested{
  332. SString: "nested message",
  333. SNested: &pb3.Nested{
  334. SString: "another nested message",
  335. },
  336. },
  337. },
  338. want: `{
  339. "sNested": {
  340. "sString": "nested message",
  341. "sNested": {
  342. "sString": "another nested message"
  343. }
  344. }
  345. }`,
  346. }, {
  347. desc: "oneof not set",
  348. input: &pb3.Oneofs{},
  349. want: "{}",
  350. }, {
  351. desc: "oneof set to empty string",
  352. input: &pb3.Oneofs{
  353. Union: &pb3.Oneofs_OneofString{},
  354. },
  355. want: `{
  356. "oneofString": ""
  357. }`,
  358. }, {
  359. desc: "oneof set to string",
  360. input: &pb3.Oneofs{
  361. Union: &pb3.Oneofs_OneofString{
  362. OneofString: "hello",
  363. },
  364. },
  365. want: `{
  366. "oneofString": "hello"
  367. }`,
  368. }, {
  369. desc: "oneof set to enum",
  370. input: &pb3.Oneofs{
  371. Union: &pb3.Oneofs_OneofEnum{
  372. OneofEnum: pb3.Enum_ZERO,
  373. },
  374. },
  375. want: `{
  376. "oneofEnum": "ZERO"
  377. }`,
  378. }, {
  379. desc: "oneof set to empty message",
  380. input: &pb3.Oneofs{
  381. Union: &pb3.Oneofs_OneofNested{
  382. OneofNested: &pb3.Nested{},
  383. },
  384. },
  385. want: `{
  386. "oneofNested": {}
  387. }`,
  388. }, {
  389. desc: "oneof set to message",
  390. input: &pb3.Oneofs{
  391. Union: &pb3.Oneofs_OneofNested{
  392. OneofNested: &pb3.Nested{
  393. SString: "nested message",
  394. },
  395. },
  396. },
  397. want: `{
  398. "oneofNested": {
  399. "sString": "nested message"
  400. }
  401. }`,
  402. }, {
  403. desc: "repeated fields not set",
  404. input: &pb2.Repeats{},
  405. want: "{}",
  406. }, {
  407. desc: "repeated fields set to empty slices",
  408. input: &pb2.Repeats{
  409. RptBool: []bool{},
  410. RptInt32: []int32{},
  411. RptInt64: []int64{},
  412. RptUint32: []uint32{},
  413. RptUint64: []uint64{},
  414. RptFloat: []float32{},
  415. RptDouble: []float64{},
  416. RptBytes: [][]byte{},
  417. },
  418. want: "{}",
  419. }, {
  420. desc: "repeated fields set to some values",
  421. input: &pb2.Repeats{
  422. RptBool: []bool{true, false, true, true},
  423. RptInt32: []int32{1, 6, 0, 0},
  424. RptInt64: []int64{-64, 47},
  425. RptUint32: []uint32{0xff, 0xffff},
  426. RptUint64: []uint64{0xdeadbeef},
  427. RptFloat: []float32{float32(math.NaN()), float32(math.Inf(1)), float32(math.Inf(-1)), 1.034},
  428. RptDouble: []float64{math.NaN(), math.Inf(1), math.Inf(-1), 1.23e-308},
  429. RptString: []string{"hello", "世界"},
  430. RptBytes: [][]byte{
  431. []byte("hello"),
  432. []byte("\xe4\xb8\x96\xe7\x95\x8c"),
  433. },
  434. },
  435. want: `{
  436. "rptBool": [
  437. true,
  438. false,
  439. true,
  440. true
  441. ],
  442. "rptInt32": [
  443. 1,
  444. 6,
  445. 0,
  446. 0
  447. ],
  448. "rptInt64": [
  449. "-64",
  450. "47"
  451. ],
  452. "rptUint32": [
  453. 255,
  454. 65535
  455. ],
  456. "rptUint64": [
  457. "3735928559"
  458. ],
  459. "rptFloat": [
  460. "NaN",
  461. "Infinity",
  462. "-Infinity",
  463. 1.034
  464. ],
  465. "rptDouble": [
  466. "NaN",
  467. "Infinity",
  468. "-Infinity",
  469. 1.23e-308
  470. ],
  471. "rptString": [
  472. "hello",
  473. "世界"
  474. ],
  475. "rptBytes": [
  476. "aGVsbG8=",
  477. "5LiW55WM"
  478. ]
  479. }`,
  480. }, {
  481. desc: "repeated enums",
  482. input: &pb2.Enums{
  483. RptEnum: []pb2.Enum{pb2.Enum_ONE, 2, pb2.Enum_TEN, 42},
  484. RptNestedEnum: []pb2.Enums_NestedEnum{2, 47, 10},
  485. },
  486. want: `{
  487. "rptEnum": [
  488. "ONE",
  489. "TWO",
  490. "TEN",
  491. 42
  492. ],
  493. "rptNestedEnum": [
  494. "DOS",
  495. 47,
  496. "DIEZ"
  497. ]
  498. }`,
  499. }, {
  500. desc: "repeated messages set to empty",
  501. input: &pb2.Nests{
  502. RptNested: []*pb2.Nested{},
  503. Rptgroup: []*pb2.Nests_RptGroup{},
  504. },
  505. want: "{}",
  506. }, {
  507. desc: "repeated messages",
  508. input: &pb2.Nests{
  509. RptNested: []*pb2.Nested{
  510. {
  511. OptString: proto.String("repeat nested one"),
  512. },
  513. {
  514. OptString: proto.String("repeat nested two"),
  515. OptNested: &pb2.Nested{
  516. OptString: proto.String("inside repeat nested two"),
  517. },
  518. },
  519. {},
  520. },
  521. },
  522. want: `{
  523. "rptNested": [
  524. {
  525. "optString": "repeat nested one"
  526. },
  527. {
  528. "optString": "repeat nested two",
  529. "optNested": {
  530. "optString": "inside repeat nested two"
  531. }
  532. },
  533. {}
  534. ]
  535. }`,
  536. }, {
  537. desc: "repeated messages contains nil value",
  538. input: &pb2.Nests{
  539. RptNested: []*pb2.Nested{nil, {}},
  540. },
  541. want: `{
  542. "rptNested": [
  543. {},
  544. {}
  545. ]
  546. }`,
  547. }, {
  548. desc: "repeated groups",
  549. input: &pb2.Nests{
  550. Rptgroup: []*pb2.Nests_RptGroup{
  551. {
  552. RptString: []string{"hello", "world"},
  553. },
  554. {},
  555. nil,
  556. },
  557. },
  558. want: `{
  559. "rptgroup": [
  560. {
  561. "rptString": [
  562. "hello",
  563. "world"
  564. ]
  565. },
  566. {},
  567. {}
  568. ]
  569. }`,
  570. }, {
  571. desc: "map fields not set",
  572. input: &pb3.Maps{},
  573. want: "{}",
  574. }, {
  575. desc: "map fields set to empty",
  576. input: &pb3.Maps{
  577. Int32ToStr: map[int32]string{},
  578. BoolToUint32: map[bool]uint32{},
  579. Uint64ToEnum: map[uint64]pb3.Enum{},
  580. StrToNested: map[string]*pb3.Nested{},
  581. StrToOneofs: map[string]*pb3.Oneofs{},
  582. },
  583. want: "{}",
  584. }, {
  585. desc: "map fields 1",
  586. input: &pb3.Maps{
  587. BoolToUint32: map[bool]uint32{
  588. true: 42,
  589. false: 101,
  590. },
  591. },
  592. want: `{
  593. "boolToUint32": {
  594. "false": 101,
  595. "true": 42
  596. }
  597. }`,
  598. }, {
  599. desc: "map fields 2",
  600. input: &pb3.Maps{
  601. Int32ToStr: map[int32]string{
  602. -101: "-101",
  603. 0xff: "0xff",
  604. 0: "zero",
  605. },
  606. },
  607. want: `{
  608. "int32ToStr": {
  609. "-101": "-101",
  610. "0": "zero",
  611. "255": "0xff"
  612. }
  613. }`,
  614. }, {
  615. desc: "map fields 3",
  616. input: &pb3.Maps{
  617. Uint64ToEnum: map[uint64]pb3.Enum{
  618. 1: pb3.Enum_ONE,
  619. 2: pb3.Enum_TWO,
  620. 10: pb3.Enum_TEN,
  621. 47: 47,
  622. },
  623. },
  624. want: `{
  625. "uint64ToEnum": {
  626. "1": "ONE",
  627. "2": "TWO",
  628. "10": "TEN",
  629. "47": 47
  630. }
  631. }`,
  632. }, {
  633. desc: "map fields 4",
  634. input: &pb3.Maps{
  635. StrToNested: map[string]*pb3.Nested{
  636. "nested": &pb3.Nested{
  637. SString: "nested in a map",
  638. },
  639. },
  640. },
  641. want: `{
  642. "strToNested": {
  643. "nested": {
  644. "sString": "nested in a map"
  645. }
  646. }
  647. }`,
  648. }, {
  649. desc: "map fields 5",
  650. input: &pb3.Maps{
  651. StrToOneofs: map[string]*pb3.Oneofs{
  652. "string": &pb3.Oneofs{
  653. Union: &pb3.Oneofs_OneofString{
  654. OneofString: "hello",
  655. },
  656. },
  657. "nested": &pb3.Oneofs{
  658. Union: &pb3.Oneofs_OneofNested{
  659. OneofNested: &pb3.Nested{
  660. SString: "nested oneof in map field value",
  661. },
  662. },
  663. },
  664. },
  665. },
  666. want: `{
  667. "strToOneofs": {
  668. "nested": {
  669. "oneofNested": {
  670. "sString": "nested oneof in map field value"
  671. }
  672. },
  673. "string": {
  674. "oneofString": "hello"
  675. }
  676. }
  677. }`,
  678. }, {
  679. desc: "map field contains nil value",
  680. input: &pb3.Maps{
  681. StrToNested: map[string]*pb3.Nested{
  682. "nil": nil,
  683. },
  684. },
  685. want: `{
  686. "strToNested": {
  687. "nil": {}
  688. }
  689. }`,
  690. }, {
  691. desc: "required fields not set",
  692. input: &pb2.Requireds{},
  693. want: `{}`,
  694. wantErr: true,
  695. }, {
  696. desc: "required fields partially set",
  697. input: &pb2.Requireds{
  698. ReqBool: proto.Bool(false),
  699. ReqSfixed64: proto.Int64(0),
  700. ReqDouble: proto.Float64(1.23),
  701. ReqString: proto.String("hello"),
  702. ReqEnum: pb2.Enum_ONE.Enum(),
  703. },
  704. want: `{
  705. "reqBool": false,
  706. "reqSfixed64": "0",
  707. "reqDouble": 1.23,
  708. "reqString": "hello",
  709. "reqEnum": "ONE"
  710. }`,
  711. wantErr: true,
  712. }, {
  713. desc: "required fields not set with AllowPartial",
  714. mo: protojson.MarshalOptions{AllowPartial: true},
  715. input: &pb2.Requireds{
  716. ReqBool: proto.Bool(false),
  717. ReqSfixed64: proto.Int64(0),
  718. ReqDouble: proto.Float64(1.23),
  719. ReqString: proto.String("hello"),
  720. ReqEnum: pb2.Enum_ONE.Enum(),
  721. },
  722. want: `{
  723. "reqBool": false,
  724. "reqSfixed64": "0",
  725. "reqDouble": 1.23,
  726. "reqString": "hello",
  727. "reqEnum": "ONE"
  728. }`,
  729. }, {
  730. desc: "required fields all set",
  731. input: &pb2.Requireds{
  732. ReqBool: proto.Bool(false),
  733. ReqSfixed64: proto.Int64(0),
  734. ReqDouble: proto.Float64(1.23),
  735. ReqString: proto.String("hello"),
  736. ReqEnum: pb2.Enum_ONE.Enum(),
  737. ReqNested: &pb2.Nested{},
  738. },
  739. want: `{
  740. "reqBool": false,
  741. "reqSfixed64": "0",
  742. "reqDouble": 1.23,
  743. "reqString": "hello",
  744. "reqEnum": "ONE",
  745. "reqNested": {}
  746. }`,
  747. }, {
  748. desc: "indirect required field",
  749. input: &pb2.IndirectRequired{
  750. OptNested: &pb2.NestedWithRequired{},
  751. },
  752. want: `{
  753. "optNested": {}
  754. }`,
  755. wantErr: true,
  756. }, {
  757. desc: "indirect required field with AllowPartial",
  758. mo: protojson.MarshalOptions{AllowPartial: true},
  759. input: &pb2.IndirectRequired{
  760. OptNested: &pb2.NestedWithRequired{},
  761. },
  762. want: `{
  763. "optNested": {}
  764. }`,
  765. }, {
  766. desc: "indirect required field in empty repeated",
  767. input: &pb2.IndirectRequired{
  768. RptNested: []*pb2.NestedWithRequired{},
  769. },
  770. want: `{}`,
  771. }, {
  772. desc: "indirect required field in repeated",
  773. input: &pb2.IndirectRequired{
  774. RptNested: []*pb2.NestedWithRequired{
  775. &pb2.NestedWithRequired{},
  776. },
  777. },
  778. want: `{
  779. "rptNested": [
  780. {}
  781. ]
  782. }`,
  783. wantErr: true,
  784. }, {
  785. desc: "indirect required field in repeated with AllowPartial",
  786. mo: protojson.MarshalOptions{AllowPartial: true},
  787. input: &pb2.IndirectRequired{
  788. RptNested: []*pb2.NestedWithRequired{
  789. &pb2.NestedWithRequired{},
  790. },
  791. },
  792. want: `{
  793. "rptNested": [
  794. {}
  795. ]
  796. }`,
  797. }, {
  798. desc: "indirect required field in empty map",
  799. input: &pb2.IndirectRequired{
  800. StrToNested: map[string]*pb2.NestedWithRequired{},
  801. },
  802. want: "{}",
  803. }, {
  804. desc: "indirect required field in map",
  805. input: &pb2.IndirectRequired{
  806. StrToNested: map[string]*pb2.NestedWithRequired{
  807. "fail": &pb2.NestedWithRequired{},
  808. },
  809. },
  810. want: `{
  811. "strToNested": {
  812. "fail": {}
  813. }
  814. }`,
  815. wantErr: true,
  816. }, {
  817. desc: "indirect required field in map with AllowPartial",
  818. mo: protojson.MarshalOptions{AllowPartial: true},
  819. input: &pb2.IndirectRequired{
  820. StrToNested: map[string]*pb2.NestedWithRequired{
  821. "fail": &pb2.NestedWithRequired{},
  822. },
  823. },
  824. want: `{
  825. "strToNested": {
  826. "fail": {}
  827. }
  828. }`,
  829. }, {
  830. desc: "indirect required field in oneof",
  831. input: &pb2.IndirectRequired{
  832. Union: &pb2.IndirectRequired_OneofNested{
  833. OneofNested: &pb2.NestedWithRequired{},
  834. },
  835. },
  836. want: `{
  837. "oneofNested": {}
  838. }`,
  839. wantErr: true,
  840. }, {
  841. desc: "indirect required field in oneof with AllowPartial",
  842. mo: protojson.MarshalOptions{AllowPartial: true},
  843. input: &pb2.IndirectRequired{
  844. Union: &pb2.IndirectRequired_OneofNested{
  845. OneofNested: &pb2.NestedWithRequired{},
  846. },
  847. },
  848. want: `{
  849. "oneofNested": {}
  850. }`,
  851. }, {
  852. desc: "unknown fields are ignored",
  853. input: func() proto.Message {
  854. m := &pb2.Scalars{
  855. OptString: proto.String("no unknowns"),
  856. }
  857. m.ProtoReflect().SetUnknown(pack.Message{
  858. pack.Tag{101, pack.BytesType}, pack.String("hello world"),
  859. }.Marshal())
  860. return m
  861. }(),
  862. want: `{
  863. "optString": "no unknowns"
  864. }`,
  865. }, {
  866. desc: "json_name",
  867. input: &pb3.JSONNames{
  868. SString: "json_name",
  869. },
  870. want: `{
  871. "foo_bar": "json_name"
  872. }`,
  873. }, {
  874. desc: "extensions of non-repeated fields",
  875. input: func() proto.Message {
  876. m := &pb2.Extensions{
  877. OptString: proto.String("non-extension field"),
  878. OptBool: proto.Bool(true),
  879. OptInt32: proto.Int32(42),
  880. }
  881. proto.SetExtension(m, pb2.E_OptExtBool, true)
  882. proto.SetExtension(m, pb2.E_OptExtString, "extension field")
  883. proto.SetExtension(m, pb2.E_OptExtEnum, pb2.Enum_TEN)
  884. proto.SetExtension(m, pb2.E_OptExtNested, &pb2.Nested{
  885. OptString: proto.String("nested in an extension"),
  886. OptNested: &pb2.Nested{
  887. OptString: proto.String("another nested in an extension"),
  888. },
  889. })
  890. return m
  891. }(),
  892. want: `{
  893. "optString": "non-extension field",
  894. "optBool": true,
  895. "optInt32": 42,
  896. "[pb2.opt_ext_bool]": true,
  897. "[pb2.opt_ext_enum]": "TEN",
  898. "[pb2.opt_ext_nested]": {
  899. "optString": "nested in an extension",
  900. "optNested": {
  901. "optString": "another nested in an extension"
  902. }
  903. },
  904. "[pb2.opt_ext_string]": "extension field"
  905. }`,
  906. }, {
  907. desc: "extensions of repeated fields",
  908. input: func() proto.Message {
  909. m := &pb2.Extensions{}
  910. proto.SetExtension(m, pb2.E_RptExtEnum, []pb2.Enum{pb2.Enum_TEN, 101, pb2.Enum_ONE})
  911. proto.SetExtension(m, pb2.E_RptExtFixed32, []uint32{42, 47})
  912. proto.SetExtension(m, pb2.E_RptExtNested, []*pb2.Nested{
  913. &pb2.Nested{OptString: proto.String("one")},
  914. &pb2.Nested{OptString: proto.String("two")},
  915. &pb2.Nested{OptString: proto.String("three")},
  916. })
  917. return m
  918. }(),
  919. want: `{
  920. "[pb2.rpt_ext_enum]": [
  921. "TEN",
  922. 101,
  923. "ONE"
  924. ],
  925. "[pb2.rpt_ext_fixed32]": [
  926. 42,
  927. 47
  928. ],
  929. "[pb2.rpt_ext_nested]": [
  930. {
  931. "optString": "one"
  932. },
  933. {
  934. "optString": "two"
  935. },
  936. {
  937. "optString": "three"
  938. }
  939. ]
  940. }`,
  941. }, {
  942. desc: "extensions of non-repeated fields in another message",
  943. input: func() proto.Message {
  944. m := &pb2.Extensions{}
  945. proto.SetExtension(m, pb2.E_ExtensionsContainer_OptExtBool, true)
  946. proto.SetExtension(m, pb2.E_ExtensionsContainer_OptExtString, "extension field")
  947. proto.SetExtension(m, pb2.E_ExtensionsContainer_OptExtEnum, pb2.Enum_TEN)
  948. proto.SetExtension(m, pb2.E_ExtensionsContainer_OptExtNested, &pb2.Nested{
  949. OptString: proto.String("nested in an extension"),
  950. OptNested: &pb2.Nested{
  951. OptString: proto.String("another nested in an extension"),
  952. },
  953. })
  954. return m
  955. }(),
  956. want: `{
  957. "[pb2.ExtensionsContainer.opt_ext_bool]": true,
  958. "[pb2.ExtensionsContainer.opt_ext_enum]": "TEN",
  959. "[pb2.ExtensionsContainer.opt_ext_nested]": {
  960. "optString": "nested in an extension",
  961. "optNested": {
  962. "optString": "another nested in an extension"
  963. }
  964. },
  965. "[pb2.ExtensionsContainer.opt_ext_string]": "extension field"
  966. }`,
  967. }, {
  968. desc: "extensions of repeated fields in another message",
  969. input: func() proto.Message {
  970. m := &pb2.Extensions{
  971. OptString: proto.String("non-extension field"),
  972. OptBool: proto.Bool(true),
  973. OptInt32: proto.Int32(42),
  974. }
  975. proto.SetExtension(m, pb2.E_ExtensionsContainer_RptExtEnum, []pb2.Enum{pb2.Enum_TEN, 101, pb2.Enum_ONE})
  976. proto.SetExtension(m, pb2.E_ExtensionsContainer_RptExtString, []string{"hello", "world"})
  977. proto.SetExtension(m, pb2.E_ExtensionsContainer_RptExtNested, []*pb2.Nested{
  978. &pb2.Nested{OptString: proto.String("one")},
  979. &pb2.Nested{OptString: proto.String("two")},
  980. &pb2.Nested{OptString: proto.String("three")},
  981. })
  982. return m
  983. }(),
  984. want: `{
  985. "optString": "non-extension field",
  986. "optBool": true,
  987. "optInt32": 42,
  988. "[pb2.ExtensionsContainer.rpt_ext_enum]": [
  989. "TEN",
  990. 101,
  991. "ONE"
  992. ],
  993. "[pb2.ExtensionsContainer.rpt_ext_nested]": [
  994. {
  995. "optString": "one"
  996. },
  997. {
  998. "optString": "two"
  999. },
  1000. {
  1001. "optString": "three"
  1002. }
  1003. ],
  1004. "[pb2.ExtensionsContainer.rpt_ext_string]": [
  1005. "hello",
  1006. "world"
  1007. ]
  1008. }`,
  1009. }, {
  1010. desc: "MessageSet",
  1011. input: func() proto.Message {
  1012. m := &pb2.MessageSet{}
  1013. proto.SetExtension(m, pb2.E_MessageSetExtension_MessageSetExtension, &pb2.MessageSetExtension{
  1014. OptString: proto.String("a messageset extension"),
  1015. })
  1016. proto.SetExtension(m, pb2.E_MessageSetExtension_NotMessageSetExtension, &pb2.MessageSetExtension{
  1017. OptString: proto.String("not a messageset extension"),
  1018. })
  1019. proto.SetExtension(m, pb2.E_MessageSetExtension_ExtNested, &pb2.Nested{
  1020. OptString: proto.String("just a regular extension"),
  1021. })
  1022. return m
  1023. }(),
  1024. want: `{
  1025. "[pb2.MessageSetExtension]": {
  1026. "optString": "a messageset extension"
  1027. },
  1028. "[pb2.MessageSetExtension.ext_nested]": {
  1029. "optString": "just a regular extension"
  1030. },
  1031. "[pb2.MessageSetExtension.not_message_set_extension]": {
  1032. "optString": "not a messageset extension"
  1033. }
  1034. }`,
  1035. skip: !flags.ProtoLegacy,
  1036. }, {
  1037. desc: "not real MessageSet 1",
  1038. input: func() proto.Message {
  1039. m := &pb2.FakeMessageSet{}
  1040. proto.SetExtension(m, pb2.E_FakeMessageSetExtension_MessageSetExtension, &pb2.FakeMessageSetExtension{
  1041. OptString: proto.String("not a messageset extension"),
  1042. })
  1043. return m
  1044. }(),
  1045. want: `{
  1046. "[pb2.FakeMessageSetExtension.message_set_extension]": {
  1047. "optString": "not a messageset extension"
  1048. }
  1049. }`,
  1050. skip: !flags.ProtoLegacy,
  1051. }, {
  1052. desc: "not real MessageSet 2",
  1053. input: func() proto.Message {
  1054. m := &pb2.MessageSet{}
  1055. proto.SetExtension(m, pb2.E_MessageSetExtension, &pb2.FakeMessageSetExtension{
  1056. OptString: proto.String("another not a messageset extension"),
  1057. })
  1058. return m
  1059. }(),
  1060. want: `{
  1061. "[pb2.message_set_extension]": {
  1062. "optString": "another not a messageset extension"
  1063. }
  1064. }`,
  1065. skip: !flags.ProtoLegacy,
  1066. }, {
  1067. desc: "BoolValue empty",
  1068. input: &wrapperspb.BoolValue{},
  1069. want: `false`,
  1070. }, {
  1071. desc: "BoolValue",
  1072. input: &wrapperspb.BoolValue{Value: true},
  1073. want: `true`,
  1074. }, {
  1075. desc: "Int32Value empty",
  1076. input: &wrapperspb.Int32Value{},
  1077. want: `0`,
  1078. }, {
  1079. desc: "Int32Value",
  1080. input: &wrapperspb.Int32Value{Value: 42},
  1081. want: `42`,
  1082. }, {
  1083. desc: "Int64Value",
  1084. input: &wrapperspb.Int64Value{Value: 42},
  1085. want: `"42"`,
  1086. }, {
  1087. desc: "UInt32Value",
  1088. input: &wrapperspb.UInt32Value{Value: 42},
  1089. want: `42`,
  1090. }, {
  1091. desc: "UInt64Value",
  1092. input: &wrapperspb.UInt64Value{Value: 42},
  1093. want: `"42"`,
  1094. }, {
  1095. desc: "FloatValue",
  1096. input: &wrapperspb.FloatValue{Value: 1.02},
  1097. want: `1.02`,
  1098. }, {
  1099. desc: "FloatValue Infinity",
  1100. input: &wrapperspb.FloatValue{Value: float32(math.Inf(-1))},
  1101. want: `"-Infinity"`,
  1102. }, {
  1103. desc: "DoubleValue",
  1104. input: &wrapperspb.DoubleValue{Value: 1.02},
  1105. want: `1.02`,
  1106. }, {
  1107. desc: "DoubleValue NaN",
  1108. input: &wrapperspb.DoubleValue{Value: math.NaN()},
  1109. want: `"NaN"`,
  1110. }, {
  1111. desc: "StringValue empty",
  1112. input: &wrapperspb.StringValue{},
  1113. want: `""`,
  1114. }, {
  1115. desc: "StringValue",
  1116. input: &wrapperspb.StringValue{Value: "谷歌"},
  1117. want: `"谷歌"`,
  1118. }, {
  1119. desc: "StringValue with invalid UTF8 error",
  1120. input: &wrapperspb.StringValue{Value: "abc\xff"},
  1121. wantErr: true,
  1122. }, {
  1123. desc: "StringValue field with invalid UTF8 error",
  1124. input: &pb2.KnownTypes{
  1125. OptString: &wrapperspb.StringValue{Value: "abc\xff"},
  1126. },
  1127. wantErr: true,
  1128. }, {
  1129. desc: "BytesValue",
  1130. input: &wrapperspb.BytesValue{Value: []byte("hello")},
  1131. want: `"aGVsbG8="`,
  1132. }, {
  1133. desc: "Empty",
  1134. input: &emptypb.Empty{},
  1135. want: `{}`,
  1136. }, {
  1137. desc: "NullValue field",
  1138. input: &pb2.KnownTypes{OptNull: new(structpb.NullValue)},
  1139. want: `{
  1140. "optNull": null
  1141. }`,
  1142. }, {
  1143. desc: "Value empty",
  1144. input: &structpb.Value{},
  1145. wantErr: true,
  1146. }, {
  1147. desc: "Value empty field",
  1148. input: &pb2.KnownTypes{
  1149. OptValue: &structpb.Value{},
  1150. },
  1151. wantErr: true,
  1152. }, {
  1153. desc: "Value contains NullValue",
  1154. input: &structpb.Value{Kind: &structpb.Value_NullValue{}},
  1155. want: `null`,
  1156. }, {
  1157. desc: "Value contains BoolValue",
  1158. input: &structpb.Value{Kind: &structpb.Value_BoolValue{}},
  1159. want: `false`,
  1160. }, {
  1161. desc: "Value contains NumberValue",
  1162. input: &structpb.Value{Kind: &structpb.Value_NumberValue{1.02}},
  1163. want: `1.02`,
  1164. }, {
  1165. desc: "Value contains StringValue",
  1166. input: &structpb.Value{Kind: &structpb.Value_StringValue{"hello"}},
  1167. want: `"hello"`,
  1168. }, {
  1169. desc: "Value contains StringValue with invalid UTF8",
  1170. input: &structpb.Value{Kind: &structpb.Value_StringValue{"\xff"}},
  1171. wantErr: true,
  1172. }, {
  1173. desc: "Value contains Struct",
  1174. input: &structpb.Value{
  1175. Kind: &structpb.Value_StructValue{
  1176. &structpb.Struct{
  1177. Fields: map[string]*structpb.Value{
  1178. "null": {Kind: &structpb.Value_NullValue{}},
  1179. "number": {Kind: &structpb.Value_NumberValue{}},
  1180. "string": {Kind: &structpb.Value_StringValue{}},
  1181. "struct": {Kind: &structpb.Value_StructValue{}},
  1182. "list": {Kind: &structpb.Value_ListValue{}},
  1183. "bool": {Kind: &structpb.Value_BoolValue{}},
  1184. },
  1185. },
  1186. },
  1187. },
  1188. want: `{
  1189. "bool": false,
  1190. "list": [],
  1191. "null": null,
  1192. "number": 0,
  1193. "string": "",
  1194. "struct": {}
  1195. }`,
  1196. }, {
  1197. desc: "Value contains ListValue",
  1198. input: &structpb.Value{
  1199. Kind: &structpb.Value_ListValue{
  1200. &structpb.ListValue{
  1201. Values: []*structpb.Value{
  1202. {Kind: &structpb.Value_BoolValue{}},
  1203. {Kind: &structpb.Value_NullValue{}},
  1204. {Kind: &structpb.Value_NumberValue{}},
  1205. {Kind: &structpb.Value_StringValue{}},
  1206. {Kind: &structpb.Value_StructValue{}},
  1207. {Kind: &structpb.Value_ListValue{}},
  1208. },
  1209. },
  1210. },
  1211. },
  1212. want: `[
  1213. false,
  1214. null,
  1215. 0,
  1216. "",
  1217. {},
  1218. []
  1219. ]`,
  1220. }, {
  1221. desc: "Struct with nil map",
  1222. input: &structpb.Struct{},
  1223. want: `{}`,
  1224. }, {
  1225. desc: "Struct with empty map",
  1226. input: &structpb.Struct{
  1227. Fields: map[string]*structpb.Value{},
  1228. },
  1229. want: `{}`,
  1230. }, {
  1231. desc: "Struct",
  1232. input: &structpb.Struct{
  1233. Fields: map[string]*structpb.Value{
  1234. "bool": {Kind: &structpb.Value_BoolValue{true}},
  1235. "null": {Kind: &structpb.Value_NullValue{}},
  1236. "number": {Kind: &structpb.Value_NumberValue{3.1415}},
  1237. "string": {Kind: &structpb.Value_StringValue{"hello"}},
  1238. "struct": {
  1239. Kind: &structpb.Value_StructValue{
  1240. &structpb.Struct{
  1241. Fields: map[string]*structpb.Value{
  1242. "string": {Kind: &structpb.Value_StringValue{"world"}},
  1243. },
  1244. },
  1245. },
  1246. },
  1247. "list": {
  1248. Kind: &structpb.Value_ListValue{
  1249. &structpb.ListValue{
  1250. Values: []*structpb.Value{
  1251. {Kind: &structpb.Value_BoolValue{}},
  1252. {Kind: &structpb.Value_NullValue{}},
  1253. {Kind: &structpb.Value_NumberValue{}},
  1254. },
  1255. },
  1256. },
  1257. },
  1258. },
  1259. },
  1260. want: `{
  1261. "bool": true,
  1262. "list": [
  1263. false,
  1264. null,
  1265. 0
  1266. ],
  1267. "null": null,
  1268. "number": 3.1415,
  1269. "string": "hello",
  1270. "struct": {
  1271. "string": "world"
  1272. }
  1273. }`,
  1274. }, {
  1275. desc: "Struct message with invalid UTF8 string",
  1276. input: &structpb.Struct{
  1277. Fields: map[string]*structpb.Value{
  1278. "string": {Kind: &structpb.Value_StringValue{"\xff"}},
  1279. },
  1280. },
  1281. wantErr: true,
  1282. }, {
  1283. desc: "ListValue with nil values",
  1284. input: &structpb.ListValue{},
  1285. want: `[]`,
  1286. }, {
  1287. desc: "ListValue with empty values",
  1288. input: &structpb.ListValue{
  1289. Values: []*structpb.Value{},
  1290. },
  1291. want: `[]`,
  1292. }, {
  1293. desc: "ListValue",
  1294. input: &structpb.ListValue{
  1295. Values: []*structpb.Value{
  1296. {Kind: &structpb.Value_BoolValue{true}},
  1297. {Kind: &structpb.Value_NullValue{}},
  1298. {Kind: &structpb.Value_NumberValue{3.1415}},
  1299. {Kind: &structpb.Value_StringValue{"hello"}},
  1300. {
  1301. Kind: &structpb.Value_ListValue{
  1302. &structpb.ListValue{
  1303. Values: []*structpb.Value{
  1304. {Kind: &structpb.Value_BoolValue{}},
  1305. {Kind: &structpb.Value_NullValue{}},
  1306. {Kind: &structpb.Value_NumberValue{}},
  1307. },
  1308. },
  1309. },
  1310. },
  1311. {
  1312. Kind: &structpb.Value_StructValue{
  1313. &structpb.Struct{
  1314. Fields: map[string]*structpb.Value{
  1315. "string": {Kind: &structpb.Value_StringValue{"world"}},
  1316. },
  1317. },
  1318. },
  1319. },
  1320. },
  1321. },
  1322. want: `[
  1323. true,
  1324. null,
  1325. 3.1415,
  1326. "hello",
  1327. [
  1328. false,
  1329. null,
  1330. 0
  1331. ],
  1332. {
  1333. "string": "world"
  1334. }
  1335. ]`,
  1336. }, {
  1337. desc: "ListValue with invalid UTF8 string",
  1338. input: &structpb.ListValue{
  1339. Values: []*structpb.Value{
  1340. {Kind: &structpb.Value_StringValue{"\xff"}},
  1341. },
  1342. },
  1343. wantErr: true,
  1344. }, {
  1345. desc: "Duration empty",
  1346. input: &durationpb.Duration{},
  1347. want: `"0s"`,
  1348. }, {
  1349. desc: "Duration with secs",
  1350. input: &durationpb.Duration{Seconds: 3},
  1351. want: `"3s"`,
  1352. }, {
  1353. desc: "Duration with -secs",
  1354. input: &durationpb.Duration{Seconds: -3},
  1355. want: `"-3s"`,
  1356. }, {
  1357. desc: "Duration with nanos",
  1358. input: &durationpb.Duration{Nanos: 1e6},
  1359. want: `"0.001s"`,
  1360. }, {
  1361. desc: "Duration with -nanos",
  1362. input: &durationpb.Duration{Nanos: -1e6},
  1363. want: `"-0.001s"`,
  1364. }, {
  1365. desc: "Duration with large secs",
  1366. input: &durationpb.Duration{Seconds: 1e10, Nanos: 1},
  1367. want: `"10000000000.000000001s"`,
  1368. }, {
  1369. desc: "Duration with 6-digit nanos",
  1370. input: &durationpb.Duration{Nanos: 1e4},
  1371. want: `"0.000010s"`,
  1372. }, {
  1373. desc: "Duration with 3-digit nanos",
  1374. input: &durationpb.Duration{Nanos: 1e6},
  1375. want: `"0.001s"`,
  1376. }, {
  1377. desc: "Duration with -secs -nanos",
  1378. input: &durationpb.Duration{Seconds: -123, Nanos: -450},
  1379. want: `"-123.000000450s"`,
  1380. }, {
  1381. desc: "Duration max value",
  1382. input: &durationpb.Duration{Seconds: 315576000000, Nanos: 999999999},
  1383. want: `"315576000000.999999999s"`,
  1384. }, {
  1385. desc: "Duration min value",
  1386. input: &durationpb.Duration{Seconds: -315576000000, Nanos: -999999999},
  1387. want: `"-315576000000.999999999s"`,
  1388. }, {
  1389. desc: "Duration with +secs -nanos",
  1390. input: &durationpb.Duration{Seconds: 1, Nanos: -1},
  1391. wantErr: true,
  1392. }, {
  1393. desc: "Duration with -secs +nanos",
  1394. input: &durationpb.Duration{Seconds: -1, Nanos: 1},
  1395. wantErr: true,
  1396. }, {
  1397. desc: "Duration with +secs out of range",
  1398. input: &durationpb.Duration{Seconds: 315576000001},
  1399. wantErr: true,
  1400. }, {
  1401. desc: "Duration with -secs out of range",
  1402. input: &durationpb.Duration{Seconds: -315576000001},
  1403. wantErr: true,
  1404. }, {
  1405. desc: "Duration with +nanos out of range",
  1406. input: &durationpb.Duration{Seconds: 0, Nanos: 1e9},
  1407. wantErr: true,
  1408. }, {
  1409. desc: "Duration with -nanos out of range",
  1410. input: &durationpb.Duration{Seconds: 0, Nanos: -1e9},
  1411. wantErr: true,
  1412. }, {
  1413. desc: "Timestamp zero",
  1414. input: &timestamppb.Timestamp{},
  1415. want: `"1970-01-01T00:00:00Z"`,
  1416. }, {
  1417. desc: "Timestamp",
  1418. input: &timestamppb.Timestamp{Seconds: 1553036601},
  1419. want: `"2019-03-19T23:03:21Z"`,
  1420. }, {
  1421. desc: "Timestamp with nanos",
  1422. input: &timestamppb.Timestamp{Seconds: 1553036601, Nanos: 1},
  1423. want: `"2019-03-19T23:03:21.000000001Z"`,
  1424. }, {
  1425. desc: "Timestamp with 6-digit nanos",
  1426. input: &timestamppb.Timestamp{Nanos: 1e3},
  1427. want: `"1970-01-01T00:00:00.000001Z"`,
  1428. }, {
  1429. desc: "Timestamp with 3-digit nanos",
  1430. input: &timestamppb.Timestamp{Nanos: 1e7},
  1431. want: `"1970-01-01T00:00:00.010Z"`,
  1432. }, {
  1433. desc: "Timestamp max value",
  1434. input: &timestamppb.Timestamp{Seconds: 253402300799, Nanos: 999999999},
  1435. want: `"9999-12-31T23:59:59.999999999Z"`,
  1436. }, {
  1437. desc: "Timestamp min value",
  1438. input: &timestamppb.Timestamp{Seconds: -62135596800},
  1439. want: `"0001-01-01T00:00:00Z"`,
  1440. }, {
  1441. desc: "Timestamp with +secs out of range",
  1442. input: &timestamppb.Timestamp{Seconds: 253402300800},
  1443. wantErr: true,
  1444. }, {
  1445. desc: "Timestamp with -secs out of range",
  1446. input: &timestamppb.Timestamp{Seconds: -62135596801},
  1447. wantErr: true,
  1448. }, {
  1449. desc: "Timestamp with -nanos",
  1450. input: &timestamppb.Timestamp{Nanos: -1},
  1451. wantErr: true,
  1452. }, {
  1453. desc: "Timestamp with +nanos out of range",
  1454. input: &timestamppb.Timestamp{Nanos: 1e9},
  1455. wantErr: true,
  1456. }, {
  1457. desc: "FieldMask empty",
  1458. input: &fieldmaskpb.FieldMask{},
  1459. want: `""`,
  1460. }, {
  1461. desc: "FieldMask",
  1462. input: &fieldmaskpb.FieldMask{
  1463. Paths: []string{
  1464. "foo",
  1465. "foo_bar",
  1466. "foo.bar_qux",
  1467. "_foo",
  1468. },
  1469. },
  1470. want: `"foo,fooBar,foo.barQux,Foo"`,
  1471. }, {
  1472. desc: "FieldMask error 1",
  1473. input: &fieldmaskpb.FieldMask{
  1474. Paths: []string{"foo_"},
  1475. },
  1476. wantErr: true,
  1477. }, {
  1478. desc: "FieldMask error 2",
  1479. input: &fieldmaskpb.FieldMask{
  1480. Paths: []string{"foo__bar"},
  1481. },
  1482. wantErr: true,
  1483. }, {
  1484. desc: "Any empty",
  1485. input: &anypb.Any{},
  1486. want: `{}`,
  1487. }, {
  1488. desc: "Any with non-custom message",
  1489. mo: protojson.MarshalOptions{
  1490. Resolver: preg.NewTypes(pimpl.Export{}.MessageTypeOf(&pb2.Nested{})),
  1491. },
  1492. input: func() proto.Message {
  1493. m := &pb2.Nested{
  1494. OptString: proto.String("embedded inside Any"),
  1495. OptNested: &pb2.Nested{
  1496. OptString: proto.String("inception"),
  1497. },
  1498. }
  1499. b, err := proto.MarshalOptions{Deterministic: true}.Marshal(m)
  1500. if err != nil {
  1501. t.Fatalf("error in binary marshaling message for Any.value: %v", err)
  1502. }
  1503. return &anypb.Any{
  1504. TypeUrl: "foo/pb2.Nested",
  1505. Value: b,
  1506. }
  1507. }(),
  1508. want: `{
  1509. "@type": "foo/pb2.Nested",
  1510. "optString": "embedded inside Any",
  1511. "optNested": {
  1512. "optString": "inception"
  1513. }
  1514. }`,
  1515. }, {
  1516. desc: "Any with empty embedded message",
  1517. mo: protojson.MarshalOptions{
  1518. Resolver: preg.NewTypes(pimpl.Export{}.MessageTypeOf(&pb2.Nested{})),
  1519. },
  1520. input: &anypb.Any{TypeUrl: "foo/pb2.Nested"},
  1521. want: `{
  1522. "@type": "foo/pb2.Nested"
  1523. }`,
  1524. }, {
  1525. desc: "Any without registered type",
  1526. mo: protojson.MarshalOptions{Resolver: preg.NewTypes()},
  1527. input: &anypb.Any{TypeUrl: "foo/pb2.Nested"},
  1528. wantErr: true,
  1529. }, {
  1530. desc: "Any with missing required",
  1531. mo: protojson.MarshalOptions{
  1532. Resolver: preg.NewTypes(pimpl.Export{}.MessageTypeOf(&pb2.PartialRequired{})),
  1533. },
  1534. input: func() proto.Message {
  1535. m := &pb2.PartialRequired{
  1536. OptString: proto.String("embedded inside Any"),
  1537. }
  1538. b, err := proto.MarshalOptions{
  1539. AllowPartial: true,
  1540. Deterministic: true,
  1541. }.Marshal(m)
  1542. if err != nil {
  1543. t.Fatalf("error in binary marshaling message for Any.value: %v", err)
  1544. }
  1545. return &anypb.Any{
  1546. TypeUrl: string(m.ProtoReflect().Descriptor().FullName()),
  1547. Value: b,
  1548. }
  1549. }(),
  1550. want: `{
  1551. "@type": "pb2.PartialRequired",
  1552. "optString": "embedded inside Any"
  1553. }`,
  1554. }, {
  1555. desc: "Any with partial required and AllowPartial",
  1556. mo: protojson.MarshalOptions{
  1557. AllowPartial: true,
  1558. Resolver: preg.NewTypes(pimpl.Export{}.MessageTypeOf(&pb2.PartialRequired{})),
  1559. },
  1560. input: func() proto.Message {
  1561. m := &pb2.PartialRequired{
  1562. OptString: proto.String("embedded inside Any"),
  1563. }
  1564. b, err := proto.MarshalOptions{
  1565. AllowPartial: true,
  1566. Deterministic: true,
  1567. }.Marshal(m)
  1568. if err != nil {
  1569. t.Fatalf("error in binary marshaling message for Any.value: %v", err)
  1570. }
  1571. return &anypb.Any{
  1572. TypeUrl: string(m.ProtoReflect().Descriptor().FullName()),
  1573. Value: b,
  1574. }
  1575. }(),
  1576. want: `{
  1577. "@type": "pb2.PartialRequired",
  1578. "optString": "embedded inside Any"
  1579. }`,
  1580. }, {
  1581. desc: "Any with invalid UTF8",
  1582. mo: protojson.MarshalOptions{
  1583. Resolver: preg.NewTypes(pimpl.Export{}.MessageTypeOf(&pb2.Nested{})),
  1584. },
  1585. input: func() proto.Message {
  1586. m := &pb2.Nested{
  1587. OptString: proto.String("abc\xff"),
  1588. }
  1589. b, err := proto.MarshalOptions{Deterministic: true}.Marshal(m)
  1590. if err != nil {
  1591. t.Fatalf("error in binary marshaling message for Any.value: %v", err)
  1592. }
  1593. return &anypb.Any{
  1594. TypeUrl: "foo/pb2.Nested",
  1595. Value: b,
  1596. }
  1597. }(),
  1598. wantErr: true,
  1599. }, {
  1600. desc: "Any with invalid value",
  1601. mo: protojson.MarshalOptions{
  1602. Resolver: preg.NewTypes(pimpl.Export{}.MessageTypeOf(&pb2.Nested{})),
  1603. },
  1604. input: &anypb.Any{
  1605. TypeUrl: "foo/pb2.Nested",
  1606. Value: []byte("\x80"),
  1607. },
  1608. wantErr: true,
  1609. }, {
  1610. desc: "Any with BoolValue",
  1611. mo: protojson.MarshalOptions{
  1612. Resolver: preg.NewTypes(pimpl.Export{}.MessageTypeOf(&wrapperspb.BoolValue{})),
  1613. },
  1614. input: func() proto.Message {
  1615. m := &wrapperspb.BoolValue{Value: true}
  1616. b, err := proto.MarshalOptions{Deterministic: true}.Marshal(m)
  1617. if err != nil {
  1618. t.Fatalf("error in binary marshaling message for Any.value: %v", err)
  1619. }
  1620. return &anypb.Any{
  1621. TypeUrl: "type.googleapis.com/google.protobuf.BoolValue",
  1622. Value: b,
  1623. }
  1624. }(),
  1625. want: `{
  1626. "@type": "type.googleapis.com/google.protobuf.BoolValue",
  1627. "value": true
  1628. }`,
  1629. }, {
  1630. desc: "Any with Empty",
  1631. mo: protojson.MarshalOptions{
  1632. Resolver: preg.NewTypes(pimpl.Export{}.MessageTypeOf(&emptypb.Empty{})),
  1633. },
  1634. input: func() proto.Message {
  1635. m := &emptypb.Empty{}
  1636. b, err := proto.MarshalOptions{Deterministic: true}.Marshal(m)
  1637. if err != nil {
  1638. t.Fatalf("error in binary marshaling message for Any.value: %v", err)
  1639. }
  1640. return &anypb.Any{
  1641. TypeUrl: "type.googleapis.com/google.protobuf.Empty",
  1642. Value: b,
  1643. }
  1644. }(),
  1645. want: `{
  1646. "@type": "type.googleapis.com/google.protobuf.Empty",
  1647. "value": {}
  1648. }`,
  1649. }, {
  1650. desc: "Any with StringValue containing invalid UTF8",
  1651. mo: protojson.MarshalOptions{
  1652. Resolver: preg.NewTypes(pimpl.Export{}.MessageTypeOf(&wrapperspb.StringValue{})),
  1653. },
  1654. input: func() proto.Message {
  1655. m := &wrapperspb.StringValue{Value: "abcd"}
  1656. b, err := proto.MarshalOptions{Deterministic: true}.Marshal(m)
  1657. if err != nil {
  1658. t.Fatalf("error in binary marshaling message for Any.value: %v", err)
  1659. }
  1660. return &anypb.Any{
  1661. TypeUrl: "google.protobuf.StringValue",
  1662. Value: bytes.Replace(b, []byte("abcd"), []byte("abc\xff"), -1),
  1663. }
  1664. }(),
  1665. wantErr: true,
  1666. }, {
  1667. desc: "Any with Int64Value",
  1668. mo: protojson.MarshalOptions{
  1669. Resolver: preg.NewTypes(pimpl.Export{}.MessageTypeOf(&wrapperspb.Int64Value{})),
  1670. },
  1671. input: func() proto.Message {
  1672. m := &wrapperspb.Int64Value{Value: 42}
  1673. b, err := proto.MarshalOptions{Deterministic: true}.Marshal(m)
  1674. if err != nil {
  1675. t.Fatalf("error in binary marshaling message for Any.value: %v", err)
  1676. }
  1677. return &anypb.Any{
  1678. TypeUrl: "google.protobuf.Int64Value",
  1679. Value: b,
  1680. }
  1681. }(),
  1682. want: `{
  1683. "@type": "google.protobuf.Int64Value",
  1684. "value": "42"
  1685. }`,
  1686. }, {
  1687. desc: "Any with Duration",
  1688. mo: protojson.MarshalOptions{
  1689. Resolver: preg.NewTypes(pimpl.Export{}.MessageTypeOf(&durationpb.Duration{})),
  1690. },
  1691. input: func() proto.Message {
  1692. m := &durationpb.Duration{}
  1693. b, err := proto.MarshalOptions{Deterministic: true}.Marshal(m)
  1694. if err != nil {
  1695. t.Fatalf("error in binary marshaling message for Any.value: %v", err)
  1696. }
  1697. return &anypb.Any{
  1698. TypeUrl: "type.googleapis.com/google.protobuf.Duration",
  1699. Value: b,
  1700. }
  1701. }(),
  1702. want: `{
  1703. "@type": "type.googleapis.com/google.protobuf.Duration",
  1704. "value": "0s"
  1705. }`,
  1706. }, {
  1707. desc: "Any with empty Value",
  1708. mo: protojson.MarshalOptions{
  1709. Resolver: preg.NewTypes(pimpl.Export{}.MessageTypeOf(&structpb.Value{})),
  1710. },
  1711. input: func() proto.Message {
  1712. m := &structpb.Value{}
  1713. b, err := proto.Marshal(m)
  1714. if err != nil {
  1715. t.Fatalf("error in binary marshaling message for Any.value: %v", err)
  1716. }
  1717. return &anypb.Any{
  1718. TypeUrl: "type.googleapis.com/google.protobuf.Value",
  1719. Value: b,
  1720. }
  1721. }(),
  1722. wantErr: true,
  1723. }, {
  1724. desc: "Any with Value of StringValue",
  1725. mo: protojson.MarshalOptions{
  1726. Resolver: preg.NewTypes(pimpl.Export{}.MessageTypeOf(&structpb.Value{})),
  1727. },
  1728. input: func() proto.Message {
  1729. m := &structpb.Value{Kind: &structpb.Value_StringValue{"abcd"}}
  1730. b, err := proto.MarshalOptions{Deterministic: true}.Marshal(m)
  1731. if err != nil {
  1732. t.Fatalf("error in binary marshaling message for Any.value: %v", err)
  1733. }
  1734. return &anypb.Any{
  1735. TypeUrl: "type.googleapis.com/google.protobuf.Value",
  1736. Value: bytes.Replace(b, []byte("abcd"), []byte("abc\xff"), -1),
  1737. }
  1738. }(),
  1739. wantErr: true,
  1740. }, {
  1741. desc: "Any with Value of NullValue",
  1742. mo: protojson.MarshalOptions{
  1743. Resolver: preg.NewTypes(pimpl.Export{}.MessageTypeOf(&structpb.Value{})),
  1744. },
  1745. input: func() proto.Message {
  1746. m := &structpb.Value{Kind: &structpb.Value_NullValue{}}
  1747. b, err := proto.MarshalOptions{Deterministic: true}.Marshal(m)
  1748. if err != nil {
  1749. t.Fatalf("error in binary marshaling message for Any.value: %v", err)
  1750. }
  1751. return &anypb.Any{
  1752. TypeUrl: "type.googleapis.com/google.protobuf.Value",
  1753. Value: b,
  1754. }
  1755. }(),
  1756. want: `{
  1757. "@type": "type.googleapis.com/google.protobuf.Value",
  1758. "value": null
  1759. }`,
  1760. }, {
  1761. desc: "Any with Struct",
  1762. mo: protojson.MarshalOptions{
  1763. Resolver: preg.NewTypes(
  1764. pimpl.Export{}.MessageTypeOf(&structpb.Struct{}),
  1765. pimpl.Export{}.MessageTypeOf(&structpb.Value{}),
  1766. pimpl.Export{}.MessageTypeOf(&wrapperspb.BoolValue{}),
  1767. pimpl.Export{}.EnumTypeOf(structpb.NullValue_NULL_VALUE),
  1768. pimpl.Export{}.MessageTypeOf(&wrapperspb.StringValue{}),
  1769. ),
  1770. },
  1771. input: func() proto.Message {
  1772. m := &structpb.Struct{
  1773. Fields: map[string]*structpb.Value{
  1774. "bool": {Kind: &structpb.Value_BoolValue{true}},
  1775. "null": {Kind: &structpb.Value_NullValue{}},
  1776. "string": {Kind: &structpb.Value_StringValue{"hello"}},
  1777. "struct": {
  1778. Kind: &structpb.Value_StructValue{
  1779. &structpb.Struct{
  1780. Fields: map[string]*structpb.Value{
  1781. "string": {Kind: &structpb.Value_StringValue{"world"}},
  1782. },
  1783. },
  1784. },
  1785. },
  1786. },
  1787. }
  1788. b, err := proto.MarshalOptions{Deterministic: true}.Marshal(m)
  1789. if err != nil {
  1790. t.Fatalf("error in binary marshaling message for Any.value: %v", err)
  1791. }
  1792. return &anypb.Any{
  1793. TypeUrl: "google.protobuf.Struct",
  1794. Value: b,
  1795. }
  1796. }(),
  1797. want: `{
  1798. "@type": "google.protobuf.Struct",
  1799. "value": {
  1800. "bool": true,
  1801. "null": null,
  1802. "string": "hello",
  1803. "struct": {
  1804. "string": "world"
  1805. }
  1806. }
  1807. }`,
  1808. }, {
  1809. desc: "Any with missing type_url",
  1810. mo: protojson.MarshalOptions{
  1811. Resolver: preg.NewTypes(pimpl.Export{}.MessageTypeOf(&wrapperspb.BoolValue{})),
  1812. },
  1813. input: func() proto.Message {
  1814. m := &wrapperspb.BoolValue{Value: true}
  1815. b, err := proto.MarshalOptions{Deterministic: true}.Marshal(m)
  1816. if err != nil {
  1817. t.Fatalf("error in binary marshaling message for Any.value: %v", err)
  1818. }
  1819. return &anypb.Any{
  1820. Value: b,
  1821. }
  1822. }(),
  1823. wantErr: true,
  1824. }, {
  1825. desc: "well known types as field values",
  1826. mo: protojson.MarshalOptions{
  1827. Resolver: preg.NewTypes(pimpl.Export{}.MessageTypeOf(&emptypb.Empty{})),
  1828. },
  1829. input: &pb2.KnownTypes{
  1830. OptBool: &wrapperspb.BoolValue{Value: false},
  1831. OptInt32: &wrapperspb.Int32Value{Value: 42},
  1832. OptInt64: &wrapperspb.Int64Value{Value: 42},
  1833. OptUint32: &wrapperspb.UInt32Value{Value: 42},
  1834. OptUint64: &wrapperspb.UInt64Value{Value: 42},
  1835. OptFloat: &wrapperspb.FloatValue{Value: 1.23},
  1836. OptDouble: &wrapperspb.DoubleValue{Value: 3.1415},
  1837. OptString: &wrapperspb.StringValue{Value: "hello"},
  1838. OptBytes: &wrapperspb.BytesValue{Value: []byte("hello")},
  1839. OptDuration: &durationpb.Duration{Seconds: 123},
  1840. OptTimestamp: &timestamppb.Timestamp{Seconds: 1553036601},
  1841. OptStruct: &structpb.Struct{
  1842. Fields: map[string]*structpb.Value{
  1843. "string": {Kind: &structpb.Value_StringValue{"hello"}},
  1844. },
  1845. },
  1846. OptList: &structpb.ListValue{
  1847. Values: []*structpb.Value{
  1848. {Kind: &structpb.Value_NullValue{}},
  1849. {Kind: &structpb.Value_StringValue{}},
  1850. {Kind: &structpb.Value_StructValue{}},
  1851. {Kind: &structpb.Value_ListValue{}},
  1852. },
  1853. },
  1854. OptValue: &structpb.Value{
  1855. Kind: &structpb.Value_StringValue{"world"},
  1856. },
  1857. OptEmpty: &emptypb.Empty{},
  1858. OptAny: &anypb.Any{
  1859. TypeUrl: "google.protobuf.Empty",
  1860. },
  1861. OptFieldmask: &fieldmaskpb.FieldMask{
  1862. Paths: []string{"foo_bar", "bar_foo"},
  1863. },
  1864. },
  1865. want: `{
  1866. "optBool": false,
  1867. "optInt32": 42,
  1868. "optInt64": "42",
  1869. "optUint32": 42,
  1870. "optUint64": "42",
  1871. "optFloat": 1.23,
  1872. "optDouble": 3.1415,
  1873. "optString": "hello",
  1874. "optBytes": "aGVsbG8=",
  1875. "optDuration": "123s",
  1876. "optTimestamp": "2019-03-19T23:03:21Z",
  1877. "optStruct": {
  1878. "string": "hello"
  1879. },
  1880. "optList": [
  1881. null,
  1882. "",
  1883. {},
  1884. []
  1885. ],
  1886. "optValue": "world",
  1887. "optEmpty": {},
  1888. "optAny": {
  1889. "@type": "google.protobuf.Empty",
  1890. "value": {}
  1891. },
  1892. "optFieldmask": "fooBar,barFoo"
  1893. }`,
  1894. }, {
  1895. desc: "EmitUnpopulated: proto2 optional scalars",
  1896. mo: protojson.MarshalOptions{EmitUnpopulated: true},
  1897. input: &pb2.Scalars{},
  1898. want: `{
  1899. "optBool": null,
  1900. "optInt32": null,
  1901. "optInt64": null,
  1902. "optUint32": null,
  1903. "optUint64": null,
  1904. "optSint32": null,
  1905. "optSint64": null,
  1906. "optFixed32": null,
  1907. "optFixed64": null,
  1908. "optSfixed32": null,
  1909. "optSfixed64": null,
  1910. "optFloat": null,
  1911. "optDouble": null,
  1912. "optBytes": null,
  1913. "optString": null
  1914. }`,
  1915. }, {
  1916. desc: "EmitUnpopulated: proto3 scalars",
  1917. mo: protojson.MarshalOptions{EmitUnpopulated: true},
  1918. input: &pb3.Scalars{},
  1919. want: `{
  1920. "sBool": false,
  1921. "sInt32": 0,
  1922. "sInt64": "0",
  1923. "sUint32": 0,
  1924. "sUint64": "0",
  1925. "sSint32": 0,
  1926. "sSint64": "0",
  1927. "sFixed32": 0,
  1928. "sFixed64": "0",
  1929. "sSfixed32": 0,
  1930. "sSfixed64": "0",
  1931. "sFloat": 0,
  1932. "sDouble": 0,
  1933. "sBytes": "",
  1934. "sString": ""
  1935. }`,
  1936. }, {
  1937. desc: "EmitUnpopulated: proto2 enum",
  1938. mo: protojson.MarshalOptions{EmitUnpopulated: true},
  1939. input: &pb2.Enums{},
  1940. want: `{
  1941. "optEnum": null,
  1942. "rptEnum": [],
  1943. "optNestedEnum": null,
  1944. "rptNestedEnum": []
  1945. }`,
  1946. }, {
  1947. desc: "EmitUnpopulated: proto3 enum",
  1948. mo: protojson.MarshalOptions{EmitUnpopulated: true},
  1949. input: &pb3.Enums{},
  1950. want: `{
  1951. "sEnum": "ZERO",
  1952. "sNestedEnum": "CERO"
  1953. }`,
  1954. }, {
  1955. desc: "EmitUnpopulated: proto2 message and group fields",
  1956. mo: protojson.MarshalOptions{EmitUnpopulated: true},
  1957. input: &pb2.Nests{},
  1958. want: `{
  1959. "optNested": null,
  1960. "optgroup": null,
  1961. "rptNested": [],
  1962. "rptgroup": []
  1963. }`,
  1964. }, {
  1965. desc: "EmitUnpopulated: proto3 message field",
  1966. mo: protojson.MarshalOptions{EmitUnpopulated: true},
  1967. input: &pb3.Nests{},
  1968. want: `{
  1969. "sNested": null
  1970. }`,
  1971. }, {
  1972. desc: "EmitUnpopulated: proto2 empty message and group fields",
  1973. mo: protojson.MarshalOptions{EmitUnpopulated: true},
  1974. input: &pb2.Nests{
  1975. OptNested: &pb2.Nested{},
  1976. Optgroup: &pb2.Nests_OptGroup{},
  1977. },
  1978. want: `{
  1979. "optNested": {
  1980. "optString": null,
  1981. "optNested": null
  1982. },
  1983. "optgroup": {
  1984. "optString": null,
  1985. "optNested": null,
  1986. "optnestedgroup": null
  1987. },
  1988. "rptNested": [],
  1989. "rptgroup": []
  1990. }`,
  1991. }, {
  1992. desc: "EmitUnpopulated: proto3 empty message field",
  1993. mo: protojson.MarshalOptions{EmitUnpopulated: true},
  1994. input: &pb3.Nests{
  1995. SNested: &pb3.Nested{},
  1996. },
  1997. want: `{
  1998. "sNested": {
  1999. "sString": "",
  2000. "sNested": null
  2001. }
  2002. }`,
  2003. }, {
  2004. desc: "EmitUnpopulated: proto2 required fields",
  2005. mo: protojson.MarshalOptions{
  2006. AllowPartial: true,
  2007. EmitUnpopulated: true,
  2008. },
  2009. input: &pb2.Requireds{},
  2010. want: `{
  2011. "reqBool": null,
  2012. "reqSfixed64": null,
  2013. "reqDouble": null,
  2014. "reqString": null,
  2015. "reqEnum": null,
  2016. "reqNested": null
  2017. }`,
  2018. }, {
  2019. desc: "EmitUnpopulated: repeated fields",
  2020. mo: protojson.MarshalOptions{EmitUnpopulated: true},
  2021. input: &pb2.Repeats{},
  2022. want: `{
  2023. "rptBool": [],
  2024. "rptInt32": [],
  2025. "rptInt64": [],
  2026. "rptUint32": [],
  2027. "rptUint64": [],
  2028. "rptFloat": [],
  2029. "rptDouble": [],
  2030. "rptString": [],
  2031. "rptBytes": []
  2032. }`,
  2033. }, {
  2034. desc: "EmitUnpopulated: repeated containing empty message",
  2035. mo: protojson.MarshalOptions{EmitUnpopulated: true},
  2036. input: &pb2.Nests{
  2037. RptNested: []*pb2.Nested{nil, {}},
  2038. },
  2039. want: `{
  2040. "optNested": null,
  2041. "optgroup": null,
  2042. "rptNested": [
  2043. {
  2044. "optString": null,
  2045. "optNested": null
  2046. },
  2047. {
  2048. "optString": null,
  2049. "optNested": null
  2050. }
  2051. ],
  2052. "rptgroup": []
  2053. }`,
  2054. }, {
  2055. desc: "EmitUnpopulated: map fields",
  2056. mo: protojson.MarshalOptions{EmitUnpopulated: true},
  2057. input: &pb3.Maps{},
  2058. want: `{
  2059. "int32ToStr": {},
  2060. "boolToUint32": {},
  2061. "uint64ToEnum": {},
  2062. "strToNested": {},
  2063. "strToOneofs": {}
  2064. }`,
  2065. }, {
  2066. desc: "EmitUnpopulated: map containing empty message",
  2067. mo: protojson.MarshalOptions{EmitUnpopulated: true},
  2068. input: &pb3.Maps{
  2069. StrToNested: map[string]*pb3.Nested{
  2070. "nested": &pb3.Nested{},
  2071. },
  2072. StrToOneofs: map[string]*pb3.Oneofs{
  2073. "nested": &pb3.Oneofs{},
  2074. },
  2075. },
  2076. want: `{
  2077. "int32ToStr": {},
  2078. "boolToUint32": {},
  2079. "uint64ToEnum": {},
  2080. "strToNested": {
  2081. "nested": {
  2082. "sString": "",
  2083. "sNested": null
  2084. }
  2085. },
  2086. "strToOneofs": {
  2087. "nested": {}
  2088. }
  2089. }`,
  2090. }, {
  2091. desc: "EmitUnpopulated: oneof fields",
  2092. mo: protojson.MarshalOptions{EmitUnpopulated: true},
  2093. input: &pb3.Oneofs{},
  2094. want: `{}`,
  2095. }, {
  2096. desc: "EmitUnpopulated: extensions",
  2097. mo: protojson.MarshalOptions{EmitUnpopulated: true},
  2098. input: func() proto.Message {
  2099. m := &pb2.Extensions{}
  2100. proto.SetExtension(m, pb2.E_OptExtNested, &pb2.Nested{})
  2101. proto.SetExtension(m, pb2.E_RptExtNested, []*pb2.Nested{
  2102. nil,
  2103. {},
  2104. })
  2105. return m
  2106. }(),
  2107. want: `{
  2108. "optString": null,
  2109. "optBool": null,
  2110. "optInt32": null,
  2111. "[pb2.opt_ext_nested]": {
  2112. "optString": null,
  2113. "optNested": null
  2114. },
  2115. "[pb2.rpt_ext_nested]": [
  2116. {
  2117. "optString": null,
  2118. "optNested": null
  2119. },
  2120. {
  2121. "optString": null,
  2122. "optNested": null
  2123. }
  2124. ]
  2125. }`,
  2126. }, {
  2127. desc: "UseEnumNumbers in singular field",
  2128. mo: protojson.MarshalOptions{UseEnumNumbers: true},
  2129. input: &pb2.Enums{
  2130. OptEnum: pb2.Enum_ONE.Enum(),
  2131. OptNestedEnum: pb2.Enums_UNO.Enum(),
  2132. },
  2133. want: `{
  2134. "optEnum": 1,
  2135. "optNestedEnum": 1
  2136. }`,
  2137. }, {
  2138. desc: "UseEnumNumbers in repeated field",
  2139. mo: protojson.MarshalOptions{UseEnumNumbers: true},
  2140. input: &pb2.Enums{
  2141. RptEnum: []pb2.Enum{pb2.Enum_ONE, 2, pb2.Enum_TEN, 42},
  2142. RptNestedEnum: []pb2.Enums_NestedEnum{pb2.Enums_UNO, pb2.Enums_DOS, 47},
  2143. },
  2144. want: `{
  2145. "rptEnum": [
  2146. 1,
  2147. 2,
  2148. 10,
  2149. 42
  2150. ],
  2151. "rptNestedEnum": [
  2152. 1,
  2153. 2,
  2154. 47
  2155. ]
  2156. }`,
  2157. }, {
  2158. desc: "UseEnumNumbers in map field",
  2159. mo: protojson.MarshalOptions{UseEnumNumbers: true},
  2160. input: &pb3.Maps{
  2161. Uint64ToEnum: map[uint64]pb3.Enum{
  2162. 1: pb3.Enum_ONE,
  2163. 2: pb3.Enum_TWO,
  2164. 10: pb3.Enum_TEN,
  2165. 47: 47,
  2166. },
  2167. },
  2168. want: `{
  2169. "uint64ToEnum": {
  2170. "1": 1,
  2171. "2": 2,
  2172. "10": 10,
  2173. "47": 47
  2174. }
  2175. }`,
  2176. }, {
  2177. desc: "UseProtoNames",
  2178. mo: protojson.MarshalOptions{UseProtoNames: true},
  2179. input: &pb2.Nests{
  2180. OptNested: &pb2.Nested{},
  2181. Optgroup: &pb2.Nests_OptGroup{
  2182. OptString: proto.String("inside a group"),
  2183. OptNested: &pb2.Nested{
  2184. OptString: proto.String("nested message inside a group"),
  2185. },
  2186. Optnestedgroup: &pb2.Nests_OptGroup_OptNestedGroup{
  2187. OptFixed32: proto.Uint32(47),
  2188. },
  2189. },
  2190. Rptgroup: []*pb2.Nests_RptGroup{
  2191. {
  2192. RptString: []string{"hello", "world"},
  2193. },
  2194. },
  2195. },
  2196. want: `{
  2197. "opt_nested": {},
  2198. "OptGroup": {
  2199. "opt_string": "inside a group",
  2200. "opt_nested": {
  2201. "opt_string": "nested message inside a group"
  2202. },
  2203. "OptNestedGroup": {
  2204. "opt_fixed32": 47
  2205. }
  2206. },
  2207. "RptGroup": [
  2208. {
  2209. "rpt_string": [
  2210. "hello",
  2211. "world"
  2212. ]
  2213. }
  2214. ]
  2215. }`,
  2216. }}
  2217. for _, tt := range tests {
  2218. tt := tt
  2219. if tt.skip {
  2220. continue
  2221. }
  2222. t.Run(tt.desc, func(t *testing.T) {
  2223. // Use 2-space indentation on all MarshalOptions.
  2224. tt.mo.Indent = " "
  2225. b, err := tt.mo.Marshal(tt.input)
  2226. if err != nil && !tt.wantErr {
  2227. t.Errorf("Marshal() returned error: %v\n", err)
  2228. }
  2229. if err == nil && tt.wantErr {
  2230. t.Errorf("Marshal() got nil error, want error\n")
  2231. }
  2232. got := string(b)
  2233. if got != tt.want {
  2234. t.Errorf("Marshal()\n<got>\n%v\n<want>\n%v\n", got, tt.want)
  2235. if diff := cmp.Diff(tt.want, got); diff != "" {
  2236. t.Errorf("Marshal() diff -want +got\n%v\n", diff)
  2237. }
  2238. }
  2239. })
  2240. }
  2241. }