wire_test.go 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680
  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 protowire
  5. import (
  6. "bytes"
  7. "encoding/hex"
  8. "io"
  9. "math"
  10. "strings"
  11. "testing"
  12. )
  13. type (
  14. testOps struct {
  15. // appendOps is a sequence of append operations, each appending to
  16. // the output of the previous append operation.
  17. appendOps []appendOp
  18. // wantRaw (if not nil) is the bytes that the appendOps should produce.
  19. wantRaw []byte
  20. // consumeOps are a sequence of consume operations, each consuming the
  21. // remaining output after the previous consume operation.
  22. // The first consume operation starts with the output of appendOps.
  23. consumeOps []consumeOp
  24. }
  25. // appendOp represents an Append operation.
  26. appendOp = interface{}
  27. appendTag struct {
  28. inNum Number
  29. inType Type
  30. }
  31. appendVarint struct {
  32. inVal uint64
  33. }
  34. appendFixed32 struct {
  35. inVal uint32
  36. }
  37. appendFixed64 struct {
  38. inVal uint64
  39. }
  40. appendBytes struct {
  41. inVal []byte
  42. }
  43. appendGroup struct {
  44. inNum Number
  45. inVal []byte
  46. }
  47. appendRaw []byte
  48. // consumeOp represents an Consume operation.
  49. consumeOp = interface{}
  50. consumeField struct {
  51. wantNum Number
  52. wantType Type
  53. wantCnt int
  54. wantErr error
  55. }
  56. consumeFieldValue struct {
  57. inNum Number
  58. inType Type
  59. wantCnt int
  60. wantErr error
  61. }
  62. consumeTag struct {
  63. wantNum Number
  64. wantType Type
  65. wantCnt int
  66. wantErr error
  67. }
  68. consumeVarint struct {
  69. wantVal uint64
  70. wantCnt int
  71. wantErr error
  72. }
  73. consumeFixed32 struct {
  74. wantVal uint32
  75. wantCnt int
  76. wantErr error
  77. }
  78. consumeFixed64 struct {
  79. wantVal uint64
  80. wantCnt int
  81. wantErr error
  82. }
  83. consumeBytes struct {
  84. wantVal []byte
  85. wantCnt int
  86. wantErr error
  87. }
  88. consumeGroup struct {
  89. inNum Number
  90. wantVal []byte
  91. wantCnt int
  92. wantErr error
  93. }
  94. ops []interface{}
  95. )
  96. // dhex decodes a hex-string and returns the bytes and panics if s is invalid.
  97. func dhex(s string) []byte {
  98. b, err := hex.DecodeString(s)
  99. if err != nil {
  100. panic(err)
  101. }
  102. return b
  103. }
  104. func TestTag(t *testing.T) {
  105. runTests(t, []testOps{{
  106. appendOps: ops{appendRaw(dhex(""))},
  107. consumeOps: ops{consumeTag{wantErr: io.ErrUnexpectedEOF}},
  108. }, {
  109. appendOps: ops{appendTag{inNum: 0, inType: Fixed32Type}},
  110. wantRaw: dhex("05"),
  111. consumeOps: ops{consumeTag{wantErr: errFieldNumber}},
  112. }, {
  113. appendOps: ops{appendTag{inNum: 1, inType: Fixed32Type}},
  114. wantRaw: dhex("0d"),
  115. consumeOps: ops{consumeTag{wantNum: 1, wantType: Fixed32Type, wantCnt: 1}},
  116. }, {
  117. appendOps: ops{appendTag{inNum: FirstReservedNumber, inType: BytesType}},
  118. wantRaw: dhex("c2a309"),
  119. consumeOps: ops{consumeTag{wantNum: FirstReservedNumber, wantType: BytesType, wantCnt: 3}},
  120. }, {
  121. appendOps: ops{appendTag{inNum: LastReservedNumber, inType: StartGroupType}},
  122. wantRaw: dhex("fbe109"),
  123. consumeOps: ops{consumeTag{wantNum: LastReservedNumber, wantType: StartGroupType, wantCnt: 3}},
  124. }, {
  125. appendOps: ops{appendTag{inNum: MaxValidNumber, inType: VarintType}},
  126. wantRaw: dhex("f8ffffff0f"),
  127. consumeOps: ops{consumeTag{wantNum: MaxValidNumber, wantType: VarintType, wantCnt: 5}},
  128. }, {
  129. appendOps: ops{appendVarint{inVal: ((math.MaxInt32+1)<<3 | uint64(VarintType))}},
  130. wantRaw: dhex("8080808040"),
  131. consumeOps: ops{consumeTag{wantErr: errFieldNumber}},
  132. }})
  133. }
  134. func TestVarint(t *testing.T) {
  135. runTests(t, []testOps{{
  136. appendOps: ops{appendRaw(dhex(""))},
  137. consumeOps: ops{consumeVarint{wantErr: io.ErrUnexpectedEOF}},
  138. }, {
  139. appendOps: ops{appendRaw(dhex("80"))},
  140. consumeOps: ops{consumeVarint{wantErr: io.ErrUnexpectedEOF}},
  141. }, {
  142. appendOps: ops{appendRaw(dhex("8080"))},
  143. consumeOps: ops{consumeVarint{wantErr: io.ErrUnexpectedEOF}},
  144. }, {
  145. appendOps: ops{appendRaw(dhex("808080"))},
  146. consumeOps: ops{consumeVarint{wantErr: io.ErrUnexpectedEOF}},
  147. }, {
  148. appendOps: ops{appendRaw(dhex("80808080"))},
  149. consumeOps: ops{consumeVarint{wantErr: io.ErrUnexpectedEOF}},
  150. }, {
  151. appendOps: ops{appendRaw(dhex("8080808080"))},
  152. consumeOps: ops{consumeVarint{wantErr: io.ErrUnexpectedEOF}},
  153. }, {
  154. appendOps: ops{appendRaw(dhex("808080808080"))},
  155. consumeOps: ops{consumeVarint{wantErr: io.ErrUnexpectedEOF}},
  156. }, {
  157. appendOps: ops{appendRaw(dhex("80808080808080"))},
  158. consumeOps: ops{consumeVarint{wantErr: io.ErrUnexpectedEOF}},
  159. }, {
  160. appendOps: ops{appendRaw(dhex("8080808080808080"))},
  161. consumeOps: ops{consumeVarint{wantErr: io.ErrUnexpectedEOF}},
  162. }, {
  163. appendOps: ops{appendRaw(dhex("808080808080808080"))},
  164. consumeOps: ops{consumeVarint{wantErr: io.ErrUnexpectedEOF}},
  165. }, {
  166. appendOps: ops{appendRaw(dhex("80808080808080808080"))},
  167. consumeOps: ops{consumeVarint{wantErr: errOverflow}},
  168. }, {
  169. // Test varints at various boundaries where the length changes.
  170. appendOps: ops{appendVarint{inVal: 0x0}},
  171. wantRaw: dhex("00"),
  172. consumeOps: ops{consumeVarint{wantVal: 0, wantCnt: 1}},
  173. }, {
  174. appendOps: ops{appendVarint{inVal: 0x1}},
  175. wantRaw: dhex("01"),
  176. consumeOps: ops{consumeVarint{wantVal: 1, wantCnt: 1}},
  177. }, {
  178. appendOps: ops{appendVarint{inVal: 0x7f}},
  179. wantRaw: dhex("7f"),
  180. consumeOps: ops{consumeVarint{wantVal: 0x7f, wantCnt: 1}},
  181. }, {
  182. appendOps: ops{appendVarint{inVal: 0x7f + 1}},
  183. wantRaw: dhex("8001"),
  184. consumeOps: ops{consumeVarint{wantVal: 0x7f + 1, wantCnt: 2}},
  185. }, {
  186. appendOps: ops{appendVarint{inVal: 0x3fff}},
  187. wantRaw: dhex("ff7f"),
  188. consumeOps: ops{consumeVarint{wantVal: 0x3fff, wantCnt: 2}},
  189. }, {
  190. appendOps: ops{appendVarint{inVal: 0x3fff + 1}},
  191. wantRaw: dhex("808001"),
  192. consumeOps: ops{consumeVarint{wantVal: 0x3fff + 1, wantCnt: 3}},
  193. }, {
  194. appendOps: ops{appendVarint{inVal: 0x1fffff}},
  195. wantRaw: dhex("ffff7f"),
  196. consumeOps: ops{consumeVarint{wantVal: 0x1fffff, wantCnt: 3}},
  197. }, {
  198. appendOps: ops{appendVarint{inVal: 0x1fffff + 1}},
  199. wantRaw: dhex("80808001"),
  200. consumeOps: ops{consumeVarint{wantVal: 0x1fffff + 1, wantCnt: 4}},
  201. }, {
  202. appendOps: ops{appendVarint{inVal: 0xfffffff}},
  203. wantRaw: dhex("ffffff7f"),
  204. consumeOps: ops{consumeVarint{wantVal: 0xfffffff, wantCnt: 4}},
  205. }, {
  206. appendOps: ops{appendVarint{inVal: 0xfffffff + 1}},
  207. wantRaw: dhex("8080808001"),
  208. consumeOps: ops{consumeVarint{wantVal: 0xfffffff + 1, wantCnt: 5}},
  209. }, {
  210. appendOps: ops{appendVarint{inVal: 0x7ffffffff}},
  211. wantRaw: dhex("ffffffff7f"),
  212. consumeOps: ops{consumeVarint{wantVal: 0x7ffffffff, wantCnt: 5}},
  213. }, {
  214. appendOps: ops{appendVarint{inVal: 0x7ffffffff + 1}},
  215. wantRaw: dhex("808080808001"),
  216. consumeOps: ops{consumeVarint{wantVal: 0x7ffffffff + 1, wantCnt: 6}},
  217. }, {
  218. appendOps: ops{appendVarint{inVal: 0x3ffffffffff}},
  219. wantRaw: dhex("ffffffffff7f"),
  220. consumeOps: ops{consumeVarint{wantVal: 0x3ffffffffff, wantCnt: 6}},
  221. }, {
  222. appendOps: ops{appendVarint{inVal: 0x3ffffffffff + 1}},
  223. wantRaw: dhex("80808080808001"),
  224. consumeOps: ops{consumeVarint{wantVal: 0x3ffffffffff + 1, wantCnt: 7}},
  225. }, {
  226. appendOps: ops{appendVarint{inVal: 0x1ffffffffffff}},
  227. wantRaw: dhex("ffffffffffff7f"),
  228. consumeOps: ops{consumeVarint{wantVal: 0x1ffffffffffff, wantCnt: 7}},
  229. }, {
  230. appendOps: ops{appendVarint{inVal: 0x1ffffffffffff + 1}},
  231. wantRaw: dhex("8080808080808001"),
  232. consumeOps: ops{consumeVarint{wantVal: 0x1ffffffffffff + 1, wantCnt: 8}},
  233. }, {
  234. appendOps: ops{appendVarint{inVal: 0xffffffffffffff}},
  235. wantRaw: dhex("ffffffffffffff7f"),
  236. consumeOps: ops{consumeVarint{wantVal: 0xffffffffffffff, wantCnt: 8}},
  237. }, {
  238. appendOps: ops{appendVarint{inVal: 0xffffffffffffff + 1}},
  239. wantRaw: dhex("808080808080808001"),
  240. consumeOps: ops{consumeVarint{wantVal: 0xffffffffffffff + 1, wantCnt: 9}},
  241. }, {
  242. appendOps: ops{appendVarint{inVal: 0x7fffffffffffffff}},
  243. wantRaw: dhex("ffffffffffffffff7f"),
  244. consumeOps: ops{consumeVarint{wantVal: 0x7fffffffffffffff, wantCnt: 9}},
  245. }, {
  246. appendOps: ops{appendVarint{inVal: 0x7fffffffffffffff + 1}},
  247. wantRaw: dhex("80808080808080808001"),
  248. consumeOps: ops{consumeVarint{wantVal: 0x7fffffffffffffff + 1, wantCnt: 10}},
  249. }, {
  250. appendOps: ops{appendVarint{inVal: math.MaxUint64}},
  251. wantRaw: dhex("ffffffffffffffffff01"),
  252. consumeOps: ops{consumeVarint{wantVal: math.MaxUint64, wantCnt: 10}},
  253. }, {
  254. appendOps: ops{appendRaw(dhex("ffffffffffffffffff02"))},
  255. consumeOps: ops{consumeVarint{wantErr: errOverflow}},
  256. }, {
  257. // Test denormalized varints; where the encoding, while valid, is
  258. // larger than necessary.
  259. appendOps: ops{appendRaw(dhex("01"))},
  260. consumeOps: ops{consumeVarint{wantVal: 1, wantCnt: 1}},
  261. }, {
  262. appendOps: ops{appendRaw(dhex("8100"))},
  263. consumeOps: ops{consumeVarint{wantVal: 1, wantCnt: 2}},
  264. }, {
  265. appendOps: ops{appendRaw(dhex("818000"))},
  266. consumeOps: ops{consumeVarint{wantVal: 1, wantCnt: 3}},
  267. }, {
  268. appendOps: ops{appendRaw(dhex("81808000"))},
  269. consumeOps: ops{consumeVarint{wantVal: 1, wantCnt: 4}},
  270. }, {
  271. appendOps: ops{appendRaw(dhex("8180808000"))},
  272. consumeOps: ops{consumeVarint{wantVal: 1, wantCnt: 5}},
  273. }, {
  274. appendOps: ops{appendRaw(dhex("818080808000"))},
  275. consumeOps: ops{consumeVarint{wantVal: 1, wantCnt: 6}},
  276. }, {
  277. appendOps: ops{appendRaw(dhex("81808080808000"))},
  278. consumeOps: ops{consumeVarint{wantVal: 1, wantCnt: 7}},
  279. }, {
  280. appendOps: ops{appendRaw(dhex("8180808080808000"))},
  281. consumeOps: ops{consumeVarint{wantVal: 1, wantCnt: 8}},
  282. }, {
  283. appendOps: ops{appendRaw(dhex("818080808080808000"))},
  284. consumeOps: ops{consumeVarint{wantVal: 1, wantCnt: 9}},
  285. }, {
  286. appendOps: ops{appendRaw(dhex("81808080808080808000"))},
  287. consumeOps: ops{consumeVarint{wantVal: 1, wantCnt: 10}},
  288. }, {
  289. appendOps: ops{appendRaw(dhex("8180808080808080808000"))},
  290. consumeOps: ops{consumeVarint{wantErr: errOverflow}},
  291. }})
  292. }
  293. func TestFixed32(t *testing.T) {
  294. runTests(t, []testOps{{
  295. appendOps: ops{appendRaw(dhex(""))},
  296. consumeOps: ops{consumeFixed32{wantErr: io.ErrUnexpectedEOF}},
  297. }, {
  298. appendOps: ops{appendRaw(dhex("000000"))},
  299. consumeOps: ops{consumeFixed32{wantErr: io.ErrUnexpectedEOF}},
  300. }, {
  301. appendOps: ops{appendFixed32{0}},
  302. wantRaw: dhex("00000000"),
  303. consumeOps: ops{consumeFixed32{wantVal: 0, wantCnt: 4}},
  304. }, {
  305. appendOps: ops{appendFixed32{math.MaxUint32}},
  306. wantRaw: dhex("ffffffff"),
  307. consumeOps: ops{consumeFixed32{wantVal: math.MaxUint32, wantCnt: 4}},
  308. }, {
  309. appendOps: ops{appendFixed32{0xf0e1d2c3}},
  310. wantRaw: dhex("c3d2e1f0"),
  311. consumeOps: ops{consumeFixed32{wantVal: 0xf0e1d2c3, wantCnt: 4}},
  312. }})
  313. }
  314. func TestFixed64(t *testing.T) {
  315. runTests(t, []testOps{{
  316. appendOps: ops{appendRaw(dhex(""))},
  317. consumeOps: ops{consumeFixed64{wantErr: io.ErrUnexpectedEOF}},
  318. }, {
  319. appendOps: ops{appendRaw(dhex("00000000000000"))},
  320. consumeOps: ops{consumeFixed64{wantErr: io.ErrUnexpectedEOF}},
  321. }, {
  322. appendOps: ops{appendFixed64{0}},
  323. wantRaw: dhex("0000000000000000"),
  324. consumeOps: ops{consumeFixed64{wantVal: 0, wantCnt: 8}},
  325. }, {
  326. appendOps: ops{appendFixed64{math.MaxUint64}},
  327. wantRaw: dhex("ffffffffffffffff"),
  328. consumeOps: ops{consumeFixed64{wantVal: math.MaxUint64, wantCnt: 8}},
  329. }, {
  330. appendOps: ops{appendFixed64{0xf0e1d2c3b4a59687}},
  331. wantRaw: dhex("8796a5b4c3d2e1f0"),
  332. consumeOps: ops{consumeFixed64{wantVal: 0xf0e1d2c3b4a59687, wantCnt: 8}},
  333. }})
  334. }
  335. func TestBytes(t *testing.T) {
  336. runTests(t, []testOps{{
  337. appendOps: ops{appendRaw(dhex(""))},
  338. consumeOps: ops{consumeBytes{wantErr: io.ErrUnexpectedEOF}},
  339. }, {
  340. appendOps: ops{appendRaw(dhex("01"))},
  341. consumeOps: ops{consumeBytes{wantErr: io.ErrUnexpectedEOF}},
  342. }, {
  343. appendOps: ops{appendVarint{0}, appendRaw("")},
  344. wantRaw: dhex("00"),
  345. consumeOps: ops{consumeBytes{wantVal: dhex(""), wantCnt: 1}},
  346. }, {
  347. appendOps: ops{appendBytes{[]byte("hello")}},
  348. wantRaw: []byte("\x05hello"),
  349. consumeOps: ops{consumeBytes{wantVal: []byte("hello"), wantCnt: 6}},
  350. }, {
  351. appendOps: ops{appendBytes{[]byte(strings.Repeat("hello", 50))}},
  352. wantRaw: []byte("\xfa\x01" + strings.Repeat("hello", 50)),
  353. consumeOps: ops{consumeBytes{wantVal: []byte(strings.Repeat("hello", 50)), wantCnt: 252}},
  354. }, {
  355. appendOps: ops{appendRaw("\x85\x80\x00hello")},
  356. consumeOps: ops{consumeBytes{wantVal: []byte("hello"), wantCnt: 8}},
  357. }, {
  358. appendOps: ops{appendRaw("\x85\x80\x00hell")},
  359. consumeOps: ops{consumeBytes{wantErr: io.ErrUnexpectedEOF}},
  360. }})
  361. }
  362. func TestGroup(t *testing.T) {
  363. runTests(t, []testOps{{
  364. appendOps: ops{appendRaw(dhex(""))},
  365. consumeOps: ops{consumeGroup{wantErr: io.ErrUnexpectedEOF}},
  366. }, {
  367. appendOps: ops{appendTag{inNum: 0, inType: StartGroupType}},
  368. consumeOps: ops{consumeGroup{inNum: 1, wantErr: errFieldNumber}},
  369. }, {
  370. appendOps: ops{appendTag{inNum: 2, inType: EndGroupType}},
  371. consumeOps: ops{consumeGroup{inNum: 1, wantErr: errEndGroup}},
  372. }, {
  373. appendOps: ops{appendTag{inNum: 1, inType: EndGroupType}},
  374. consumeOps: ops{consumeGroup{inNum: 1, wantCnt: 1}},
  375. }, {
  376. appendOps: ops{
  377. appendTag{inNum: 5, inType: Fixed32Type},
  378. appendFixed32{0xf0e1d2c3},
  379. appendTag{inNum: 5, inType: EndGroupType},
  380. },
  381. wantRaw: dhex("2dc3d2e1f02c"),
  382. consumeOps: ops{consumeGroup{inNum: 5, wantVal: dhex("2dc3d2e1f0"), wantCnt: 6}},
  383. }, {
  384. appendOps: ops{
  385. appendTag{inNum: 5, inType: Fixed32Type},
  386. appendFixed32{0xf0e1d2c3},
  387. appendRaw(dhex("ac808000")),
  388. },
  389. consumeOps: ops{consumeGroup{inNum: 5, wantVal: dhex("2dc3d2e1f0"), wantCnt: 9}},
  390. }})
  391. }
  392. func TestField(t *testing.T) {
  393. runTests(t, []testOps{{
  394. appendOps: ops{appendRaw(dhex(""))},
  395. consumeOps: ops{consumeField{wantErr: io.ErrUnexpectedEOF}},
  396. }, {
  397. appendOps: ops{
  398. appendTag{inNum: 5000, inType: StartGroupType},
  399. appendTag{inNum: 1, inType: VarintType},
  400. appendVarint{123456789},
  401. appendTag{inNum: 12, inType: Fixed32Type},
  402. appendFixed32{123456789},
  403. appendTag{inNum: 123, inType: Fixed64Type},
  404. appendFixed64{123456789},
  405. appendTag{inNum: 1234, inType: BytesType},
  406. appendBytes{[]byte("hello")},
  407. appendTag{inNum: 12345, inType: StartGroupType},
  408. appendTag{inNum: 11, inType: VarintType},
  409. appendVarint{123456789},
  410. appendTag{inNum: 1212, inType: Fixed32Type},
  411. appendFixed32{123456789},
  412. appendTag{inNum: 123123, inType: Fixed64Type},
  413. appendFixed64{123456789},
  414. appendTag{inNum: 12341234, inType: BytesType},
  415. appendBytes{[]byte("goodbye")},
  416. appendTag{inNum: 12345, inType: EndGroupType},
  417. appendTag{inNum: 5000, inType: EndGroupType},
  418. },
  419. wantRaw: dhex("c3b80208959aef3a6515cd5b07d90715cd5b0700000000924d0568656c6c6fcb830658959aef3ae54b15cd5b07998f3c15cd5b070000000092ff892f07676f6f64627965cc8306c4b802"),
  420. consumeOps: ops{
  421. consumeTag{wantNum: 5000, wantType: StartGroupType, wantCnt: 3},
  422. consumeTag{wantNum: 1, wantType: VarintType, wantCnt: 1},
  423. consumeVarint{wantVal: 123456789, wantCnt: 4},
  424. consumeTag{wantNum: 12, wantType: Fixed32Type, wantCnt: 1},
  425. consumeFixed32{wantVal: 123456789, wantCnt: 4},
  426. consumeTag{wantNum: 123, wantType: Fixed64Type, wantCnt: 2},
  427. consumeFixed64{wantVal: 123456789, wantCnt: 8},
  428. consumeTag{wantNum: 1234, wantType: BytesType, wantCnt: 2},
  429. consumeBytes{wantVal: []byte("hello"), wantCnt: 6},
  430. consumeTag{wantNum: 12345, wantType: StartGroupType, wantCnt: 3},
  431. consumeTag{wantNum: 11, wantType: VarintType, wantCnt: 1},
  432. consumeVarint{wantVal: 123456789, wantCnt: 4},
  433. consumeTag{wantNum: 1212, wantType: Fixed32Type, wantCnt: 2},
  434. consumeFixed32{wantVal: 123456789, wantCnt: 4},
  435. consumeTag{wantNum: 123123, wantType: Fixed64Type, wantCnt: 3},
  436. consumeFixed64{wantVal: 123456789, wantCnt: 8},
  437. consumeTag{wantNum: 12341234, wantType: BytesType, wantCnt: 4},
  438. consumeBytes{wantVal: []byte("goodbye"), wantCnt: 8},
  439. consumeTag{wantNum: 12345, wantType: EndGroupType, wantCnt: 3},
  440. consumeTag{wantNum: 5000, wantType: EndGroupType, wantCnt: 3},
  441. },
  442. }, {
  443. appendOps: ops{appendRaw(dhex("c3b80208959aef3a6515cd5b07d90715cd5b0700000000924d0568656c6c6fcb830658959aef3ae54b15cd5b07998f3c15cd5b070000000092ff892f07676f6f64627965cc8306c4b802"))},
  444. consumeOps: ops{consumeField{wantNum: 5000, wantType: StartGroupType, wantCnt: 74}},
  445. }, {
  446. appendOps: ops{appendTag{inNum: 5, inType: EndGroupType}},
  447. wantRaw: dhex("2c"),
  448. consumeOps: ops{consumeField{wantErr: errEndGroup}},
  449. }, {
  450. appendOps: ops{
  451. appendTag{inNum: 1, inType: StartGroupType},
  452. appendTag{inNum: 22, inType: StartGroupType},
  453. appendTag{inNum: 333, inType: StartGroupType},
  454. appendTag{inNum: 4444, inType: StartGroupType},
  455. appendTag{inNum: 4444, inType: EndGroupType},
  456. appendTag{inNum: 333, inType: EndGroupType},
  457. appendTag{inNum: 22, inType: EndGroupType},
  458. appendTag{inNum: 1, inType: EndGroupType},
  459. },
  460. wantRaw: dhex("0bb301eb14e39502e49502ec14b4010c"),
  461. consumeOps: ops{consumeField{wantNum: 1, wantType: StartGroupType, wantCnt: 16}},
  462. }, {
  463. appendOps: ops{
  464. appendTag{inNum: 1, inType: StartGroupType},
  465. appendGroup{inNum: 1, inVal: dhex("b301eb14e39502e49502ec14b401")},
  466. },
  467. wantRaw: dhex("0b" + "b301eb14e39502e49502ec14b401" + "0c"),
  468. consumeOps: ops{consumeField{wantNum: 1, wantType: StartGroupType, wantCnt: 16}},
  469. }, {
  470. appendOps: ops{
  471. appendTag{inNum: 1, inType: StartGroupType},
  472. appendTag{inNum: 22, inType: StartGroupType},
  473. appendTag{inNum: 333, inType: StartGroupType},
  474. appendTag{inNum: 4444, inType: StartGroupType},
  475. appendTag{inNum: 333, inType: EndGroupType},
  476. appendTag{inNum: 22, inType: EndGroupType},
  477. appendTag{inNum: 1, inType: EndGroupType},
  478. },
  479. consumeOps: ops{consumeField{wantErr: errEndGroup}},
  480. }, {
  481. appendOps: ops{
  482. appendTag{inNum: 1, inType: StartGroupType},
  483. appendTag{inNum: 22, inType: StartGroupType},
  484. appendTag{inNum: 333, inType: StartGroupType},
  485. appendTag{inNum: 4444, inType: StartGroupType},
  486. appendTag{inNum: 4444, inType: EndGroupType},
  487. appendTag{inNum: 333, inType: EndGroupType},
  488. appendTag{inNum: 22, inType: EndGroupType},
  489. },
  490. consumeOps: ops{consumeField{wantErr: io.ErrUnexpectedEOF}},
  491. }, {
  492. appendOps: ops{
  493. appendTag{inNum: 1, inType: StartGroupType},
  494. appendTag{inNum: 22, inType: StartGroupType},
  495. appendTag{inNum: 333, inType: StartGroupType},
  496. appendTag{inNum: 4444, inType: StartGroupType},
  497. appendTag{inNum: 0, inType: VarintType},
  498. appendTag{inNum: 4444, inType: EndGroupType},
  499. appendTag{inNum: 333, inType: EndGroupType},
  500. appendTag{inNum: 22, inType: EndGroupType},
  501. appendTag{inNum: 1, inType: EndGroupType},
  502. },
  503. consumeOps: ops{consumeField{wantErr: errFieldNumber}},
  504. }, {
  505. appendOps: ops{
  506. appendTag{inNum: 1, inType: StartGroupType},
  507. appendTag{inNum: 22, inType: StartGroupType},
  508. appendTag{inNum: 333, inType: StartGroupType},
  509. appendTag{inNum: 4444, inType: StartGroupType},
  510. appendTag{inNum: 1, inType: 6},
  511. appendTag{inNum: 4444, inType: EndGroupType},
  512. appendTag{inNum: 333, inType: EndGroupType},
  513. appendTag{inNum: 22, inType: EndGroupType},
  514. appendTag{inNum: 1, inType: EndGroupType},
  515. },
  516. consumeOps: ops{consumeField{wantErr: errReserved}},
  517. }})
  518. }
  519. func runTests(t *testing.T, tests []testOps) {
  520. for _, tt := range tests {
  521. t.Run("", func(t *testing.T) {
  522. var b []byte
  523. for _, op := range tt.appendOps {
  524. b0 := b
  525. switch op := op.(type) {
  526. case appendTag:
  527. b = AppendTag(b, op.inNum, op.inType)
  528. case appendVarint:
  529. b = AppendVarint(b, op.inVal)
  530. case appendFixed32:
  531. b = AppendFixed32(b, op.inVal)
  532. case appendFixed64:
  533. b = AppendFixed64(b, op.inVal)
  534. case appendBytes:
  535. b = AppendBytes(b, op.inVal)
  536. case appendGroup:
  537. b = AppendGroup(b, op.inNum, op.inVal)
  538. case appendRaw:
  539. b = append(b, op...)
  540. }
  541. check := func(label string, want int) {
  542. t.Helper()
  543. if got := len(b) - len(b0); got != want {
  544. t.Errorf("len(Append%v) and Size%v mismatch: got %v, want %v", label, label, got, want)
  545. }
  546. }
  547. switch op := op.(type) {
  548. case appendTag:
  549. check("Tag", SizeTag(op.inNum))
  550. case appendVarint:
  551. check("Varint", SizeVarint(op.inVal))
  552. case appendFixed32:
  553. check("Fixed32", SizeFixed32())
  554. case appendFixed64:
  555. check("Fixed64", SizeFixed64())
  556. case appendBytes:
  557. check("Bytes", SizeBytes(len(op.inVal)))
  558. case appendGroup:
  559. check("Group", SizeGroup(op.inNum, len(op.inVal)))
  560. }
  561. }
  562. if tt.wantRaw != nil && !bytes.Equal(b, tt.wantRaw) {
  563. t.Errorf("raw output mismatch:\ngot %x\nwant %x", b, tt.wantRaw)
  564. }
  565. for _, op := range tt.consumeOps {
  566. check := func(label string, gotCnt, wantCnt int, wantErr error) {
  567. t.Helper()
  568. gotErr := ParseError(gotCnt)
  569. if gotCnt < 0 {
  570. gotCnt = 0
  571. }
  572. if gotCnt != wantCnt {
  573. t.Errorf("Consume%v(): consumed %d bytes, want %d bytes consumed", label, gotCnt, wantCnt)
  574. }
  575. if gotErr != wantErr {
  576. t.Errorf("Consume%v(): got %v error, want %v error", label, gotErr, wantErr)
  577. }
  578. b = b[gotCnt:]
  579. }
  580. switch op := op.(type) {
  581. case consumeField:
  582. gotNum, gotType, n := ConsumeField(b)
  583. if gotNum != op.wantNum || gotType != op.wantType {
  584. t.Errorf("ConsumeField() = (%d, %v), want (%d, %v)", gotNum, gotType, op.wantNum, op.wantType)
  585. }
  586. check("Field", n, op.wantCnt, op.wantErr)
  587. case consumeFieldValue:
  588. n := ConsumeFieldValue(op.inNum, op.inType, b)
  589. check("FieldValue", n, op.wantCnt, op.wantErr)
  590. case consumeTag:
  591. gotNum, gotType, n := ConsumeTag(b)
  592. if gotNum != op.wantNum || gotType != op.wantType {
  593. t.Errorf("ConsumeTag() = (%d, %v), want (%d, %v)", gotNum, gotType, op.wantNum, op.wantType)
  594. }
  595. check("Tag", n, op.wantCnt, op.wantErr)
  596. case consumeVarint:
  597. gotVal, n := ConsumeVarint(b)
  598. if gotVal != op.wantVal {
  599. t.Errorf("ConsumeVarint() = %d, want %d", gotVal, op.wantVal)
  600. }
  601. check("Varint", n, op.wantCnt, op.wantErr)
  602. case consumeFixed32:
  603. gotVal, n := ConsumeFixed32(b)
  604. if gotVal != op.wantVal {
  605. t.Errorf("ConsumeFixed32() = %d, want %d", gotVal, op.wantVal)
  606. }
  607. check("Fixed32", n, op.wantCnt, op.wantErr)
  608. case consumeFixed64:
  609. gotVal, n := ConsumeFixed64(b)
  610. if gotVal != op.wantVal {
  611. t.Errorf("ConsumeFixed64() = %d, want %d", gotVal, op.wantVal)
  612. }
  613. check("Fixed64", n, op.wantCnt, op.wantErr)
  614. case consumeBytes:
  615. gotVal, n := ConsumeBytes(b)
  616. if !bytes.Equal(gotVal, op.wantVal) {
  617. t.Errorf("ConsumeBytes() = %x, want %x", gotVal, op.wantVal)
  618. }
  619. check("Bytes", n, op.wantCnt, op.wantErr)
  620. case consumeGroup:
  621. gotVal, n := ConsumeGroup(op.inNum, b)
  622. if !bytes.Equal(gotVal, op.wantVal) {
  623. t.Errorf("ConsumeGroup() = %x, want %x", gotVal, op.wantVal)
  624. }
  625. check("Group", n, op.wantCnt, op.wantErr)
  626. }
  627. }
  628. })
  629. }
  630. }
  631. func TestZigZag(t *testing.T) {
  632. tests := []struct {
  633. dec int64
  634. enc uint64
  635. }{
  636. {math.MinInt64 + 0, math.MaxUint64 - 0},
  637. {math.MinInt64 + 1, math.MaxUint64 - 2},
  638. {math.MinInt64 + 2, math.MaxUint64 - 4},
  639. {-3, 5},
  640. {-2, 3},
  641. {-1, 1},
  642. {0, 0},
  643. {+1, 2},
  644. {+2, 4},
  645. {+3, 6},
  646. {math.MaxInt64 - 2, math.MaxUint64 - 5},
  647. {math.MaxInt64 - 1, math.MaxUint64 - 3},
  648. {math.MaxInt64 - 0, math.MaxUint64 - 1},
  649. }
  650. for _, tt := range tests {
  651. if enc := EncodeZigZag(tt.dec); enc != tt.enc {
  652. t.Errorf("EncodeZigZag(%d) = %d, want %d", tt.dec, enc, tt.enc)
  653. }
  654. if dec := DecodeZigZag(tt.enc); dec != tt.dec {
  655. t.Errorf("DecodeZigZag(%d) = %d, want %d", tt.enc, dec, tt.dec)
  656. }
  657. }
  658. }