encode_test.go 26 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135
  1. // Copyright 2018 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 textpb_test
  5. import (
  6. "encoding/hex"
  7. "math"
  8. "strings"
  9. "testing"
  10. protoV1 "github.com/golang/protobuf/proto"
  11. "github.com/golang/protobuf/protoapi"
  12. "github.com/golang/protobuf/v2/encoding/textpb"
  13. "github.com/golang/protobuf/v2/internal/detrand"
  14. "github.com/golang/protobuf/v2/internal/encoding/pack"
  15. "github.com/golang/protobuf/v2/internal/encoding/wire"
  16. "github.com/golang/protobuf/v2/internal/impl"
  17. "github.com/golang/protobuf/v2/internal/legacy"
  18. "github.com/golang/protobuf/v2/internal/scalar"
  19. "github.com/golang/protobuf/v2/proto"
  20. preg "github.com/golang/protobuf/v2/reflect/protoregistry"
  21. "github.com/google/go-cmp/cmp"
  22. "github.com/google/go-cmp/cmp/cmpopts"
  23. "github.com/golang/protobuf/v2/encoding/testprotos/pb2"
  24. "github.com/golang/protobuf/v2/encoding/testprotos/pb3"
  25. knownpb "github.com/golang/protobuf/v2/types/known"
  26. )
  27. func init() {
  28. // Disable detrand to enable direct comparisons on outputs.
  29. detrand.Disable()
  30. }
  31. // splitLines is a cmpopts.Option for comparing strings with line breaks.
  32. var splitLines = cmpopts.AcyclicTransformer("SplitLines", func(s string) []string {
  33. return strings.Split(s, "\n")
  34. })
  35. func pb2Enum(i int32) *pb2.Enum {
  36. p := new(pb2.Enum)
  37. *p = pb2.Enum(i)
  38. return p
  39. }
  40. func pb2Enums_NestedEnum(i int32) *pb2.Enums_NestedEnum {
  41. p := new(pb2.Enums_NestedEnum)
  42. *p = pb2.Enums_NestedEnum(i)
  43. return p
  44. }
  45. func setExtension(m proto.Message, xd *protoapi.ExtensionDesc, val interface{}) {
  46. xt := legacy.Export{}.ExtensionTypeFromDesc(xd)
  47. knownFields := m.ProtoReflect().KnownFields()
  48. extTypes := knownFields.ExtensionTypes()
  49. extTypes.Register(xt)
  50. if val == nil {
  51. return
  52. }
  53. pval := xt.ValueOf(val)
  54. knownFields.Set(wire.Number(xd.Field), pval)
  55. }
  56. func wrapV1Message(any *knownpb.Any) proto.Message {
  57. return impl.Export{}.MessageOf(any).Interface()
  58. }
  59. // dhex decodes a hex-string and returns the bytes and panics if s is invalid.
  60. func dhex(s string) []byte {
  61. b, err := hex.DecodeString(s)
  62. if err != nil {
  63. panic(err)
  64. }
  65. return b
  66. }
  67. func TestMarshal(t *testing.T) {
  68. tests := []struct {
  69. desc string
  70. mo textpb.MarshalOptions
  71. input proto.Message
  72. want string
  73. wantErr bool
  74. }{{
  75. desc: "proto2 optional scalars not set",
  76. input: &pb2.Scalars{},
  77. want: "\n",
  78. }, {
  79. desc: "proto3 scalars not set",
  80. input: &pb3.Scalars{},
  81. want: "\n",
  82. }, {
  83. desc: "proto2 optional scalars set to zero values",
  84. input: &pb2.Scalars{
  85. OptBool: scalar.Bool(false),
  86. OptInt32: scalar.Int32(0),
  87. OptInt64: scalar.Int64(0),
  88. OptUint32: scalar.Uint32(0),
  89. OptUint64: scalar.Uint64(0),
  90. OptSint32: scalar.Int32(0),
  91. OptSint64: scalar.Int64(0),
  92. OptFixed32: scalar.Uint32(0),
  93. OptFixed64: scalar.Uint64(0),
  94. OptSfixed32: scalar.Int32(0),
  95. OptSfixed64: scalar.Int64(0),
  96. OptFloat: scalar.Float32(0),
  97. OptDouble: scalar.Float64(0),
  98. OptBytes: []byte{},
  99. OptString: scalar.String(""),
  100. },
  101. want: `opt_bool: false
  102. opt_int32: 0
  103. opt_int64: 0
  104. opt_uint32: 0
  105. opt_uint64: 0
  106. opt_sint32: 0
  107. opt_sint64: 0
  108. opt_fixed32: 0
  109. opt_fixed64: 0
  110. opt_sfixed32: 0
  111. opt_sfixed64: 0
  112. opt_float: 0
  113. opt_double: 0
  114. opt_bytes: ""
  115. opt_string: ""
  116. `,
  117. }, {
  118. desc: "proto3 scalars set to zero values",
  119. input: &pb3.Scalars{
  120. SBool: false,
  121. SInt32: 0,
  122. SInt64: 0,
  123. SUint32: 0,
  124. SUint64: 0,
  125. SSint32: 0,
  126. SSint64: 0,
  127. SFixed32: 0,
  128. SFixed64: 0,
  129. SSfixed32: 0,
  130. SSfixed64: 0,
  131. SFloat: 0,
  132. SDouble: 0,
  133. SBytes: []byte{},
  134. SString: "",
  135. },
  136. want: "\n",
  137. }, {
  138. desc: "proto2 optional scalars set to some values",
  139. input: &pb2.Scalars{
  140. OptBool: scalar.Bool(true),
  141. OptInt32: scalar.Int32(0xff),
  142. OptInt64: scalar.Int64(0xdeadbeef),
  143. OptUint32: scalar.Uint32(47),
  144. OptUint64: scalar.Uint64(0xdeadbeef),
  145. OptSint32: scalar.Int32(-1001),
  146. OptSint64: scalar.Int64(-0xffff),
  147. OptFixed64: scalar.Uint64(64),
  148. OptSfixed32: scalar.Int32(-32),
  149. OptFloat: scalar.Float32(1.02),
  150. OptDouble: scalar.Float64(1.0199999809265137),
  151. OptBytes: []byte("\xe8\xb0\xb7\xe6\xad\x8c"),
  152. OptString: scalar.String("谷歌"),
  153. },
  154. want: `opt_bool: true
  155. opt_int32: 255
  156. opt_int64: 3735928559
  157. opt_uint32: 47
  158. opt_uint64: 3735928559
  159. opt_sint32: -1001
  160. opt_sint64: -65535
  161. opt_fixed64: 64
  162. opt_sfixed32: -32
  163. opt_float: 1.02
  164. opt_double: 1.0199999809265137
  165. opt_bytes: "谷歌"
  166. opt_string: "谷歌"
  167. `,
  168. }, {
  169. desc: "float nan",
  170. input: &pb3.Scalars{
  171. SFloat: float32(math.NaN()),
  172. },
  173. want: "s_float: nan\n",
  174. }, {
  175. desc: "float positive infinity",
  176. input: &pb3.Scalars{
  177. SFloat: float32(math.Inf(1)),
  178. },
  179. want: "s_float: inf\n",
  180. }, {
  181. desc: "float negative infinity",
  182. input: &pb3.Scalars{
  183. SFloat: float32(math.Inf(-1)),
  184. },
  185. want: "s_float: -inf\n",
  186. }, {
  187. desc: "double nan",
  188. input: &pb3.Scalars{
  189. SDouble: math.NaN(),
  190. },
  191. want: "s_double: nan\n",
  192. }, {
  193. desc: "double positive infinity",
  194. input: &pb3.Scalars{
  195. SDouble: math.Inf(1),
  196. },
  197. want: "s_double: inf\n",
  198. }, {
  199. desc: "double negative infinity",
  200. input: &pb3.Scalars{
  201. SDouble: math.Inf(-1),
  202. },
  203. want: "s_double: -inf\n",
  204. }, {
  205. desc: "proto2 enum not set",
  206. input: &pb2.Enums{},
  207. want: "\n",
  208. }, {
  209. desc: "proto2 enum set to zero value",
  210. input: &pb2.Enums{
  211. OptEnum: pb2Enum(0),
  212. OptNestedEnum: pb2Enums_NestedEnum(0),
  213. },
  214. want: `opt_enum: 0
  215. opt_nested_enum: 0
  216. `,
  217. }, {
  218. desc: "proto2 enum",
  219. input: &pb2.Enums{
  220. OptEnum: pb2.Enum_ONE.Enum(),
  221. OptNestedEnum: pb2.Enums_UNO.Enum(),
  222. },
  223. want: `opt_enum: ONE
  224. opt_nested_enum: UNO
  225. `,
  226. }, {
  227. desc: "proto2 enum set to numeric values",
  228. input: &pb2.Enums{
  229. OptEnum: pb2Enum(2),
  230. OptNestedEnum: pb2Enums_NestedEnum(2),
  231. },
  232. want: `opt_enum: TWO
  233. opt_nested_enum: DOS
  234. `,
  235. }, {
  236. desc: "proto2 enum set to unnamed numeric values",
  237. input: &pb2.Enums{
  238. OptEnum: pb2Enum(101),
  239. OptNestedEnum: pb2Enums_NestedEnum(-101),
  240. },
  241. want: `opt_enum: 101
  242. opt_nested_enum: -101
  243. `,
  244. }, {
  245. desc: "proto3 enum not set",
  246. input: &pb3.Enums{},
  247. want: "\n",
  248. }, {
  249. desc: "proto3 enum set to zero value",
  250. input: &pb3.Enums{
  251. SEnum: pb3.Enum_ZERO,
  252. SNestedEnum: pb3.Enums_CERO,
  253. },
  254. want: "\n",
  255. }, {
  256. desc: "proto3 enum",
  257. input: &pb3.Enums{
  258. SEnum: pb3.Enum_ONE,
  259. SNestedEnum: pb3.Enums_UNO,
  260. },
  261. want: `s_enum: ONE
  262. s_nested_enum: UNO
  263. `,
  264. }, {
  265. desc: "proto3 enum set to numeric values",
  266. input: &pb3.Enums{
  267. SEnum: 2,
  268. SNestedEnum: 2,
  269. },
  270. want: `s_enum: TWO
  271. s_nested_enum: DOS
  272. `,
  273. }, {
  274. desc: "proto3 enum set to unnamed numeric values",
  275. input: &pb3.Enums{
  276. SEnum: -47,
  277. SNestedEnum: 47,
  278. },
  279. want: `s_enum: -47
  280. s_nested_enum: 47
  281. `,
  282. }, {
  283. desc: "proto2 nested message not set",
  284. input: &pb2.Nests{},
  285. want: "\n",
  286. }, {
  287. desc: "proto2 nested message set to empty",
  288. input: &pb2.Nests{
  289. OptNested: &pb2.Nested{},
  290. Optgroup: &pb2.Nests_OptGroup{},
  291. },
  292. want: `opt_nested: {}
  293. OptGroup: {}
  294. `,
  295. }, {
  296. desc: "proto2 nested messages",
  297. input: &pb2.Nests{
  298. OptNested: &pb2.Nested{
  299. OptString: scalar.String("nested message"),
  300. OptNested: &pb2.Nested{
  301. OptString: scalar.String("another nested message"),
  302. },
  303. },
  304. },
  305. want: `opt_nested: {
  306. opt_string: "nested message"
  307. opt_nested: {
  308. opt_string: "another nested message"
  309. }
  310. }
  311. `,
  312. }, {
  313. desc: "proto2 groups",
  314. input: &pb2.Nests{
  315. Optgroup: &pb2.Nests_OptGroup{
  316. OptString: scalar.String("inside a group"),
  317. OptNested: &pb2.Nested{
  318. OptString: scalar.String("nested message inside a group"),
  319. },
  320. Optnestedgroup: &pb2.Nests_OptGroup_OptNestedGroup{
  321. OptFixed32: scalar.Uint32(47),
  322. },
  323. },
  324. },
  325. want: `OptGroup: {
  326. opt_string: "inside a group"
  327. opt_nested: {
  328. opt_string: "nested message inside a group"
  329. }
  330. OptNestedGroup: {
  331. opt_fixed32: 47
  332. }
  333. }
  334. `,
  335. }, {
  336. desc: "proto3 nested message not set",
  337. input: &pb3.Nests{},
  338. want: "\n",
  339. }, {
  340. desc: "proto3 nested message set to empty",
  341. input: &pb3.Nests{
  342. SNested: &pb3.Nested{},
  343. },
  344. want: "s_nested: {}\n",
  345. }, {
  346. desc: "proto3 nested message",
  347. input: &pb3.Nests{
  348. SNested: &pb3.Nested{
  349. SString: "nested message",
  350. SNested: &pb3.Nested{
  351. SString: "another nested message",
  352. },
  353. },
  354. },
  355. want: `s_nested: {
  356. s_string: "nested message"
  357. s_nested: {
  358. s_string: "another nested message"
  359. }
  360. }
  361. `,
  362. }, {
  363. desc: "oneof not set",
  364. input: &pb3.Oneofs{},
  365. want: "\n",
  366. }, {
  367. desc: "oneof set to empty string",
  368. input: &pb3.Oneofs{
  369. Union: &pb3.Oneofs_OneofString{},
  370. },
  371. want: `oneof_string: ""
  372. `,
  373. }, {
  374. desc: "oneof set to string",
  375. input: &pb3.Oneofs{
  376. Union: &pb3.Oneofs_OneofString{
  377. OneofString: "hello",
  378. },
  379. },
  380. want: `oneof_string: "hello"
  381. `,
  382. }, {
  383. desc: "oneof set to enum",
  384. input: &pb3.Oneofs{
  385. Union: &pb3.Oneofs_OneofEnum{
  386. OneofEnum: pb3.Enum_ZERO,
  387. },
  388. },
  389. want: `oneof_enum: ZERO
  390. `,
  391. }, {
  392. desc: "oneof set to empty message",
  393. input: &pb3.Oneofs{
  394. Union: &pb3.Oneofs_OneofNested{
  395. OneofNested: &pb3.Nested{},
  396. },
  397. },
  398. want: "oneof_nested: {}\n",
  399. }, {
  400. desc: "oneof set to message",
  401. input: &pb3.Oneofs{
  402. Union: &pb3.Oneofs_OneofNested{
  403. OneofNested: &pb3.Nested{
  404. SString: "nested message",
  405. },
  406. },
  407. },
  408. want: `oneof_nested: {
  409. s_string: "nested message"
  410. }
  411. `,
  412. }, {
  413. desc: "repeated fields not set",
  414. input: &pb2.Repeats{},
  415. want: "\n",
  416. }, {
  417. desc: "repeated fields set to empty slices",
  418. input: &pb2.Repeats{
  419. RptBool: []bool{},
  420. RptInt32: []int32{},
  421. RptInt64: []int64{},
  422. RptUint32: []uint32{},
  423. RptUint64: []uint64{},
  424. RptFloat: []float32{},
  425. RptDouble: []float64{},
  426. RptBytes: [][]byte{},
  427. },
  428. want: "\n",
  429. }, {
  430. desc: "repeated fields set to some values",
  431. input: &pb2.Repeats{
  432. RptBool: []bool{true, false, true, true},
  433. RptInt32: []int32{1, 6, 0, 0},
  434. RptInt64: []int64{-64, 47},
  435. RptUint32: []uint32{0xff, 0xffff},
  436. RptUint64: []uint64{0xdeadbeef},
  437. RptFloat: []float32{float32(math.NaN()), float32(math.Inf(1)), float32(math.Inf(-1)), 1.034},
  438. RptDouble: []float64{math.NaN(), math.Inf(1), math.Inf(-1), 1.23e-308},
  439. RptString: []string{"hello", "世界"},
  440. RptBytes: [][]byte{
  441. []byte("hello"),
  442. []byte("\xe4\xb8\x96\xe7\x95\x8c"),
  443. },
  444. },
  445. want: `rpt_bool: true
  446. rpt_bool: false
  447. rpt_bool: true
  448. rpt_bool: true
  449. rpt_int32: 1
  450. rpt_int32: 6
  451. rpt_int32: 0
  452. rpt_int32: 0
  453. rpt_int64: -64
  454. rpt_int64: 47
  455. rpt_uint32: 255
  456. rpt_uint32: 65535
  457. rpt_uint64: 3735928559
  458. rpt_float: nan
  459. rpt_float: inf
  460. rpt_float: -inf
  461. rpt_float: 1.034
  462. rpt_double: nan
  463. rpt_double: inf
  464. rpt_double: -inf
  465. rpt_double: 1.23e-308
  466. rpt_string: "hello"
  467. rpt_string: "世界"
  468. rpt_bytes: "hello"
  469. rpt_bytes: "世界"
  470. `,
  471. }, {
  472. desc: "repeated enums",
  473. input: &pb2.Enums{
  474. RptEnum: []pb2.Enum{pb2.Enum_ONE, 2, pb2.Enum_TEN, 42},
  475. RptNestedEnum: []pb2.Enums_NestedEnum{2, 47, 10},
  476. },
  477. want: `rpt_enum: ONE
  478. rpt_enum: TWO
  479. rpt_enum: TEN
  480. rpt_enum: 42
  481. rpt_nested_enum: DOS
  482. rpt_nested_enum: 47
  483. rpt_nested_enum: DIEZ
  484. `,
  485. }, {
  486. desc: "repeated messages set to empty",
  487. input: &pb2.Nests{
  488. RptNested: []*pb2.Nested{},
  489. Rptgroup: []*pb2.Nests_RptGroup{},
  490. },
  491. want: "\n",
  492. }, {
  493. desc: "repeated messages",
  494. input: &pb2.Nests{
  495. RptNested: []*pb2.Nested{
  496. {
  497. OptString: scalar.String("repeat nested one"),
  498. },
  499. {
  500. OptString: scalar.String("repeat nested two"),
  501. OptNested: &pb2.Nested{
  502. OptString: scalar.String("inside repeat nested two"),
  503. },
  504. },
  505. {},
  506. },
  507. },
  508. want: `rpt_nested: {
  509. opt_string: "repeat nested one"
  510. }
  511. rpt_nested: {
  512. opt_string: "repeat nested two"
  513. opt_nested: {
  514. opt_string: "inside repeat nested two"
  515. }
  516. }
  517. rpt_nested: {}
  518. `,
  519. }, {
  520. desc: "repeated messages contains nil value",
  521. input: &pb2.Nests{
  522. RptNested: []*pb2.Nested{nil, {}},
  523. },
  524. want: `rpt_nested: {}
  525. rpt_nested: {}
  526. `,
  527. }, {
  528. desc: "repeated groups",
  529. input: &pb2.Nests{
  530. Rptgroup: []*pb2.Nests_RptGroup{
  531. {
  532. RptString: []string{"hello", "world"},
  533. },
  534. {},
  535. nil,
  536. },
  537. },
  538. want: `RptGroup: {
  539. rpt_string: "hello"
  540. rpt_string: "world"
  541. }
  542. RptGroup: {}
  543. RptGroup: {}
  544. `,
  545. }, {
  546. desc: "map fields not set",
  547. input: &pb3.Maps{},
  548. want: "\n",
  549. }, {
  550. desc: "map fields set to empty",
  551. input: &pb3.Maps{
  552. Int32ToStr: map[int32]string{},
  553. BoolToUint32: map[bool]uint32{},
  554. Uint64ToEnum: map[uint64]pb3.Enum{},
  555. StrToNested: map[string]*pb3.Nested{},
  556. StrToOneofs: map[string]*pb3.Oneofs{},
  557. },
  558. want: "\n",
  559. }, {
  560. desc: "map fields 1",
  561. input: &pb3.Maps{
  562. Int32ToStr: map[int32]string{
  563. -101: "-101",
  564. 0xff: "0xff",
  565. 0: "zero",
  566. },
  567. BoolToUint32: map[bool]uint32{
  568. true: 42,
  569. false: 101,
  570. },
  571. },
  572. want: `int32_to_str: {
  573. key: -101
  574. value: "-101"
  575. }
  576. int32_to_str: {
  577. key: 0
  578. value: "zero"
  579. }
  580. int32_to_str: {
  581. key: 255
  582. value: "0xff"
  583. }
  584. bool_to_uint32: {
  585. key: false
  586. value: 101
  587. }
  588. bool_to_uint32: {
  589. key: true
  590. value: 42
  591. }
  592. `,
  593. }, {
  594. desc: "map fields 2",
  595. input: &pb3.Maps{
  596. Uint64ToEnum: map[uint64]pb3.Enum{
  597. 1: pb3.Enum_ONE,
  598. 2: pb3.Enum_TWO,
  599. 10: pb3.Enum_TEN,
  600. 47: 47,
  601. },
  602. },
  603. want: `uint64_to_enum: {
  604. key: 1
  605. value: ONE
  606. }
  607. uint64_to_enum: {
  608. key: 2
  609. value: TWO
  610. }
  611. uint64_to_enum: {
  612. key: 10
  613. value: TEN
  614. }
  615. uint64_to_enum: {
  616. key: 47
  617. value: 47
  618. }
  619. `,
  620. }, {
  621. desc: "map fields 3",
  622. input: &pb3.Maps{
  623. StrToNested: map[string]*pb3.Nested{
  624. "nested": &pb3.Nested{
  625. SString: "nested in a map",
  626. },
  627. },
  628. },
  629. want: `str_to_nested: {
  630. key: "nested"
  631. value: {
  632. s_string: "nested in a map"
  633. }
  634. }
  635. `,
  636. }, {
  637. desc: "map fields 4",
  638. input: &pb3.Maps{
  639. StrToOneofs: map[string]*pb3.Oneofs{
  640. "string": &pb3.Oneofs{
  641. Union: &pb3.Oneofs_OneofString{
  642. OneofString: "hello",
  643. },
  644. },
  645. "nested": &pb3.Oneofs{
  646. Union: &pb3.Oneofs_OneofNested{
  647. OneofNested: &pb3.Nested{
  648. SString: "nested oneof in map field value",
  649. },
  650. },
  651. },
  652. },
  653. },
  654. want: `str_to_oneofs: {
  655. key: "nested"
  656. value: {
  657. oneof_nested: {
  658. s_string: "nested oneof in map field value"
  659. }
  660. }
  661. }
  662. str_to_oneofs: {
  663. key: "string"
  664. value: {
  665. oneof_string: "hello"
  666. }
  667. }
  668. `,
  669. }, {
  670. desc: "map field contains nil value",
  671. input: &pb3.Maps{
  672. StrToNested: map[string]*pb3.Nested{
  673. "nil": nil,
  674. },
  675. },
  676. want: `str_to_nested: {
  677. key: "nil"
  678. value: {}
  679. }
  680. `,
  681. }, {
  682. desc: "proto2 required fields not set",
  683. input: &pb2.Requireds{},
  684. want: "\n",
  685. wantErr: true,
  686. }, {
  687. desc: "proto2 required fields partially set",
  688. input: &pb2.Requireds{
  689. ReqBool: scalar.Bool(false),
  690. ReqSfixed64: scalar.Int64(0xbeefcafe),
  691. ReqDouble: scalar.Float64(math.NaN()),
  692. ReqString: scalar.String("hello"),
  693. ReqEnum: pb2.Enum_ONE.Enum(),
  694. },
  695. want: `req_bool: false
  696. req_sfixed64: 3203386110
  697. req_double: nan
  698. req_string: "hello"
  699. req_enum: ONE
  700. `,
  701. wantErr: true,
  702. }, {
  703. desc: "proto2 required fields all set",
  704. input: &pb2.Requireds{
  705. ReqBool: scalar.Bool(false),
  706. ReqSfixed64: scalar.Int64(0),
  707. ReqDouble: scalar.Float64(1.23),
  708. ReqString: scalar.String(""),
  709. ReqEnum: pb2.Enum_ONE.Enum(),
  710. ReqNested: &pb2.Nested{},
  711. },
  712. want: `req_bool: false
  713. req_sfixed64: 0
  714. req_double: 1.23
  715. req_string: ""
  716. req_enum: ONE
  717. req_nested: {}
  718. `,
  719. }, {
  720. desc: "indirect required field",
  721. input: &pb2.IndirectRequired{
  722. OptNested: &pb2.NestedWithRequired{},
  723. },
  724. want: "opt_nested: {}\n",
  725. wantErr: true,
  726. }, {
  727. desc: "indirect required field in empty repeated",
  728. input: &pb2.IndirectRequired{
  729. RptNested: []*pb2.NestedWithRequired{},
  730. },
  731. want: "\n",
  732. }, {
  733. desc: "indirect required field in repeated",
  734. input: &pb2.IndirectRequired{
  735. RptNested: []*pb2.NestedWithRequired{
  736. &pb2.NestedWithRequired{},
  737. },
  738. },
  739. want: "rpt_nested: {}\n",
  740. wantErr: true,
  741. }, {
  742. desc: "indirect required field in empty map",
  743. input: &pb2.IndirectRequired{
  744. StrToNested: map[string]*pb2.NestedWithRequired{},
  745. },
  746. want: "\n",
  747. }, {
  748. desc: "indirect required field in map",
  749. input: &pb2.IndirectRequired{
  750. StrToNested: map[string]*pb2.NestedWithRequired{
  751. "fail": &pb2.NestedWithRequired{},
  752. },
  753. },
  754. want: `str_to_nested: {
  755. key: "fail"
  756. value: {}
  757. }
  758. `,
  759. wantErr: true,
  760. }, {
  761. desc: "indirect required field in oneof",
  762. input: &pb2.IndirectRequired{
  763. Union: &pb2.IndirectRequired_OneofNested{
  764. OneofNested: &pb2.NestedWithRequired{},
  765. },
  766. },
  767. want: "oneof_nested: {}\n",
  768. wantErr: true,
  769. }, {
  770. desc: "unknown varint and fixed types",
  771. input: &pb2.Scalars{
  772. OptString: scalar.String("this message contains unknown fields"),
  773. XXX_unrecognized: pack.Message{
  774. pack.Tag{101, pack.VarintType}, pack.Bool(true),
  775. pack.Tag{102, pack.VarintType}, pack.Varint(0xff),
  776. pack.Tag{103, pack.Fixed32Type}, pack.Uint32(47),
  777. pack.Tag{104, pack.Fixed64Type}, pack.Int64(0xdeadbeef),
  778. }.Marshal(),
  779. },
  780. want: `opt_string: "this message contains unknown fields"
  781. 101: 1
  782. 102: 255
  783. 103: 47
  784. 104: 3735928559
  785. `,
  786. }, {
  787. desc: "unknown length-delimited",
  788. input: &pb2.Scalars{
  789. XXX_unrecognized: pack.Message{
  790. pack.Tag{101, pack.BytesType}, pack.LengthPrefix{pack.Bool(true), pack.Bool(false)},
  791. pack.Tag{102, pack.BytesType}, pack.String("hello world"),
  792. pack.Tag{103, pack.BytesType}, pack.Bytes("\xe4\xb8\x96\xe7\x95\x8c"),
  793. }.Marshal(),
  794. },
  795. want: `101: "\x01\x00"
  796. 102: "hello world"
  797. 103: "世界"
  798. `,
  799. }, {
  800. desc: "unknown group type",
  801. input: &pb2.Scalars{
  802. XXX_unrecognized: pack.Message{
  803. pack.Tag{101, pack.StartGroupType}, pack.Tag{101, pack.EndGroupType},
  804. pack.Tag{102, pack.StartGroupType},
  805. pack.Tag{101, pack.VarintType}, pack.Bool(false),
  806. pack.Tag{102, pack.BytesType}, pack.String("inside a group"),
  807. pack.Tag{102, pack.EndGroupType},
  808. }.Marshal(),
  809. },
  810. want: `101: {}
  811. 102: {
  812. 101: 0
  813. 102: "inside a group"
  814. }
  815. `,
  816. }, {
  817. desc: "unknown unpack repeated field",
  818. input: &pb2.Scalars{
  819. XXX_unrecognized: pack.Message{
  820. pack.Tag{101, pack.BytesType}, pack.LengthPrefix{pack.Bool(true), pack.Bool(false), pack.Bool(true)},
  821. pack.Tag{102, pack.BytesType}, pack.String("hello"),
  822. pack.Tag{101, pack.VarintType}, pack.Bool(true),
  823. pack.Tag{102, pack.BytesType}, pack.String("世界"),
  824. }.Marshal(),
  825. },
  826. want: `101: "\x01\x00\x01"
  827. 101: 1
  828. 102: "hello"
  829. 102: "世界"
  830. `,
  831. }, {
  832. desc: "extensions of non-repeated fields",
  833. input: func() proto.Message {
  834. m := &pb2.Extensions{
  835. OptString: scalar.String("non-extension field"),
  836. OptBool: scalar.Bool(true),
  837. OptInt32: scalar.Int32(42),
  838. }
  839. setExtension(m, pb2.E_OptExtBool, true)
  840. setExtension(m, pb2.E_OptExtString, "extension field")
  841. setExtension(m, pb2.E_OptExtEnum, pb2.Enum_TEN)
  842. setExtension(m, pb2.E_OptExtNested, &pb2.Nested{
  843. OptString: scalar.String("nested in an extension"),
  844. OptNested: &pb2.Nested{
  845. OptString: scalar.String("another nested in an extension"),
  846. },
  847. })
  848. return m
  849. }(),
  850. want: `opt_string: "non-extension field"
  851. opt_bool: true
  852. opt_int32: 42
  853. [pb2.opt_ext_bool]: true
  854. [pb2.opt_ext_enum]: TEN
  855. [pb2.opt_ext_nested]: {
  856. opt_string: "nested in an extension"
  857. opt_nested: {
  858. opt_string: "another nested in an extension"
  859. }
  860. }
  861. [pb2.opt_ext_string]: "extension field"
  862. `,
  863. }, {
  864. desc: "extension message field set to nil",
  865. input: func() proto.Message {
  866. m := &pb2.Extensions{}
  867. setExtension(m, pb2.E_OptExtNested, nil)
  868. return m
  869. }(),
  870. want: "\n",
  871. }, {
  872. desc: "extensions of repeated fields",
  873. input: func() proto.Message {
  874. m := &pb2.Extensions{}
  875. setExtension(m, pb2.E_RptExtEnum, &[]pb2.Enum{pb2.Enum_TEN, 101, pb2.Enum_ONE})
  876. setExtension(m, pb2.E_RptExtFixed32, &[]uint32{42, 47})
  877. setExtension(m, pb2.E_RptExtNested, &[]*pb2.Nested{
  878. &pb2.Nested{OptString: scalar.String("one")},
  879. &pb2.Nested{OptString: scalar.String("two")},
  880. &pb2.Nested{OptString: scalar.String("three")},
  881. })
  882. return m
  883. }(),
  884. want: `[pb2.rpt_ext_enum]: TEN
  885. [pb2.rpt_ext_enum]: 101
  886. [pb2.rpt_ext_enum]: ONE
  887. [pb2.rpt_ext_fixed32]: 42
  888. [pb2.rpt_ext_fixed32]: 47
  889. [pb2.rpt_ext_nested]: {
  890. opt_string: "one"
  891. }
  892. [pb2.rpt_ext_nested]: {
  893. opt_string: "two"
  894. }
  895. [pb2.rpt_ext_nested]: {
  896. opt_string: "three"
  897. }
  898. `,
  899. }, {
  900. desc: "extensions of non-repeated fields in another message",
  901. input: func() proto.Message {
  902. m := &pb2.Extensions{}
  903. setExtension(m, pb2.E_ExtensionsContainer_OptExtBool, true)
  904. setExtension(m, pb2.E_ExtensionsContainer_OptExtString, "extension field")
  905. setExtension(m, pb2.E_ExtensionsContainer_OptExtEnum, pb2.Enum_TEN)
  906. setExtension(m, pb2.E_ExtensionsContainer_OptExtNested, &pb2.Nested{
  907. OptString: scalar.String("nested in an extension"),
  908. OptNested: &pb2.Nested{
  909. OptString: scalar.String("another nested in an extension"),
  910. },
  911. })
  912. return m
  913. }(),
  914. want: `[pb2.ExtensionsContainer.opt_ext_bool]: true
  915. [pb2.ExtensionsContainer.opt_ext_enum]: TEN
  916. [pb2.ExtensionsContainer.opt_ext_nested]: {
  917. opt_string: "nested in an extension"
  918. opt_nested: {
  919. opt_string: "another nested in an extension"
  920. }
  921. }
  922. [pb2.ExtensionsContainer.opt_ext_string]: "extension field"
  923. `,
  924. }, {
  925. desc: "extensions of repeated fields in another message",
  926. input: func() proto.Message {
  927. m := &pb2.Extensions{
  928. OptString: scalar.String("non-extension field"),
  929. OptBool: scalar.Bool(true),
  930. OptInt32: scalar.Int32(42),
  931. }
  932. setExtension(m, pb2.E_ExtensionsContainer_RptExtEnum, &[]pb2.Enum{pb2.Enum_TEN, 101, pb2.Enum_ONE})
  933. setExtension(m, pb2.E_ExtensionsContainer_RptExtString, &[]string{"hello", "world"})
  934. setExtension(m, pb2.E_ExtensionsContainer_RptExtNested, &[]*pb2.Nested{
  935. &pb2.Nested{OptString: scalar.String("one")},
  936. &pb2.Nested{OptString: scalar.String("two")},
  937. &pb2.Nested{OptString: scalar.String("three")},
  938. })
  939. return m
  940. }(),
  941. want: `opt_string: "non-extension field"
  942. opt_bool: true
  943. opt_int32: 42
  944. [pb2.ExtensionsContainer.rpt_ext_enum]: TEN
  945. [pb2.ExtensionsContainer.rpt_ext_enum]: 101
  946. [pb2.ExtensionsContainer.rpt_ext_enum]: ONE
  947. [pb2.ExtensionsContainer.rpt_ext_nested]: {
  948. opt_string: "one"
  949. }
  950. [pb2.ExtensionsContainer.rpt_ext_nested]: {
  951. opt_string: "two"
  952. }
  953. [pb2.ExtensionsContainer.rpt_ext_nested]: {
  954. opt_string: "three"
  955. }
  956. [pb2.ExtensionsContainer.rpt_ext_string]: "hello"
  957. [pb2.ExtensionsContainer.rpt_ext_string]: "world"
  958. `,
  959. }, {
  960. desc: "MessageSet",
  961. input: func() proto.Message {
  962. m := &pb2.MessageSet{}
  963. setExtension(m, pb2.E_MessageSetExtension_MessageSetExtension, &pb2.MessageSetExtension{
  964. OptString: scalar.String("a messageset extension"),
  965. })
  966. setExtension(m, pb2.E_MessageSetExtension_NotMessageSetExtension, &pb2.MessageSetExtension{
  967. OptString: scalar.String("not a messageset extension"),
  968. })
  969. setExtension(m, pb2.E_MessageSetExtension_ExtNested, &pb2.Nested{
  970. OptString: scalar.String("just a regular extension"),
  971. })
  972. return m
  973. }(),
  974. want: `[pb2.MessageSetExtension]: {
  975. opt_string: "a messageset extension"
  976. }
  977. [pb2.MessageSetExtension.ext_nested]: {
  978. opt_string: "just a regular extension"
  979. }
  980. [pb2.MessageSetExtension.not_message_set_extension]: {
  981. opt_string: "not a messageset extension"
  982. }
  983. `,
  984. }, {
  985. desc: "not real MessageSet 1",
  986. input: func() proto.Message {
  987. m := &pb2.FakeMessageSet{}
  988. setExtension(m, pb2.E_FakeMessageSetExtension_MessageSetExtension, &pb2.FakeMessageSetExtension{
  989. OptString: scalar.String("not a messageset extension"),
  990. })
  991. return m
  992. }(),
  993. want: `[pb2.FakeMessageSetExtension.message_set_extension]: {
  994. opt_string: "not a messageset extension"
  995. }
  996. `,
  997. }, {
  998. desc: "not real MessageSet 2",
  999. input: func() proto.Message {
  1000. m := &pb2.MessageSet{}
  1001. setExtension(m, pb2.E_MessageSetExtension, &pb2.FakeMessageSetExtension{
  1002. OptString: scalar.String("another not a messageset extension"),
  1003. })
  1004. return m
  1005. }(),
  1006. want: `[pb2.message_set_extension]: {
  1007. opt_string: "another not a messageset extension"
  1008. }
  1009. `,
  1010. }, {
  1011. desc: "Any not expanded",
  1012. mo: textpb.MarshalOptions{
  1013. Resolver: preg.NewTypes(),
  1014. },
  1015. input: func() proto.Message {
  1016. m := &pb2.Nested{
  1017. OptString: scalar.String("embedded inside Any"),
  1018. OptNested: &pb2.Nested{
  1019. OptString: scalar.String("inception"),
  1020. },
  1021. }
  1022. // TODO: Switch to V2 marshal when ready.
  1023. b, err := protoV1.Marshal(m)
  1024. if err != nil {
  1025. t.Fatalf("error in binary marshaling message for Any.value: %v", err)
  1026. }
  1027. return wrapV1Message(&knownpb.Any{
  1028. TypeUrl: "pb2.Nested",
  1029. Value: b,
  1030. })
  1031. }(),
  1032. want: `type_url: "pb2.Nested"
  1033. value: "\n\x13embedded inside Any\x12\x0b\n\tinception"
  1034. `,
  1035. }, {
  1036. desc: "Any expanded",
  1037. mo: textpb.MarshalOptions{
  1038. Resolver: preg.NewTypes((&pb2.Nested{}).ProtoReflect().Type()),
  1039. },
  1040. input: func() proto.Message {
  1041. m := &pb2.Nested{
  1042. OptString: scalar.String("embedded inside Any"),
  1043. OptNested: &pb2.Nested{
  1044. OptString: scalar.String("inception"),
  1045. },
  1046. }
  1047. // TODO: Switch to V2 marshal when ready.
  1048. b, err := protoV1.Marshal(m)
  1049. if err != nil {
  1050. t.Fatalf("error in binary marshaling message for Any.value: %v", err)
  1051. }
  1052. return wrapV1Message(&knownpb.Any{
  1053. TypeUrl: "foo/pb2.Nested",
  1054. Value: b,
  1055. })
  1056. }(),
  1057. want: `[foo/pb2.Nested]: {
  1058. opt_string: "embedded inside Any"
  1059. opt_nested: {
  1060. opt_string: "inception"
  1061. }
  1062. }
  1063. `,
  1064. }, {
  1065. desc: "Any expanded with missing required error",
  1066. mo: textpb.MarshalOptions{
  1067. Resolver: preg.NewTypes((&pb2.PartialRequired{}).ProtoReflect().Type()),
  1068. },
  1069. input: func() proto.Message {
  1070. m := &pb2.PartialRequired{
  1071. OptString: scalar.String("embedded inside Any"),
  1072. }
  1073. // TODO: Switch to V2 marshal when ready.
  1074. b, err := protoV1.Marshal(m)
  1075. // Ignore required not set error.
  1076. if _, ok := err.(*protoV1.RequiredNotSetError); !ok {
  1077. t.Fatalf("error in binary marshaling message for Any.value: %v", err)
  1078. }
  1079. return wrapV1Message(&knownpb.Any{
  1080. TypeUrl: string(m.ProtoReflect().Type().FullName()),
  1081. Value: b,
  1082. })
  1083. }(),
  1084. want: `[pb2.PartialRequired]: {
  1085. opt_string: "embedded inside Any"
  1086. }
  1087. `,
  1088. wantErr: true,
  1089. }, {
  1090. desc: "Any with invalid value",
  1091. mo: textpb.MarshalOptions{
  1092. Resolver: preg.NewTypes((&pb2.Nested{}).ProtoReflect().Type()),
  1093. },
  1094. input: wrapV1Message(&knownpb.Any{
  1095. TypeUrl: "foo/pb2.Nested",
  1096. Value: dhex("80"),
  1097. }),
  1098. want: `type_url: "foo/pb2.Nested"
  1099. value: "\x80"
  1100. `,
  1101. }}
  1102. for _, tt := range tests {
  1103. tt := tt
  1104. t.Run(tt.desc, func(t *testing.T) {
  1105. t.Parallel()
  1106. b, err := tt.mo.Marshal(tt.input)
  1107. if err != nil && !tt.wantErr {
  1108. t.Errorf("Marshal() returned error: %v\n", err)
  1109. }
  1110. if err == nil && tt.wantErr {
  1111. t.Error("Marshal() got nil error, want error\n")
  1112. }
  1113. got := string(b)
  1114. if tt.want != "" && got != tt.want {
  1115. t.Errorf("Marshal()\n<got>\n%v\n<want>\n%v\n", got, tt.want)
  1116. if diff := cmp.Diff(tt.want, got, splitLines); diff != "" {
  1117. t.Errorf("Marshal() diff -want +got\n%v\n", diff)
  1118. }
  1119. }
  1120. })
  1121. }
  1122. }