decode_test.go 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645
  1. package wire
  2. import (
  3. "bytes"
  4. "io"
  5. "testing"
  6. "github.com/stretchr/testify/assert"
  7. )
  8. func TestUnmarshal(t *testing.T) {
  9. tests := []struct {
  10. name string
  11. prototype any
  12. given []byte
  13. want any
  14. wantErr error
  15. }{
  16. {
  17. name: "uint8",
  18. prototype: &struct {
  19. Val uint8
  20. }{},
  21. want: &struct {
  22. Val uint8
  23. }{
  24. Val: 100,
  25. },
  26. given: []byte{0x64},
  27. },
  28. {
  29. name: "uint8 with read error",
  30. prototype: &struct {
  31. Val uint8
  32. }{},
  33. wantErr: io.EOF,
  34. given: []byte{},
  35. },
  36. {
  37. name: "uint16",
  38. prototype: &struct {
  39. Val uint16
  40. }{},
  41. want: &struct {
  42. Val uint16
  43. }{
  44. Val: 100,
  45. },
  46. given: []byte{0x0, 0x64},
  47. },
  48. {
  49. name: "uint16 with read error",
  50. prototype: &struct {
  51. Val uint16
  52. }{},
  53. wantErr: io.EOF,
  54. given: []byte{},
  55. },
  56. {
  57. name: "uint32",
  58. prototype: &struct {
  59. Val uint32
  60. }{},
  61. want: &struct {
  62. Val uint32
  63. }{
  64. Val: 100,
  65. },
  66. given: []byte{0x0, 0x0, 0x0, 0x64},
  67. },
  68. {
  69. name: "uint32 with read error",
  70. prototype: &struct {
  71. Val uint32
  72. }{},
  73. wantErr: io.EOF,
  74. given: []byte{},
  75. },
  76. {
  77. name: "uint64",
  78. prototype: &struct {
  79. Val uint64
  80. }{},
  81. want: &struct {
  82. Val uint64
  83. }{
  84. Val: 100,
  85. },
  86. given: []byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x64},
  87. },
  88. {
  89. name: "uint64 with read error",
  90. prototype: &struct {
  91. Val uint64
  92. }{},
  93. wantErr: io.EOF,
  94. given: []byte{},
  95. },
  96. {
  97. name: "string8",
  98. prototype: &struct {
  99. Val string `oscar:"len_prefix=uint8"`
  100. }{},
  101. want: &struct {
  102. Val string `oscar:"len_prefix=uint8"`
  103. }{
  104. Val: "test-value",
  105. },
  106. given: append(
  107. []byte{0xa}, /* len prefix */
  108. []byte{0x74, 0x65, 0x73, 0x74, 0x2d, 0x76, 0x61, 0x6c, 0x75, 0x65}...), /* str val */
  109. },
  110. {
  111. name: "string8 read error",
  112. prototype: &struct {
  113. Val string `oscar:"len_prefix=uint8"`
  114. }{},
  115. given: []byte{},
  116. wantErr: io.EOF,
  117. },
  118. {
  119. name: "string16",
  120. prototype: &struct {
  121. Val string `oscar:"len_prefix=uint16"`
  122. }{},
  123. want: &struct {
  124. Val string `oscar:"len_prefix=uint16"`
  125. }{
  126. Val: "test-value",
  127. },
  128. given: append(
  129. []byte{0x0, 0xa}, /* len prefix */
  130. []byte{0x74, 0x65, 0x73, 0x74, 0x2d, 0x76, 0x61, 0x6c, 0x75, 0x65}...), /* str val */
  131. },
  132. {
  133. name: "null-terminated string16",
  134. prototype: &struct {
  135. Val string `oscar:"len_prefix=uint16,nullterm"`
  136. }{},
  137. want: &struct {
  138. Val string `oscar:"len_prefix=uint16,nullterm"`
  139. }{
  140. Val: "test-value",
  141. },
  142. given: append(
  143. []byte{0x0, 0xb}, /* len prefix */
  144. []byte{0x74, 0x65, 0x73, 0x74, 0x2d, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00}...), /* str val */
  145. },
  146. {
  147. name: "null-terminated string16 without null terminator",
  148. prototype: &struct {
  149. Val string `oscar:"len_prefix=uint16,nullterm"`
  150. }{},
  151. wantErr: errNotNullTerminated,
  152. given: append(
  153. []byte{0x0, 0xa}, /* len prefix */
  154. []byte{0x74, 0x65, 0x73, 0x74, 0x2d, 0x76, 0x61, 0x6c, 0x75, 0x65}...), /* str val */
  155. },
  156. {
  157. name: "string16 read error",
  158. prototype: &struct {
  159. Val string `oscar:"len_prefix=uint16"`
  160. }{},
  161. given: []byte{},
  162. wantErr: io.EOF,
  163. },
  164. {
  165. name: "unsupported string prefix type",
  166. prototype: &struct {
  167. Val string `oscar:"len_prefix=uint128"`
  168. }{},
  169. wantErr: ErrUnmarshalFailure,
  170. given: append(
  171. []byte{0x0, 0xa}, /* len prefix */
  172. []byte{0x74, 0x65, 0x73, 0x74, 0x2d, 0x76, 0x61, 0x6c, 0x75, 0x65}...), /* str val */
  173. },
  174. {
  175. name: "string with missing len_prefix",
  176. prototype: &struct {
  177. Val string
  178. }{},
  179. wantErr: ErrUnmarshalFailure,
  180. given: append(
  181. []byte{0x0, 0xa}, /* len prefix */
  182. []byte{0x74, 0x65, 0x73, 0x74, 0x2d, 0x76, 0x61, 0x6c, 0x75, 0x65}...), /* str val */
  183. },
  184. {
  185. name: "partial string8",
  186. prototype: &struct {
  187. Val string `oscar:"len_prefix=uint8"`
  188. }{},
  189. wantErr: io.EOF,
  190. given: append(
  191. []byte{0xa}, /* len prefix */
  192. []byte{}...), /* truncated payload */
  193. },
  194. {
  195. name: "byte slice with uint8 len_prefix",
  196. prototype: &struct {
  197. Val []byte `oscar:"len_prefix=uint8"`
  198. }{},
  199. want: &struct {
  200. Val []byte `oscar:"len_prefix=uint8"`
  201. }{
  202. Val: []byte(`hello`),
  203. },
  204. given: append(
  205. []byte{0x05}, /* len prefix */
  206. []byte{0x68, 0x65, 0x6c, 0x6c, 0x6f}...), /* slice val */
  207. },
  208. {
  209. name: "slice of invalid type with uint8 len_prefix",
  210. prototype: &struct {
  211. Val []int `oscar:"len_prefix=uint8"`
  212. }{},
  213. wantErr: ErrUnmarshalFailure,
  214. given: []byte{0x04, 0x65, 0x6c, 0x6c, 0x6f},
  215. },
  216. {
  217. name: "byte slice with uint8 len_prefix with read error",
  218. prototype: &struct {
  219. Val []byte `oscar:"len_prefix=uint8"`
  220. }{},
  221. wantErr: io.EOF,
  222. given: append(
  223. []byte{0x05}, /* len prefix */
  224. []byte{}...), /* slice val */
  225. },
  226. {
  227. name: "byte slice with uint8 len_prefix read error",
  228. prototype: &struct {
  229. Val []byte `oscar:"len_prefix=uint8"`
  230. }{},
  231. wantErr: io.EOF,
  232. given: []byte{},
  233. },
  234. {
  235. name: "byte slice with uint16 len_prefix",
  236. prototype: &struct {
  237. Val []byte `oscar:"len_prefix=uint16"`
  238. }{},
  239. want: &struct {
  240. Val []byte `oscar:"len_prefix=uint16"`
  241. }{
  242. Val: []byte(`hello`),
  243. },
  244. given: append(
  245. []byte{0x00, 0x05}, /* len prefix */
  246. []byte{0x68, 0x65, 0x6c, 0x6c, 0x6f}...), /* slice val */
  247. },
  248. {
  249. name: "byte slice with uint16 len_prefix read error",
  250. prototype: &struct {
  251. Val []byte `oscar:"len_prefix=uint16"`
  252. }{},
  253. wantErr: io.EOF,
  254. given: []byte{},
  255. },
  256. {
  257. name: "byte slice with invalid len_prefix",
  258. prototype: &struct {
  259. Val []byte `oscar:"len_prefix=uint128"`
  260. }{},
  261. wantErr: ErrUnmarshalFailure,
  262. given: append(
  263. []byte{0x00, 0x05}, /* len prefix */
  264. []byte{0x68, 0x65, 0x6c, 0x6c, 0x6f}...), /* slice val */
  265. },
  266. {
  267. name: "struct slice without prefix",
  268. prototype: &struct {
  269. Val []TLV
  270. }{},
  271. want: &struct {
  272. Val []TLV
  273. }{
  274. Val: []TLV{
  275. NewTLV(10, uint16(1234)),
  276. NewTLV(20, uint16(1234)),
  277. },
  278. },
  279. given: []byte{0x0, 0xa, 0x0, 0x2, 0x4, 0xd2, 0x0, 0x14, 0x0, 0x2, 0x4, 0xd2},
  280. },
  281. {
  282. name: "slice of unsupported type without prefix",
  283. prototype: &struct {
  284. Val []int
  285. }{},
  286. wantErr: ErrUnmarshalFailure,
  287. given: []byte{0x0, 0xa, 0x0, 0x2},
  288. },
  289. {
  290. name: "struct slice with uint8 count_prefix",
  291. prototype: &struct {
  292. Val []TLV `oscar:"count_prefix=uint8"`
  293. }{},
  294. want: &struct {
  295. Val []TLV `oscar:"count_prefix=uint8"`
  296. }{
  297. Val: []TLV{
  298. NewTLV(10, uint16(1234)),
  299. NewTLV(20, uint16(1234)),
  300. },
  301. },
  302. given: append(
  303. []byte{0x02}, /* count prefix */
  304. []byte{0x0, 0xa, 0x0, 0x2, 0x4, 0xd2, 0x0, 0x14, 0x0, 0x2, 0x4, 0xd2}...), /* slice val */
  305. },
  306. {
  307. name: "struct slice with uint8 count_prefix and unsupported type",
  308. prototype: &struct {
  309. Val []struct {
  310. Val int16
  311. } `oscar:"count_prefix=uint8"`
  312. }{},
  313. wantErr: ErrUnmarshalFailure,
  314. given: append(
  315. []byte{0x02}, /* count prefix */
  316. []byte{0x0, 0xa, 0x0, 0x2, 0x4, 0xd2, 0x0, 0x14, 0x0, 0x2, 0x4, 0xd2}...), /* slice val */
  317. },
  318. {
  319. name: "struct slice with uint8 count_prefix read error",
  320. prototype: &struct {
  321. Val []TLV `oscar:"count_prefix=uint8"`
  322. }{},
  323. wantErr: io.EOF,
  324. given: []byte{},
  325. },
  326. {
  327. name: "struct slice with uint16 count_prefix",
  328. prototype: &struct {
  329. Val []TLV `oscar:"count_prefix=uint16"`
  330. }{},
  331. want: &struct {
  332. Val []TLV `oscar:"count_prefix=uint16"`
  333. }{
  334. Val: []TLV{
  335. NewTLV(10, uint16(1234)),
  336. NewTLV(20, uint16(1234)),
  337. },
  338. },
  339. given: append(
  340. []byte{0x0, 0x02}, /* count prefix */
  341. []byte{0x0, 0xa, 0x0, 0x2, 0x4, 0xd2, 0x0, 0x14, 0x0, 0x2, 0x4, 0xd2}...), /* slice val */
  342. },
  343. {
  344. name: "struct slice with uint16 count_prefix and unsupported type",
  345. prototype: &struct {
  346. Val []struct {
  347. Val int16
  348. } `oscar:"count_prefix=uint16"`
  349. }{},
  350. wantErr: ErrUnmarshalFailure,
  351. given: append(
  352. []byte{0x0, 0x02}, /* count prefix */
  353. []byte{0x0, 0xa, 0x0, 0x2, 0x4, 0xd2, 0x0, 0x14, 0x0, 0x2, 0x4, 0xd2}...), /* slice val */
  354. },
  355. {
  356. name: "struct slice with uint16 count_prefix read error",
  357. prototype: &struct {
  358. Val []TLV `oscar:"count_prefix=uint16"`
  359. }{},
  360. wantErr: io.EOF,
  361. given: []byte{},
  362. },
  363. {
  364. name: "struct slice with invalid count_prefix",
  365. prototype: &struct {
  366. Val []TLV `oscar:"count_prefix=uint128"`
  367. }{},
  368. wantErr: ErrUnmarshalFailure,
  369. given: append(
  370. []byte{0x0, 0x02}, /* count prefix */
  371. []byte{0x0, 0xa, 0x0, 0x2, 0x4, 0xd2, 0x0, 0x14, 0x0, 0x2, 0x4, 0xd2}...), /* slice val */
  372. },
  373. {
  374. name: "struct with uint8 len_prefix",
  375. prototype: &struct {
  376. Val0 uint8
  377. Val1 struct {
  378. Val2 uint16
  379. Val3 uint8
  380. } `oscar:"len_prefix=uint8"`
  381. Val4 uint16
  382. }{},
  383. want: &struct {
  384. Val0 uint8
  385. Val1 struct {
  386. Val2 uint16
  387. Val3 uint8
  388. } `oscar:"len_prefix=uint8"`
  389. Val4 uint16
  390. }{
  391. Val0: 34,
  392. Val1: struct {
  393. Val2 uint16
  394. Val3 uint8
  395. }{
  396. Val2: 16,
  397. Val3: 10,
  398. },
  399. Val4: 32,
  400. },
  401. given: []byte{
  402. 0x22, // Val0
  403. 0x03, // Val1 struct len
  404. 0x00, 0x10, // Val2
  405. 0x0A, // Val3
  406. 0x00, 0x20, // Val2
  407. },
  408. },
  409. {
  410. name: "struct with uint16 len_prefix",
  411. prototype: &struct {
  412. Val0 uint8
  413. Val1 struct {
  414. Val2 uint16
  415. Val3 uint8
  416. } `oscar:"len_prefix=uint16"`
  417. Val4 uint16
  418. }{},
  419. want: &struct {
  420. Val0 uint8
  421. Val1 struct {
  422. Val2 uint16
  423. Val3 uint8
  424. } `oscar:"len_prefix=uint16"`
  425. Val4 uint16
  426. }{
  427. Val0: 34,
  428. Val1: struct {
  429. Val2 uint16
  430. Val3 uint8
  431. }{
  432. Val2: 16,
  433. Val3: 10,
  434. },
  435. Val4: 32,
  436. },
  437. given: []byte{
  438. 0x22, // Val0
  439. 0x00, 0x03, // Val1 struct len
  440. 0x00, 0x10, // Val2
  441. 0x0A, // Val3
  442. 0x00, 0x20, // Val2
  443. },
  444. },
  445. {
  446. name: "struct with uint16 len_prefix with read error",
  447. prototype: &struct {
  448. Val1 struct {
  449. Val2 uint16
  450. } `oscar:"len_prefix=uint16"`
  451. }{},
  452. given: []byte{
  453. 0x00, 0x10, // 16 byte len, but the body is truncated
  454. },
  455. wantErr: io.EOF,
  456. },
  457. {
  458. name: "struct with unknown len_prefix",
  459. prototype: &struct {
  460. Val1 struct {
  461. Val2 uint16
  462. } `oscar:"len_prefix=uint128"`
  463. }{},
  464. wantErr: ErrUnmarshalFailure,
  465. },
  466. {
  467. name: "optional struct has value",
  468. prototype: &struct {
  469. Val0 uint16
  470. Optional *struct {
  471. Val1 uint16
  472. } `oscar:"optional"`
  473. }{},
  474. want: &struct {
  475. Val0 uint16
  476. Optional *struct {
  477. Val1 uint16
  478. } `oscar:"optional"`
  479. }{
  480. Val0: 34,
  481. Optional: &struct {
  482. Val1 uint16
  483. }{
  484. Val1: 100,
  485. },
  486. },
  487. given: []byte{
  488. 0x00, 0x22, // Val0
  489. 0x00, 0x64, // Val1
  490. },
  491. },
  492. {
  493. name: "optional struct with value missing `optional` struct tag",
  494. prototype: &struct {
  495. Val0 uint16
  496. Optional *struct {
  497. Val1 uint16
  498. }
  499. }{},
  500. given: []byte{
  501. 0x00, 0x22, // Val0
  502. 0x00, 0x64, // Val1
  503. },
  504. wantErr: ErrUnmarshalFailure,
  505. },
  506. {
  507. name: "optional struct doesn't have value",
  508. prototype: &struct {
  509. Val0 uint16
  510. Optional *struct {
  511. Val1 uint16
  512. } `oscar:"optional"`
  513. }{},
  514. want: &struct {
  515. Val0 uint16
  516. Optional *struct {
  517. Val1 uint16
  518. } `oscar:"optional"`
  519. }{
  520. Val0: 34,
  521. Optional: nil,
  522. },
  523. given: []byte{
  524. 0x00, 0x22, // Val0
  525. },
  526. },
  527. {
  528. name: "optional struct followed by value throws error",
  529. prototype: &struct {
  530. Optional *struct {
  531. Val0 uint16
  532. } `oscar:"optional"`
  533. Val1 uint16
  534. }{},
  535. wantErr: ErrUnmarshalFailure,
  536. given: []byte{
  537. 0x00, 0x22, // Val0
  538. 0x00, 0x22, // Val1
  539. },
  540. },
  541. {
  542. name: "optional non-struct field throws error",
  543. prototype: &struct {
  544. Optional *uint16 `oscar:"optional"`
  545. }{},
  546. wantErr: ErrUnmarshalFailure,
  547. given: []byte{
  548. 0x00, 0x22, // Val0
  549. },
  550. },
  551. {
  552. name: "non-struct pointer value throws error",
  553. prototype: func() any {
  554. val := 10
  555. ptr1 := &val
  556. return &ptr1
  557. }(),
  558. wantErr: ErrUnmarshalFailure,
  559. given: []byte{
  560. 0x00, 0x22, // Val0
  561. },
  562. },
  563. {
  564. name: "optional struct with uint16 len_prefix and value",
  565. prototype: &struct {
  566. Val0 uint8
  567. Val1 *struct {
  568. Val2 uint16
  569. Val3 uint8
  570. } `oscar:"len_prefix=uint16,optional"`
  571. }{},
  572. want: &struct {
  573. Val0 uint8
  574. Val1 *struct {
  575. Val2 uint16
  576. Val3 uint8
  577. } `oscar:"len_prefix=uint16,optional"`
  578. }{
  579. Val0: 34,
  580. Val1: &struct {
  581. Val2 uint16
  582. Val3 uint8
  583. }{
  584. Val2: 16,
  585. Val3: 10,
  586. },
  587. },
  588. given: []byte{
  589. 0x22, // Val0
  590. 0x00, 0x03, // Val1 struct len
  591. 0x00, 0x10, // Val2
  592. 0x0A, // Val3
  593. 0x00, 0x20, // Val2
  594. },
  595. },
  596. {
  597. name: "optional struct with uint16 len_prefix and no value",
  598. prototype: &struct {
  599. Val0 uint8
  600. Val1 *struct {
  601. Val2 uint16
  602. Val3 uint8
  603. } `oscar:"len_prefix=uint16,optional"`
  604. }{},
  605. want: &struct {
  606. Val0 uint8
  607. Val1 *struct {
  608. Val2 uint16
  609. Val3 uint8
  610. } `oscar:"len_prefix=uint16,optional"`
  611. }{
  612. Val0: 34,
  613. Val1: nil,
  614. },
  615. given: []byte{
  616. 0x22, // Val0
  617. },
  618. },
  619. {
  620. name: "optional field that isn't a pointer to a struct is unsupported",
  621. prototype: &struct {
  622. Val1 *string `oscar:"optional"`
  623. }{},
  624. given: []byte{
  625. 0x00,
  626. },
  627. wantErr: errNonOptionalPointer,
  628. },
  629. }
  630. for _, tt := range tests {
  631. t.Run(tt.name, func(t *testing.T) {
  632. r := bytes.NewBuffer(tt.given)
  633. err := UnmarshalBE(tt.prototype, r)
  634. assert.ErrorIs(t, err, tt.wantErr)
  635. if tt.wantErr == nil {
  636. assert.Equal(t, tt.want, tt.prototype)
  637. }
  638. })
  639. }
  640. }