encode_test.go 26 KB

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