encode_test.go 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479
  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 prototext_test
  5. import (
  6. "bytes"
  7. "math"
  8. "testing"
  9. "github.com/google/go-cmp/cmp"
  10. "google.golang.org/protobuf/encoding/prototext"
  11. "google.golang.org/protobuf/internal/detrand"
  12. "google.golang.org/protobuf/internal/flags"
  13. "google.golang.org/protobuf/proto"
  14. "google.golang.org/protobuf/reflect/protoregistry"
  15. "google.golang.org/protobuf/testing/protopack"
  16. pb2 "google.golang.org/protobuf/internal/testprotos/textpb2"
  17. pb3 "google.golang.org/protobuf/internal/testprotos/textpb3"
  18. "google.golang.org/protobuf/types/known/anypb"
  19. )
  20. func init() {
  21. // Disable detrand to enable direct comparisons on outputs.
  22. detrand.Disable()
  23. }
  24. func TestMarshal(t *testing.T) {
  25. tests := []struct {
  26. desc string
  27. mo prototext.MarshalOptions
  28. input proto.Message
  29. want string
  30. wantErr bool // TODO: Verify error message content.
  31. skip bool
  32. }{{
  33. desc: "proto2 optional scalars not set",
  34. input: &pb2.Scalars{},
  35. want: "",
  36. }, {
  37. desc: "proto3 scalars not set",
  38. input: &pb3.Scalars{},
  39. want: "",
  40. }, {
  41. desc: "proto3 optional not set",
  42. input: &pb3.Proto3Optional{},
  43. want: "",
  44. }, {
  45. desc: "proto2 optional scalars set to zero values",
  46. input: &pb2.Scalars{
  47. OptBool: proto.Bool(false),
  48. OptInt32: proto.Int32(0),
  49. OptInt64: proto.Int64(0),
  50. OptUint32: proto.Uint32(0),
  51. OptUint64: proto.Uint64(0),
  52. OptSint32: proto.Int32(0),
  53. OptSint64: proto.Int64(0),
  54. OptFixed32: proto.Uint32(0),
  55. OptFixed64: proto.Uint64(0),
  56. OptSfixed32: proto.Int32(0),
  57. OptSfixed64: proto.Int64(0),
  58. OptFloat: proto.Float32(0),
  59. OptDouble: proto.Float64(0),
  60. OptBytes: []byte{},
  61. OptString: proto.String(""),
  62. },
  63. want: `opt_bool: false
  64. opt_int32: 0
  65. opt_int64: 0
  66. opt_uint32: 0
  67. opt_uint64: 0
  68. opt_sint32: 0
  69. opt_sint64: 0
  70. opt_fixed32: 0
  71. opt_fixed64: 0
  72. opt_sfixed32: 0
  73. opt_sfixed64: 0
  74. opt_float: 0
  75. opt_double: 0
  76. opt_bytes: ""
  77. opt_string: ""
  78. `,
  79. }, {
  80. desc: "proto3 optional set to zero values",
  81. input: &pb3.Proto3Optional{
  82. OptBool: proto.Bool(false),
  83. OptInt32: proto.Int32(0),
  84. OptInt64: proto.Int64(0),
  85. OptUint32: proto.Uint32(0),
  86. OptUint64: proto.Uint64(0),
  87. OptFloat: proto.Float32(0),
  88. OptDouble: proto.Float64(0),
  89. OptString: proto.String(""),
  90. OptBytes: []byte{},
  91. OptEnum: pb3.Enum_ZERO.Enum(),
  92. OptMessage: &pb3.Nested{},
  93. },
  94. want: `opt_bool: false
  95. opt_int32: 0
  96. opt_int64: 0
  97. opt_uint32: 0
  98. opt_uint64: 0
  99. opt_float: 0
  100. opt_double: 0
  101. opt_string: ""
  102. opt_bytes: ""
  103. opt_enum: ZERO
  104. opt_message: {}
  105. `,
  106. }, {
  107. desc: "proto3 scalars set to zero values",
  108. input: &pb3.Scalars{
  109. SBool: false,
  110. SInt32: 0,
  111. SInt64: 0,
  112. SUint32: 0,
  113. SUint64: 0,
  114. SSint32: 0,
  115. SSint64: 0,
  116. SFixed32: 0,
  117. SFixed64: 0,
  118. SSfixed32: 0,
  119. SSfixed64: 0,
  120. SFloat: 0,
  121. SDouble: 0,
  122. SBytes: []byte{},
  123. SString: "",
  124. },
  125. want: "",
  126. }, {
  127. desc: "proto2 optional scalars set to some values",
  128. input: &pb2.Scalars{
  129. OptBool: proto.Bool(true),
  130. OptInt32: proto.Int32(0xff),
  131. OptInt64: proto.Int64(0xdeadbeef),
  132. OptUint32: proto.Uint32(47),
  133. OptUint64: proto.Uint64(0xdeadbeef),
  134. OptSint32: proto.Int32(-1001),
  135. OptSint64: proto.Int64(-0xffff),
  136. OptFixed64: proto.Uint64(64),
  137. OptSfixed32: proto.Int32(-32),
  138. OptFloat: proto.Float32(1.02),
  139. OptDouble: proto.Float64(1.0199999809265137),
  140. OptBytes: []byte("\xe8\xb0\xb7\xe6\xad\x8c"),
  141. OptString: proto.String("谷歌"),
  142. },
  143. want: `opt_bool: true
  144. opt_int32: 255
  145. opt_int64: 3735928559
  146. opt_uint32: 47
  147. opt_uint64: 3735928559
  148. opt_sint32: -1001
  149. opt_sint64: -65535
  150. opt_fixed64: 64
  151. opt_sfixed32: -32
  152. opt_float: 1.02
  153. opt_double: 1.0199999809265137
  154. opt_bytes: "谷歌"
  155. opt_string: "谷歌"
  156. `,
  157. }, {
  158. desc: "proto2 string with invalid UTF-8",
  159. input: &pb2.Scalars{
  160. OptString: proto.String("abc\xff"),
  161. },
  162. want: `opt_string: "abc\xff"
  163. `,
  164. }, {
  165. desc: "proto3 string with invalid UTF-8",
  166. input: &pb3.Scalars{
  167. SString: "abc\xff",
  168. },
  169. wantErr: true,
  170. }, {
  171. desc: "float nan",
  172. input: &pb3.Scalars{
  173. SFloat: float32(math.NaN()),
  174. },
  175. want: "s_float: nan\n",
  176. }, {
  177. desc: "float positive infinity",
  178. input: &pb3.Scalars{
  179. SFloat: float32(math.Inf(1)),
  180. },
  181. want: "s_float: inf\n",
  182. }, {
  183. desc: "float negative infinity",
  184. input: &pb3.Scalars{
  185. SFloat: float32(math.Inf(-1)),
  186. },
  187. want: "s_float: -inf\n",
  188. }, {
  189. desc: "double nan",
  190. input: &pb3.Scalars{
  191. SDouble: math.NaN(),
  192. },
  193. want: "s_double: nan\n",
  194. }, {
  195. desc: "double positive infinity",
  196. input: &pb3.Scalars{
  197. SDouble: math.Inf(1),
  198. },
  199. want: "s_double: inf\n",
  200. }, {
  201. desc: "double negative infinity",
  202. input: &pb3.Scalars{
  203. SDouble: math.Inf(-1),
  204. },
  205. want: "s_double: -inf\n",
  206. }, {
  207. desc: "proto2 enum not set",
  208. input: &pb2.Enums{},
  209. want: "",
  210. }, {
  211. desc: "proto2 enum set to zero value",
  212. input: &pb2.Enums{
  213. OptEnum: pb2.Enum(0).Enum(),
  214. OptNestedEnum: pb2.Enums_NestedEnum(0).Enum(),
  215. },
  216. want: `opt_enum: 0
  217. opt_nested_enum: 0
  218. `,
  219. }, {
  220. desc: "proto2 enum",
  221. input: &pb2.Enums{
  222. OptEnum: pb2.Enum_ONE.Enum(),
  223. OptNestedEnum: pb2.Enums_UNO.Enum(),
  224. },
  225. want: `opt_enum: ONE
  226. opt_nested_enum: UNO
  227. `,
  228. }, {
  229. desc: "proto2 enum set to numeric values",
  230. input: &pb2.Enums{
  231. OptEnum: pb2.Enum(2).Enum(),
  232. OptNestedEnum: pb2.Enums_NestedEnum(2).Enum(),
  233. },
  234. want: `opt_enum: TWO
  235. opt_nested_enum: DOS
  236. `,
  237. }, {
  238. desc: "proto2 enum set to unnamed numeric values",
  239. input: &pb2.Enums{
  240. OptEnum: pb2.Enum(101).Enum(),
  241. OptNestedEnum: pb2.Enums_NestedEnum(-101).Enum(),
  242. },
  243. want: `opt_enum: 101
  244. opt_nested_enum: -101
  245. `,
  246. }, {
  247. desc: "proto3 enum not set",
  248. input: &pb3.Enums{},
  249. want: "",
  250. }, {
  251. desc: "proto3 enum set to zero value",
  252. input: &pb3.Enums{
  253. SEnum: pb3.Enum_ZERO,
  254. SNestedEnum: pb3.Enums_CERO,
  255. },
  256. want: "",
  257. }, {
  258. desc: "proto3 enum",
  259. input: &pb3.Enums{
  260. SEnum: pb3.Enum_ONE,
  261. SNestedEnum: pb3.Enums_UNO,
  262. },
  263. want: `s_enum: ONE
  264. s_nested_enum: UNO
  265. `,
  266. }, {
  267. desc: "proto3 enum set to numeric values",
  268. input: &pb3.Enums{
  269. SEnum: 2,
  270. SNestedEnum: 2,
  271. },
  272. want: `s_enum: TWO
  273. s_nested_enum: DOS
  274. `,
  275. }, {
  276. desc: "proto3 enum set to unnamed numeric values",
  277. input: &pb3.Enums{
  278. SEnum: -47,
  279. SNestedEnum: 47,
  280. },
  281. want: `s_enum: -47
  282. s_nested_enum: 47
  283. `,
  284. }, {
  285. desc: "proto2 nested message not set",
  286. input: &pb2.Nests{},
  287. want: "",
  288. }, {
  289. desc: "proto2 nested message set to empty",
  290. input: &pb2.Nests{
  291. OptNested: &pb2.Nested{},
  292. Optgroup: &pb2.Nests_OptGroup{},
  293. },
  294. want: `opt_nested: {}
  295. OptGroup: {}
  296. `,
  297. }, {
  298. desc: "proto2 nested messages",
  299. input: &pb2.Nests{
  300. OptNested: &pb2.Nested{
  301. OptString: proto.String("nested message"),
  302. OptNested: &pb2.Nested{
  303. OptString: proto.String("another nested message"),
  304. },
  305. },
  306. },
  307. want: `opt_nested: {
  308. opt_string: "nested message"
  309. opt_nested: {
  310. opt_string: "another nested message"
  311. }
  312. }
  313. `,
  314. }, {
  315. desc: "proto2 groups",
  316. input: &pb2.Nests{
  317. Optgroup: &pb2.Nests_OptGroup{
  318. OptString: proto.String("inside a group"),
  319. OptNested: &pb2.Nested{
  320. OptString: proto.String("nested message inside a group"),
  321. },
  322. Optnestedgroup: &pb2.Nests_OptGroup_OptNestedGroup{
  323. OptFixed32: proto.Uint32(47),
  324. },
  325. },
  326. },
  327. want: `OptGroup: {
  328. opt_string: "inside a group"
  329. opt_nested: {
  330. opt_string: "nested message inside a group"
  331. }
  332. OptNestedGroup: {
  333. opt_fixed32: 47
  334. }
  335. }
  336. `,
  337. }, {
  338. desc: "proto3 nested message not set",
  339. input: &pb3.Nests{},
  340. want: "",
  341. }, {
  342. desc: "proto3 nested message set to empty",
  343. input: &pb3.Nests{
  344. SNested: &pb3.Nested{},
  345. },
  346. want: "s_nested: {}\n",
  347. }, {
  348. desc: "proto3 nested message",
  349. input: &pb3.Nests{
  350. SNested: &pb3.Nested{
  351. SString: "nested message",
  352. SNested: &pb3.Nested{
  353. SString: "another nested message",
  354. },
  355. },
  356. },
  357. want: `s_nested: {
  358. s_string: "nested message"
  359. s_nested: {
  360. s_string: "another nested message"
  361. }
  362. }
  363. `,
  364. }, {
  365. desc: "proto3 nested message contains invalid UTF-8",
  366. input: &pb3.Nests{
  367. SNested: &pb3.Nested{
  368. SString: "abc\xff",
  369. },
  370. },
  371. wantErr: true,
  372. }, {
  373. desc: "oneof not set",
  374. input: &pb3.Oneofs{},
  375. want: "",
  376. }, {
  377. desc: "oneof set to empty string",
  378. input: &pb3.Oneofs{
  379. Union: &pb3.Oneofs_OneofString{},
  380. },
  381. want: `oneof_string: ""
  382. `,
  383. }, {
  384. desc: "oneof set to string",
  385. input: &pb3.Oneofs{
  386. Union: &pb3.Oneofs_OneofString{
  387. OneofString: "hello",
  388. },
  389. },
  390. want: `oneof_string: "hello"
  391. `,
  392. }, {
  393. desc: "oneof set to enum",
  394. input: &pb3.Oneofs{
  395. Union: &pb3.Oneofs_OneofEnum{
  396. OneofEnum: pb3.Enum_ZERO,
  397. },
  398. },
  399. want: `oneof_enum: ZERO
  400. `,
  401. }, {
  402. desc: "oneof set to empty message",
  403. input: &pb3.Oneofs{
  404. Union: &pb3.Oneofs_OneofNested{
  405. OneofNested: &pb3.Nested{},
  406. },
  407. },
  408. want: "oneof_nested: {}\n",
  409. }, {
  410. desc: "oneof set to message",
  411. input: &pb3.Oneofs{
  412. Union: &pb3.Oneofs_OneofNested{
  413. OneofNested: &pb3.Nested{
  414. SString: "nested message",
  415. },
  416. },
  417. },
  418. want: `oneof_nested: {
  419. s_string: "nested message"
  420. }
  421. `,
  422. }, {
  423. desc: "repeated fields not set",
  424. input: &pb2.Repeats{},
  425. want: "",
  426. }, {
  427. desc: "repeated fields set to empty slices",
  428. input: &pb2.Repeats{
  429. RptBool: []bool{},
  430. RptInt32: []int32{},
  431. RptInt64: []int64{},
  432. RptUint32: []uint32{},
  433. RptUint64: []uint64{},
  434. RptFloat: []float32{},
  435. RptDouble: []float64{},
  436. RptBytes: [][]byte{},
  437. },
  438. want: "",
  439. }, {
  440. desc: "repeated fields set to some values",
  441. input: &pb2.Repeats{
  442. RptBool: []bool{true, false, true, true},
  443. RptInt32: []int32{1, 6, 0, 0},
  444. RptInt64: []int64{-64, 47},
  445. RptUint32: []uint32{0xff, 0xffff},
  446. RptUint64: []uint64{0xdeadbeef},
  447. RptFloat: []float32{float32(math.NaN()), float32(math.Inf(1)), float32(math.Inf(-1)), 1.034},
  448. RptDouble: []float64{math.NaN(), math.Inf(1), math.Inf(-1), 1.23e-308},
  449. RptString: []string{"hello", "世界"},
  450. RptBytes: [][]byte{
  451. []byte("hello"),
  452. []byte("\xe4\xb8\x96\xe7\x95\x8c"),
  453. },
  454. },
  455. want: `rpt_bool: true
  456. rpt_bool: false
  457. rpt_bool: true
  458. rpt_bool: true
  459. rpt_int32: 1
  460. rpt_int32: 6
  461. rpt_int32: 0
  462. rpt_int32: 0
  463. rpt_int64: -64
  464. rpt_int64: 47
  465. rpt_uint32: 255
  466. rpt_uint32: 65535
  467. rpt_uint64: 3735928559
  468. rpt_float: nan
  469. rpt_float: inf
  470. rpt_float: -inf
  471. rpt_float: 1.034
  472. rpt_double: nan
  473. rpt_double: inf
  474. rpt_double: -inf
  475. rpt_double: 1.23e-308
  476. rpt_string: "hello"
  477. rpt_string: "世界"
  478. rpt_bytes: "hello"
  479. rpt_bytes: "世界"
  480. `,
  481. }, {
  482. desc: "repeated proto2 contains invalid UTF-8",
  483. input: &pb2.Repeats{
  484. RptString: []string{"abc\xff"},
  485. },
  486. want: `rpt_string: "abc\xff"
  487. `,
  488. }, {
  489. desc: "repeated proto3 contains invalid UTF-8",
  490. input: &pb3.Repeats{
  491. RptString: []string{"abc\xff"},
  492. },
  493. wantErr: true,
  494. }, {
  495. desc: "repeated enums",
  496. input: &pb2.Enums{
  497. RptEnum: []pb2.Enum{pb2.Enum_ONE, 2, pb2.Enum_TEN, 42},
  498. RptNestedEnum: []pb2.Enums_NestedEnum{2, 47, 10},
  499. },
  500. want: `rpt_enum: ONE
  501. rpt_enum: TWO
  502. rpt_enum: TEN
  503. rpt_enum: 42
  504. rpt_nested_enum: DOS
  505. rpt_nested_enum: 47
  506. rpt_nested_enum: DIEZ
  507. `,
  508. }, {
  509. desc: "repeated messages set to empty",
  510. input: &pb2.Nests{
  511. RptNested: []*pb2.Nested{},
  512. Rptgroup: []*pb2.Nests_RptGroup{},
  513. },
  514. want: "",
  515. }, {
  516. desc: "repeated messages",
  517. input: &pb2.Nests{
  518. RptNested: []*pb2.Nested{
  519. {
  520. OptString: proto.String("repeat nested one"),
  521. },
  522. {
  523. OptString: proto.String("repeat nested two"),
  524. OptNested: &pb2.Nested{
  525. OptString: proto.String("inside repeat nested two"),
  526. },
  527. },
  528. {},
  529. },
  530. },
  531. want: `rpt_nested: {
  532. opt_string: "repeat nested one"
  533. }
  534. rpt_nested: {
  535. opt_string: "repeat nested two"
  536. opt_nested: {
  537. opt_string: "inside repeat nested two"
  538. }
  539. }
  540. rpt_nested: {}
  541. `,
  542. }, {
  543. desc: "repeated messages contains nil value",
  544. input: &pb2.Nests{
  545. RptNested: []*pb2.Nested{nil, {}},
  546. },
  547. want: `rpt_nested: {}
  548. rpt_nested: {}
  549. `,
  550. }, {
  551. desc: "repeated groups",
  552. input: &pb2.Nests{
  553. Rptgroup: []*pb2.Nests_RptGroup{
  554. {
  555. RptString: []string{"hello", "world"},
  556. },
  557. {},
  558. nil,
  559. },
  560. },
  561. want: `RptGroup: {
  562. rpt_string: "hello"
  563. rpt_string: "world"
  564. }
  565. RptGroup: {}
  566. RptGroup: {}
  567. `,
  568. }, {
  569. desc: "map fields not set",
  570. input: &pb3.Maps{},
  571. want: "",
  572. }, {
  573. desc: "map fields set to empty",
  574. input: &pb3.Maps{
  575. Int32ToStr: map[int32]string{},
  576. BoolToUint32: map[bool]uint32{},
  577. Uint64ToEnum: map[uint64]pb3.Enum{},
  578. StrToNested: map[string]*pb3.Nested{},
  579. StrToOneofs: map[string]*pb3.Oneofs{},
  580. },
  581. want: "",
  582. }, {
  583. desc: "map fields 1",
  584. input: &pb3.Maps{
  585. Int32ToStr: map[int32]string{
  586. -101: "-101",
  587. 0xff: "0xff",
  588. 0: "zero",
  589. },
  590. BoolToUint32: map[bool]uint32{
  591. true: 42,
  592. false: 101,
  593. },
  594. },
  595. want: `int32_to_str: {
  596. key: -101
  597. value: "-101"
  598. }
  599. int32_to_str: {
  600. key: 0
  601. value: "zero"
  602. }
  603. int32_to_str: {
  604. key: 255
  605. value: "0xff"
  606. }
  607. bool_to_uint32: {
  608. key: false
  609. value: 101
  610. }
  611. bool_to_uint32: {
  612. key: true
  613. value: 42
  614. }
  615. `,
  616. }, {
  617. desc: "map fields 2",
  618. input: &pb3.Maps{
  619. Uint64ToEnum: map[uint64]pb3.Enum{
  620. 1: pb3.Enum_ONE,
  621. 2: pb3.Enum_TWO,
  622. 10: pb3.Enum_TEN,
  623. 47: 47,
  624. },
  625. },
  626. want: `uint64_to_enum: {
  627. key: 1
  628. value: ONE
  629. }
  630. uint64_to_enum: {
  631. key: 2
  632. value: TWO
  633. }
  634. uint64_to_enum: {
  635. key: 10
  636. value: TEN
  637. }
  638. uint64_to_enum: {
  639. key: 47
  640. value: 47
  641. }
  642. `,
  643. }, {
  644. desc: "map fields 3",
  645. input: &pb3.Maps{
  646. StrToNested: map[string]*pb3.Nested{
  647. "nested": &pb3.Nested{
  648. SString: "nested in a map",
  649. },
  650. },
  651. },
  652. want: `str_to_nested: {
  653. key: "nested"
  654. value: {
  655. s_string: "nested in a map"
  656. }
  657. }
  658. `,
  659. }, {
  660. desc: "map fields 4",
  661. input: &pb3.Maps{
  662. StrToOneofs: map[string]*pb3.Oneofs{
  663. "string": &pb3.Oneofs{
  664. Union: &pb3.Oneofs_OneofString{
  665. OneofString: "hello",
  666. },
  667. },
  668. "nested": &pb3.Oneofs{
  669. Union: &pb3.Oneofs_OneofNested{
  670. OneofNested: &pb3.Nested{
  671. SString: "nested oneof in map field value",
  672. },
  673. },
  674. },
  675. },
  676. },
  677. want: `str_to_oneofs: {
  678. key: "nested"
  679. value: {
  680. oneof_nested: {
  681. s_string: "nested oneof in map field value"
  682. }
  683. }
  684. }
  685. str_to_oneofs: {
  686. key: "string"
  687. value: {
  688. oneof_string: "hello"
  689. }
  690. }
  691. `,
  692. }, {
  693. desc: "proto2 map field value contains invalid UTF-8",
  694. input: &pb2.Maps{
  695. Int32ToStr: map[int32]string{
  696. 101: "abc\xff",
  697. },
  698. },
  699. want: `int32_to_str: {
  700. key: 101
  701. value: "abc\xff"
  702. }
  703. `,
  704. }, {
  705. desc: "proto2 map field key contains invalid UTF-8",
  706. input: &pb2.Maps{
  707. StrToNested: map[string]*pb2.Nested{
  708. "abc\xff": {},
  709. },
  710. },
  711. want: `str_to_nested: {
  712. key: "abc\xff"
  713. value: {}
  714. }
  715. `,
  716. }, {
  717. desc: "proto3 map field value contains invalid UTF-8",
  718. input: &pb3.Maps{
  719. Int32ToStr: map[int32]string{
  720. 101: "abc\xff",
  721. },
  722. },
  723. wantErr: true,
  724. }, {
  725. desc: "proto3 map field key contains invalid UTF-8",
  726. input: &pb3.Maps{
  727. StrToNested: map[string]*pb3.Nested{
  728. "abc\xff": {},
  729. },
  730. },
  731. wantErr: true,
  732. }, {
  733. desc: "map field contains nil value",
  734. input: &pb3.Maps{
  735. StrToNested: map[string]*pb3.Nested{
  736. "nil": nil,
  737. },
  738. },
  739. want: `str_to_nested: {
  740. key: "nil"
  741. value: {}
  742. }
  743. `,
  744. }, {
  745. desc: "required fields not set",
  746. input: &pb2.Requireds{},
  747. want: "",
  748. wantErr: true,
  749. }, {
  750. desc: "required fields partially set",
  751. input: &pb2.Requireds{
  752. ReqBool: proto.Bool(false),
  753. ReqSfixed64: proto.Int64(0xbeefcafe),
  754. ReqDouble: proto.Float64(math.NaN()),
  755. ReqString: proto.String("hello"),
  756. ReqEnum: pb2.Enum_ONE.Enum(),
  757. },
  758. want: `req_bool: false
  759. req_sfixed64: 3203386110
  760. req_double: nan
  761. req_string: "hello"
  762. req_enum: ONE
  763. `,
  764. wantErr: true,
  765. }, {
  766. desc: "required fields not set with AllowPartial",
  767. mo: prototext.MarshalOptions{AllowPartial: true},
  768. input: &pb2.Requireds{
  769. ReqBool: proto.Bool(false),
  770. ReqSfixed64: proto.Int64(0xbeefcafe),
  771. ReqDouble: proto.Float64(math.NaN()),
  772. ReqString: proto.String("hello"),
  773. ReqEnum: pb2.Enum_ONE.Enum(),
  774. },
  775. want: `req_bool: false
  776. req_sfixed64: 3203386110
  777. req_double: nan
  778. req_string: "hello"
  779. req_enum: ONE
  780. `,
  781. }, {
  782. desc: "required fields all set",
  783. input: &pb2.Requireds{
  784. ReqBool: proto.Bool(false),
  785. ReqSfixed64: proto.Int64(0),
  786. ReqDouble: proto.Float64(1.23),
  787. ReqString: proto.String(""),
  788. ReqEnum: pb2.Enum_ONE.Enum(),
  789. ReqNested: &pb2.Nested{},
  790. },
  791. want: `req_bool: false
  792. req_sfixed64: 0
  793. req_double: 1.23
  794. req_string: ""
  795. req_enum: ONE
  796. req_nested: {}
  797. `,
  798. }, {
  799. desc: "indirect required field",
  800. input: &pb2.IndirectRequired{
  801. OptNested: &pb2.NestedWithRequired{},
  802. },
  803. want: "opt_nested: {}\n",
  804. wantErr: true,
  805. }, {
  806. desc: "indirect required field with AllowPartial",
  807. mo: prototext.MarshalOptions{AllowPartial: true},
  808. input: &pb2.IndirectRequired{
  809. OptNested: &pb2.NestedWithRequired{},
  810. },
  811. want: "opt_nested: {}\n",
  812. }, {
  813. desc: "indirect required field in empty repeated",
  814. input: &pb2.IndirectRequired{
  815. RptNested: []*pb2.NestedWithRequired{},
  816. },
  817. want: "",
  818. }, {
  819. desc: "indirect required field in repeated",
  820. input: &pb2.IndirectRequired{
  821. RptNested: []*pb2.NestedWithRequired{
  822. &pb2.NestedWithRequired{},
  823. },
  824. },
  825. want: "rpt_nested: {}\n",
  826. wantErr: true,
  827. }, {
  828. desc: "indirect required field in repeated with AllowPartial",
  829. mo: prototext.MarshalOptions{AllowPartial: true},
  830. input: &pb2.IndirectRequired{
  831. RptNested: []*pb2.NestedWithRequired{
  832. &pb2.NestedWithRequired{},
  833. },
  834. },
  835. want: "rpt_nested: {}\n",
  836. }, {
  837. desc: "indirect required field in empty map",
  838. input: &pb2.IndirectRequired{
  839. StrToNested: map[string]*pb2.NestedWithRequired{},
  840. },
  841. want: "",
  842. }, {
  843. desc: "indirect required field in map",
  844. input: &pb2.IndirectRequired{
  845. StrToNested: map[string]*pb2.NestedWithRequired{
  846. "fail": &pb2.NestedWithRequired{},
  847. },
  848. },
  849. want: `str_to_nested: {
  850. key: "fail"
  851. value: {}
  852. }
  853. `,
  854. wantErr: true,
  855. }, {
  856. desc: "indirect required field in map with AllowPartial",
  857. mo: prototext.MarshalOptions{AllowPartial: true},
  858. input: &pb2.IndirectRequired{
  859. StrToNested: map[string]*pb2.NestedWithRequired{
  860. "fail": &pb2.NestedWithRequired{},
  861. },
  862. },
  863. want: `str_to_nested: {
  864. key: "fail"
  865. value: {}
  866. }
  867. `,
  868. }, {
  869. desc: "indirect required field in oneof",
  870. input: &pb2.IndirectRequired{
  871. Union: &pb2.IndirectRequired_OneofNested{
  872. OneofNested: &pb2.NestedWithRequired{},
  873. },
  874. },
  875. want: "oneof_nested: {}\n",
  876. wantErr: true,
  877. }, {
  878. desc: "indirect required field in oneof with AllowPartial",
  879. mo: prototext.MarshalOptions{AllowPartial: true},
  880. input: &pb2.IndirectRequired{
  881. Union: &pb2.IndirectRequired_OneofNested{
  882. OneofNested: &pb2.NestedWithRequired{},
  883. },
  884. },
  885. want: "oneof_nested: {}\n",
  886. }, {
  887. desc: "unknown fields not printed",
  888. input: func() proto.Message {
  889. m := &pb2.Scalars{
  890. OptString: proto.String("this message contains unknown fields"),
  891. }
  892. m.ProtoReflect().SetUnknown(protopack.Message{
  893. protopack.Tag{101, protopack.VarintType}, protopack.Bool(true),
  894. protopack.Tag{102, protopack.VarintType}, protopack.Varint(0xff),
  895. protopack.Tag{103, protopack.Fixed32Type}, protopack.Uint32(47),
  896. protopack.Tag{104, protopack.Fixed64Type}, protopack.Int64(0xdeadbeef),
  897. }.Marshal())
  898. return m
  899. }(),
  900. want: `opt_string: "this message contains unknown fields"
  901. `,
  902. }, {
  903. desc: "unknown varint and fixed types",
  904. mo: prototext.MarshalOptions{EmitUnknown: true},
  905. input: func() proto.Message {
  906. m := &pb2.Scalars{
  907. OptString: proto.String("this message contains unknown fields"),
  908. }
  909. m.ProtoReflect().SetUnknown(protopack.Message{
  910. protopack.Tag{101, protopack.VarintType}, protopack.Bool(true),
  911. protopack.Tag{102, protopack.VarintType}, protopack.Varint(0xff),
  912. protopack.Tag{103, protopack.Fixed32Type}, protopack.Uint32(0x47),
  913. protopack.Tag{104, protopack.Fixed64Type}, protopack.Int64(0xdeadbeef),
  914. }.Marshal())
  915. return m
  916. }(),
  917. want: `opt_string: "this message contains unknown fields"
  918. 101: 1
  919. 102: 255
  920. 103: 0x47
  921. 104: 0xdeadbeef
  922. `,
  923. }, {
  924. desc: "unknown length-delimited",
  925. mo: prototext.MarshalOptions{EmitUnknown: true},
  926. input: func() proto.Message {
  927. m := new(pb2.Scalars)
  928. m.ProtoReflect().SetUnknown(protopack.Message{
  929. protopack.Tag{101, protopack.BytesType}, protopack.LengthPrefix{protopack.Bool(true), protopack.Bool(false)},
  930. protopack.Tag{102, protopack.BytesType}, protopack.String("hello world"),
  931. protopack.Tag{103, protopack.BytesType}, protopack.Bytes("\xe4\xb8\x96\xe7\x95\x8c"),
  932. }.Marshal())
  933. return m
  934. }(),
  935. want: `101: "\x01\x00"
  936. 102: "hello world"
  937. 103: "世界"
  938. `,
  939. }, {
  940. desc: "unknown group type",
  941. mo: prototext.MarshalOptions{EmitUnknown: true},
  942. input: func() proto.Message {
  943. m := new(pb2.Scalars)
  944. m.ProtoReflect().SetUnknown(protopack.Message{
  945. protopack.Tag{101, protopack.StartGroupType}, protopack.Tag{101, protopack.EndGroupType},
  946. protopack.Tag{102, protopack.StartGroupType},
  947. protopack.Tag{101, protopack.VarintType}, protopack.Bool(false),
  948. protopack.Tag{102, protopack.BytesType}, protopack.String("inside a group"),
  949. protopack.Tag{102, protopack.EndGroupType},
  950. }.Marshal())
  951. return m
  952. }(),
  953. want: `101: {}
  954. 102: {
  955. 101: 0
  956. 102: "inside a group"
  957. }
  958. `,
  959. }, {
  960. desc: "unknown unpack repeated field",
  961. mo: prototext.MarshalOptions{EmitUnknown: true},
  962. input: func() proto.Message {
  963. m := new(pb2.Scalars)
  964. m.ProtoReflect().SetUnknown(protopack.Message{
  965. protopack.Tag{101, protopack.BytesType}, protopack.LengthPrefix{protopack.Bool(true), protopack.Bool(false), protopack.Bool(true)},
  966. protopack.Tag{102, protopack.BytesType}, protopack.String("hello"),
  967. protopack.Tag{101, protopack.VarintType}, protopack.Bool(true),
  968. protopack.Tag{102, protopack.BytesType}, protopack.String("世界"),
  969. }.Marshal())
  970. return m
  971. }(),
  972. want: `101: "\x01\x00\x01"
  973. 102: "hello"
  974. 101: 1
  975. 102: "世界"
  976. `,
  977. }, {
  978. desc: "extensions of non-repeated fields",
  979. input: func() proto.Message {
  980. m := &pb2.Extensions{
  981. OptString: proto.String("non-extension field"),
  982. OptBool: proto.Bool(true),
  983. OptInt32: proto.Int32(42),
  984. }
  985. proto.SetExtension(m, pb2.E_OptExtBool, true)
  986. proto.SetExtension(m, pb2.E_OptExtString, "extension field")
  987. proto.SetExtension(m, pb2.E_OptExtEnum, pb2.Enum_TEN)
  988. proto.SetExtension(m, pb2.E_OptExtNested, &pb2.Nested{
  989. OptString: proto.String("nested in an extension"),
  990. OptNested: &pb2.Nested{
  991. OptString: proto.String("another nested in an extension"),
  992. },
  993. })
  994. return m
  995. }(),
  996. want: `opt_string: "non-extension field"
  997. opt_bool: true
  998. opt_int32: 42
  999. [pb2.opt_ext_bool]: true
  1000. [pb2.opt_ext_enum]: TEN
  1001. [pb2.opt_ext_nested]: {
  1002. opt_string: "nested in an extension"
  1003. opt_nested: {
  1004. opt_string: "another nested in an extension"
  1005. }
  1006. }
  1007. [pb2.opt_ext_string]: "extension field"
  1008. `,
  1009. }, {
  1010. desc: "proto2 extension field contains invalid UTF-8",
  1011. input: func() proto.Message {
  1012. m := &pb2.Extensions{}
  1013. proto.SetExtension(m, pb2.E_OptExtString, "abc\xff")
  1014. return m
  1015. }(),
  1016. want: `[pb2.opt_ext_string]: "abc\xff"
  1017. `,
  1018. }, {
  1019. desc: "extension partial returns error",
  1020. input: func() proto.Message {
  1021. m := &pb2.Extensions{}
  1022. proto.SetExtension(m, pb2.E_OptExtPartial, &pb2.PartialRequired{
  1023. OptString: proto.String("partial1"),
  1024. })
  1025. proto.SetExtension(m, pb2.E_ExtensionsContainer_OptExtPartial, &pb2.PartialRequired{
  1026. OptString: proto.String("partial2"),
  1027. })
  1028. return m
  1029. }(),
  1030. want: `[pb2.ExtensionsContainer.opt_ext_partial]: {
  1031. opt_string: "partial2"
  1032. }
  1033. [pb2.opt_ext_partial]: {
  1034. opt_string: "partial1"
  1035. }
  1036. `,
  1037. wantErr: true,
  1038. }, {
  1039. desc: "extension partial with AllowPartial",
  1040. mo: prototext.MarshalOptions{AllowPartial: true},
  1041. input: func() proto.Message {
  1042. m := &pb2.Extensions{}
  1043. proto.SetExtension(m, pb2.E_OptExtPartial, &pb2.PartialRequired{
  1044. OptString: proto.String("partial1"),
  1045. })
  1046. return m
  1047. }(),
  1048. want: `[pb2.opt_ext_partial]: {
  1049. opt_string: "partial1"
  1050. }
  1051. `,
  1052. }, {
  1053. desc: "extensions of repeated fields",
  1054. input: func() proto.Message {
  1055. m := &pb2.Extensions{}
  1056. proto.SetExtension(m, pb2.E_RptExtEnum, []pb2.Enum{pb2.Enum_TEN, 101, pb2.Enum_ONE})
  1057. proto.SetExtension(m, pb2.E_RptExtFixed32, []uint32{42, 47})
  1058. proto.SetExtension(m, pb2.E_RptExtNested, []*pb2.Nested{
  1059. &pb2.Nested{OptString: proto.String("one")},
  1060. &pb2.Nested{OptString: proto.String("two")},
  1061. &pb2.Nested{OptString: proto.String("three")},
  1062. })
  1063. return m
  1064. }(),
  1065. want: `[pb2.rpt_ext_enum]: TEN
  1066. [pb2.rpt_ext_enum]: 101
  1067. [pb2.rpt_ext_enum]: ONE
  1068. [pb2.rpt_ext_fixed32]: 42
  1069. [pb2.rpt_ext_fixed32]: 47
  1070. [pb2.rpt_ext_nested]: {
  1071. opt_string: "one"
  1072. }
  1073. [pb2.rpt_ext_nested]: {
  1074. opt_string: "two"
  1075. }
  1076. [pb2.rpt_ext_nested]: {
  1077. opt_string: "three"
  1078. }
  1079. `,
  1080. }, {
  1081. desc: "extensions of non-repeated fields in another message",
  1082. input: func() proto.Message {
  1083. m := &pb2.Extensions{}
  1084. proto.SetExtension(m, pb2.E_ExtensionsContainer_OptExtBool, true)
  1085. proto.SetExtension(m, pb2.E_ExtensionsContainer_OptExtString, "extension field")
  1086. proto.SetExtension(m, pb2.E_ExtensionsContainer_OptExtEnum, pb2.Enum_TEN)
  1087. proto.SetExtension(m, pb2.E_ExtensionsContainer_OptExtNested, &pb2.Nested{
  1088. OptString: proto.String("nested in an extension"),
  1089. OptNested: &pb2.Nested{
  1090. OptString: proto.String("another nested in an extension"),
  1091. },
  1092. })
  1093. return m
  1094. }(),
  1095. want: `[pb2.ExtensionsContainer.opt_ext_bool]: true
  1096. [pb2.ExtensionsContainer.opt_ext_enum]: TEN
  1097. [pb2.ExtensionsContainer.opt_ext_nested]: {
  1098. opt_string: "nested in an extension"
  1099. opt_nested: {
  1100. opt_string: "another nested in an extension"
  1101. }
  1102. }
  1103. [pb2.ExtensionsContainer.opt_ext_string]: "extension field"
  1104. `,
  1105. }, {
  1106. desc: "extensions of repeated fields in another message",
  1107. input: func() proto.Message {
  1108. m := &pb2.Extensions{
  1109. OptString: proto.String("non-extension field"),
  1110. OptBool: proto.Bool(true),
  1111. OptInt32: proto.Int32(42),
  1112. }
  1113. proto.SetExtension(m, pb2.E_ExtensionsContainer_RptExtEnum, []pb2.Enum{pb2.Enum_TEN, 101, pb2.Enum_ONE})
  1114. proto.SetExtension(m, pb2.E_ExtensionsContainer_RptExtString, []string{"hello", "world"})
  1115. proto.SetExtension(m, pb2.E_ExtensionsContainer_RptExtNested, []*pb2.Nested{
  1116. &pb2.Nested{OptString: proto.String("one")},
  1117. &pb2.Nested{OptString: proto.String("two")},
  1118. &pb2.Nested{OptString: proto.String("three")},
  1119. })
  1120. return m
  1121. }(),
  1122. want: `opt_string: "non-extension field"
  1123. opt_bool: true
  1124. opt_int32: 42
  1125. [pb2.ExtensionsContainer.rpt_ext_enum]: TEN
  1126. [pb2.ExtensionsContainer.rpt_ext_enum]: 101
  1127. [pb2.ExtensionsContainer.rpt_ext_enum]: ONE
  1128. [pb2.ExtensionsContainer.rpt_ext_nested]: {
  1129. opt_string: "one"
  1130. }
  1131. [pb2.ExtensionsContainer.rpt_ext_nested]: {
  1132. opt_string: "two"
  1133. }
  1134. [pb2.ExtensionsContainer.rpt_ext_nested]: {
  1135. opt_string: "three"
  1136. }
  1137. [pb2.ExtensionsContainer.rpt_ext_string]: "hello"
  1138. [pb2.ExtensionsContainer.rpt_ext_string]: "world"
  1139. `,
  1140. }, {
  1141. desc: "MessageSet",
  1142. input: func() proto.Message {
  1143. m := &pb2.MessageSet{}
  1144. proto.SetExtension(m, pb2.E_MessageSetExtension_MessageSetExtension, &pb2.MessageSetExtension{
  1145. OptString: proto.String("a messageset extension"),
  1146. })
  1147. proto.SetExtension(m, pb2.E_MessageSetExtension_NotMessageSetExtension, &pb2.MessageSetExtension{
  1148. OptString: proto.String("not a messageset extension"),
  1149. })
  1150. proto.SetExtension(m, pb2.E_MessageSetExtension_ExtNested, &pb2.Nested{
  1151. OptString: proto.String("just a regular extension"),
  1152. })
  1153. return m
  1154. }(),
  1155. want: `[pb2.MessageSetExtension.ext_nested]: {
  1156. opt_string: "just a regular extension"
  1157. }
  1158. [pb2.MessageSetExtension]: {
  1159. opt_string: "a messageset extension"
  1160. }
  1161. [pb2.MessageSetExtension.not_message_set_extension]: {
  1162. opt_string: "not a messageset extension"
  1163. }
  1164. `,
  1165. skip: !flags.ProtoLegacy,
  1166. }, {
  1167. desc: "not real MessageSet 1",
  1168. input: func() proto.Message {
  1169. m := &pb2.FakeMessageSet{}
  1170. proto.SetExtension(m, pb2.E_FakeMessageSetExtension_MessageSetExtension, &pb2.FakeMessageSetExtension{
  1171. OptString: proto.String("not a messageset extension"),
  1172. })
  1173. return m
  1174. }(),
  1175. want: `[pb2.FakeMessageSetExtension.message_set_extension]: {
  1176. opt_string: "not a messageset extension"
  1177. }
  1178. `,
  1179. skip: !flags.ProtoLegacy,
  1180. }, {
  1181. desc: "not real MessageSet 2",
  1182. input: func() proto.Message {
  1183. m := &pb2.MessageSet{}
  1184. proto.SetExtension(m, pb2.E_MessageSetExtension, &pb2.FakeMessageSetExtension{
  1185. OptString: proto.String("another not a messageset extension"),
  1186. })
  1187. return m
  1188. }(),
  1189. want: `[pb2.message_set_extension]: {
  1190. opt_string: "another not a messageset extension"
  1191. }
  1192. `,
  1193. skip: !flags.ProtoLegacy,
  1194. }, {
  1195. desc: "Any not expanded",
  1196. mo: prototext.MarshalOptions{
  1197. Resolver: new(protoregistry.Types),
  1198. },
  1199. input: func() proto.Message {
  1200. m := &pb2.Nested{
  1201. OptString: proto.String("embedded inside Any"),
  1202. OptNested: &pb2.Nested{
  1203. OptString: proto.String("inception"),
  1204. },
  1205. }
  1206. b, err := proto.MarshalOptions{Deterministic: true}.Marshal(m)
  1207. if err != nil {
  1208. t.Fatalf("error in binary marshaling message for Any.value: %v", err)
  1209. }
  1210. return &anypb.Any{
  1211. TypeUrl: "pb2.Nested",
  1212. Value: b,
  1213. }
  1214. }(),
  1215. want: `type_url: "pb2.Nested"
  1216. value: "\n\x13embedded inside Any\x12\x0b\n\tinception"
  1217. `,
  1218. }, {
  1219. desc: "Any expanded",
  1220. input: func() proto.Message {
  1221. m := &pb2.Nested{
  1222. OptString: proto.String("embedded inside Any"),
  1223. OptNested: &pb2.Nested{
  1224. OptString: proto.String("inception"),
  1225. },
  1226. }
  1227. b, err := proto.MarshalOptions{Deterministic: true}.Marshal(m)
  1228. if err != nil {
  1229. t.Fatalf("error in binary marshaling message for Any.value: %v", err)
  1230. }
  1231. return &anypb.Any{
  1232. TypeUrl: "foo/pb2.Nested",
  1233. Value: b,
  1234. }
  1235. }(),
  1236. want: `[foo/pb2.Nested]: {
  1237. opt_string: "embedded inside Any"
  1238. opt_nested: {
  1239. opt_string: "inception"
  1240. }
  1241. }
  1242. `,
  1243. }, {
  1244. desc: "Any expanded with missing required",
  1245. input: func() proto.Message {
  1246. m := &pb2.PartialRequired{
  1247. OptString: proto.String("embedded inside Any"),
  1248. }
  1249. b, err := proto.MarshalOptions{
  1250. AllowPartial: true,
  1251. Deterministic: true,
  1252. }.Marshal(m)
  1253. if err != nil {
  1254. t.Fatalf("error in binary marshaling message for Any.value: %v", err)
  1255. }
  1256. return &anypb.Any{
  1257. TypeUrl: string(m.ProtoReflect().Descriptor().FullName()),
  1258. Value: b,
  1259. }
  1260. }(),
  1261. want: `[pb2.PartialRequired]: {
  1262. opt_string: "embedded inside Any"
  1263. }
  1264. `,
  1265. }, {
  1266. desc: "Any with invalid value",
  1267. input: &anypb.Any{
  1268. TypeUrl: "foo/pb2.Nested",
  1269. Value: []byte("\x80"),
  1270. },
  1271. want: `type_url: "foo/pb2.Nested"
  1272. value: "\x80"
  1273. `,
  1274. }, {
  1275. desc: "Any expanded in another message",
  1276. input: func() *pb2.KnownTypes {
  1277. m1 := &pb2.Nested{
  1278. OptString: proto.String("message inside Any of another Any field"),
  1279. }
  1280. b1, err := proto.MarshalOptions{Deterministic: true}.Marshal(m1)
  1281. if err != nil {
  1282. t.Fatalf("error in binary marshaling message for Any.value: %v", err)
  1283. }
  1284. m2 := &anypb.Any{
  1285. TypeUrl: "pb2.Nested",
  1286. Value: b1,
  1287. }
  1288. b2, err := proto.MarshalOptions{Deterministic: true}.Marshal(m2)
  1289. if err != nil {
  1290. t.Fatalf("error in binary marshaling message for Any.value: %v", err)
  1291. }
  1292. return &pb2.KnownTypes{
  1293. OptAny: &anypb.Any{
  1294. TypeUrl: "google.protobuf.Any",
  1295. Value: b2,
  1296. },
  1297. }
  1298. }(),
  1299. want: `opt_any: {
  1300. [google.protobuf.Any]: {
  1301. [pb2.Nested]: {
  1302. opt_string: "message inside Any of another Any field"
  1303. }
  1304. }
  1305. }
  1306. `,
  1307. }, {
  1308. desc: "Any expanded with invalid UTF-8 in proto2",
  1309. input: func() *pb2.KnownTypes {
  1310. m := &pb2.Nested{
  1311. OptString: proto.String("invalid UTF-8 abc\xff"),
  1312. }
  1313. b, err := proto.MarshalOptions{Deterministic: true}.Marshal(m)
  1314. if err != nil {
  1315. t.Fatalf("error in binary marshaling message for Any.value: %v", err)
  1316. }
  1317. return &pb2.KnownTypes{
  1318. OptAny: &anypb.Any{
  1319. TypeUrl: "pb2.Nested",
  1320. Value: b,
  1321. },
  1322. }
  1323. }(),
  1324. want: `opt_any: {
  1325. [pb2.Nested]: {
  1326. opt_string: "invalid UTF-8 abc\xff"
  1327. }
  1328. }
  1329. `,
  1330. }, {
  1331. desc: "Any not expanded due to invalid data",
  1332. mo: prototext.MarshalOptions{EmitASCII: true},
  1333. input: func() *pb2.KnownTypes {
  1334. return &pb2.KnownTypes{
  1335. OptAny: &anypb.Any{
  1336. TypeUrl: "pb3.Scalar",
  1337. Value: []byte("\xde\xad\xbe\xef"),
  1338. },
  1339. }
  1340. }(),
  1341. want: `opt_any: {
  1342. type_url: "pb3.Scalar"
  1343. value: "\u07ad\xbe\xef"
  1344. }
  1345. `,
  1346. }, {
  1347. desc: "Any inside Any expanded",
  1348. input: func() *pb2.KnownTypes {
  1349. m1 := &pb2.Nested{
  1350. OptString: proto.String("invalid UTF-8 abc\xff"),
  1351. }
  1352. b1, err := proto.MarshalOptions{Deterministic: true}.Marshal(m1)
  1353. if err != nil {
  1354. t.Fatalf("error in binary marshaling message for Any.value: %v", err)
  1355. }
  1356. m2 := &anypb.Any{
  1357. TypeUrl: "pb2.Nested",
  1358. Value: b1,
  1359. }
  1360. b2, err := proto.MarshalOptions{Deterministic: true}.Marshal(m2)
  1361. if err != nil {
  1362. t.Fatalf("error in binary marshaling message for Any.value: %v", err)
  1363. }
  1364. return &pb2.KnownTypes{
  1365. OptAny: &anypb.Any{
  1366. TypeUrl: "google.protobuf.Any",
  1367. Value: b2,
  1368. },
  1369. }
  1370. }(),
  1371. want: `opt_any: {
  1372. [google.protobuf.Any]: {
  1373. [pb2.Nested]: {
  1374. opt_string: "invalid UTF-8 abc\xff"
  1375. }
  1376. }
  1377. }
  1378. `,
  1379. }, {
  1380. desc: "Any inside Any not expanded due to invalid data",
  1381. mo: prototext.MarshalOptions{EmitASCII: true},
  1382. input: func() *pb2.KnownTypes {
  1383. m := &anypb.Any{
  1384. TypeUrl: "pb2.Nested",
  1385. Value: []byte("\xde\xad\xbe\xef"),
  1386. }
  1387. b, err := proto.MarshalOptions{Deterministic: true}.Marshal(m)
  1388. if err != nil {
  1389. t.Fatalf("error in binary marshaling message for Any.value: %v", err)
  1390. }
  1391. return &pb2.KnownTypes{
  1392. OptAny: &anypb.Any{
  1393. TypeUrl: "google.protobuf.Any",
  1394. Value: b,
  1395. },
  1396. }
  1397. }(),
  1398. want: `opt_any: {
  1399. [google.protobuf.Any]: {
  1400. type_url: "pb2.Nested"
  1401. value: "\u07ad\xbe\xef"
  1402. }
  1403. }
  1404. `,
  1405. }}
  1406. for _, tt := range tests {
  1407. tt := tt
  1408. if tt.skip {
  1409. continue
  1410. }
  1411. t.Run(tt.desc, func(t *testing.T) {
  1412. // Use 2-space indentation on all MarshalOptions.
  1413. tt.mo.Indent = " "
  1414. b, err := tt.mo.Marshal(tt.input)
  1415. if err != nil && !tt.wantErr {
  1416. t.Errorf("Marshal() returned error: %v\n", err)
  1417. }
  1418. if err == nil && tt.wantErr {
  1419. t.Error("Marshal() got nil error, want error\n")
  1420. }
  1421. got := string(b)
  1422. if tt.want != "" && got != tt.want {
  1423. t.Errorf("Marshal()\n<got>\n%v\n<want>\n%v\n", got, tt.want)
  1424. if diff := cmp.Diff(tt.want, got); diff != "" {
  1425. t.Errorf("Marshal() diff -want +got\n%v\n", diff)
  1426. }
  1427. }
  1428. })
  1429. }
  1430. }
  1431. func TestEncodeAppend(t *testing.T) {
  1432. want := []byte("prefix")
  1433. got := append([]byte(nil), want...)
  1434. got, err := prototext.MarshalOptions{}.MarshalAppend(got, &pb3.Scalars{
  1435. SString: "value",
  1436. })
  1437. if err != nil {
  1438. t.Fatal(err)
  1439. }
  1440. if !bytes.HasPrefix(got, want) {
  1441. t.Fatalf("MarshalAppend modified prefix: got %v, want prefix %v", got, want)
  1442. }
  1443. }
  1444. func TestMarshalAppendAllocations(t *testing.T) {
  1445. m := &pb3.Scalars{SInt32: 1}
  1446. const count = 1000
  1447. size := 9
  1448. b := make([]byte, size)
  1449. // AllocsPerRun returns an integral value.
  1450. marshalAllocs := testing.AllocsPerRun(count, func() {
  1451. _, err := prototext.MarshalOptions{}.MarshalAppend(b[:0], m)
  1452. if err != nil {
  1453. t.Fatal(err)
  1454. }
  1455. })
  1456. b = nil
  1457. marshalAppendAllocs := testing.AllocsPerRun(count, func() {
  1458. var err error
  1459. b, err = prototext.MarshalOptions{}.MarshalAppend(b, m)
  1460. if err != nil {
  1461. t.Fatal(err)
  1462. }
  1463. })
  1464. if marshalAllocs != marshalAppendAllocs {
  1465. t.Errorf("%v allocs/op when writing to a preallocated buffer", marshalAllocs)
  1466. t.Errorf("%v allocs/op when repeatedly appending to a slice", marshalAppendAllocs)
  1467. t.Errorf("expect amortized allocs/op to be identical")
  1468. }
  1469. }