imapflow 1.7.8 → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (296) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/README.md +8 -2
  3. package/dist/cjs/charsets.d.ts +1 -0
  4. package/dist/cjs/charsets.js +294 -0
  5. package/dist/cjs/commands/append.d.ts +22 -0
  6. package/dist/cjs/commands/append.js +151 -0
  7. package/dist/cjs/commands/authenticate.d.ts +24 -0
  8. package/dist/cjs/commands/authenticate.js +223 -0
  9. package/dist/cjs/commands/capability.d.ts +8 -0
  10. package/dist/cjs/commands/capability.js +32 -0
  11. package/dist/cjs/commands/close.d.ts +8 -0
  12. package/dist/cjs/commands/close.js +39 -0
  13. package/dist/cjs/commands/compress.d.ts +8 -0
  14. package/dist/cjs/commands/compress.js +56 -0
  15. package/dist/cjs/commands/copy.d.ts +13 -0
  16. package/dist/cjs/commands/copy.js +44 -0
  17. package/dist/cjs/commands/copyuid-parser.d.ts +11 -0
  18. package/dist/cjs/commands/copyuid-parser.js +32 -0
  19. package/dist/cjs/commands/create.d.ts +11 -0
  20. package/dist/cjs/commands/create.js +80 -0
  21. package/dist/cjs/commands/delete.d.ts +11 -0
  22. package/dist/cjs/commands/delete.js +40 -0
  23. package/dist/cjs/commands/enable.d.ts +9 -0
  24. package/dist/cjs/commands/enable.js +61 -0
  25. package/dist/cjs/commands/esearch-parser.d.ts +17 -0
  26. package/dist/cjs/commands/esearch-parser.js +91 -0
  27. package/dist/cjs/commands/expunge.d.ts +12 -0
  28. package/dist/cjs/commands/expunge.js +60 -0
  29. package/dist/cjs/commands/fetch.d.ts +30 -0
  30. package/dist/cjs/commands/fetch.js +241 -0
  31. package/dist/cjs/commands/id.d.ts +10 -0
  32. package/dist/cjs/commands/id.js +80 -0
  33. package/dist/cjs/commands/idle.d.ts +9 -0
  34. package/dist/cjs/commands/idle.js +347 -0
  35. package/dist/cjs/commands/list.d.ts +16 -0
  36. package/dist/cjs/commands/list.js +520 -0
  37. package/dist/cjs/commands/login.d.ts +11 -0
  38. package/dist/cjs/commands/login.js +42 -0
  39. package/dist/cjs/commands/logout.d.ts +8 -0
  40. package/dist/cjs/commands/logout.js +47 -0
  41. package/dist/cjs/commands/move.d.ts +13 -0
  42. package/dist/cjs/commands/move.js +57 -0
  43. package/dist/cjs/commands/namespace.d.ts +25 -0
  44. package/dist/cjs/commands/namespace.js +139 -0
  45. package/dist/cjs/commands/noop.d.ts +8 -0
  46. package/dist/cjs/commands/noop.js +22 -0
  47. package/dist/cjs/commands/quota.d.ts +10 -0
  48. package/dist/cjs/commands/quota.js +119 -0
  49. package/dist/cjs/commands/rename.d.ts +12 -0
  50. package/dist/cjs/commands/rename.js +48 -0
  51. package/dist/cjs/commands/search.d.ts +15 -0
  52. package/dist/cjs/commands/search.js +228 -0
  53. package/dist/cjs/commands/select.d.ts +25 -0
  54. package/dist/cjs/commands/select.js +250 -0
  55. package/dist/cjs/commands/starttls.d.ts +8 -0
  56. package/dist/cjs/commands/starttls.js +30 -0
  57. package/dist/cjs/commands/status-fields.d.ts +14 -0
  58. package/dist/cjs/commands/status-fields.js +61 -0
  59. package/dist/cjs/commands/status.d.ts +12 -0
  60. package/dist/cjs/commands/status.js +108 -0
  61. package/dist/cjs/commands/store.d.ts +19 -0
  62. package/dist/cjs/commands/store.js +93 -0
  63. package/dist/cjs/commands/subscribe.d.ts +9 -0
  64. package/dist/cjs/commands/subscribe.js +31 -0
  65. package/dist/cjs/commands/unsubscribe.d.ts +9 -0
  66. package/dist/cjs/commands/unsubscribe.js +31 -0
  67. package/dist/cjs/connection-deadline.d.ts +49 -0
  68. package/dist/cjs/connection-deadline.js +91 -0
  69. package/dist/cjs/errors.d.ts +83 -0
  70. package/dist/cjs/errors.js +13 -0
  71. package/dist/cjs/handler/imap-compiler.d.ts +24 -0
  72. package/dist/cjs/handler/imap-compiler.js +285 -0
  73. package/dist/cjs/handler/imap-formal-syntax.d.ts +28 -0
  74. package/dist/cjs/handler/imap-formal-syntax.js +121 -0
  75. package/dist/cjs/handler/imap-handler.d.ts +9 -0
  76. package/dist/cjs/handler/imap-handler.js +10 -0
  77. package/dist/cjs/handler/imap-parser.d.ts +16 -0
  78. package/dist/cjs/handler/imap-parser.js +90 -0
  79. package/dist/cjs/handler/imap-stream.d.ts +181 -0
  80. package/dist/cjs/handler/imap-stream.js +446 -0
  81. package/dist/cjs/handler/limits.d.ts +25 -0
  82. package/dist/cjs/handler/limits.js +51 -0
  83. package/dist/cjs/handler/parser-instance.d.ts +68 -0
  84. package/dist/cjs/handler/parser-instance.js +223 -0
  85. package/dist/cjs/handler/token-parser.d.ts +91 -0
  86. package/dist/cjs/handler/token-parser.js +673 -0
  87. package/dist/cjs/handler/types.d.ts +91 -0
  88. package/dist/cjs/handler/types.js +4 -0
  89. package/dist/cjs/imap-commands.d.ts +16 -0
  90. package/dist/cjs/imap-commands.js +74 -0
  91. package/dist/cjs/imap-flow.d.ts +676 -0
  92. package/dist/cjs/imap-flow.js +3956 -0
  93. package/dist/cjs/jp-decoder.d.ts +12 -0
  94. package/dist/cjs/jp-decoder.js +79 -0
  95. package/dist/cjs/limited-passthrough.d.ts +25 -0
  96. package/dist/cjs/limited-passthrough.js +54 -0
  97. package/dist/cjs/logger.d.ts +3 -0
  98. package/dist/cjs/logger.js +11 -0
  99. package/dist/cjs/package-info.d.ts +3 -0
  100. package/dist/cjs/package-info.js +7 -0
  101. package/dist/cjs/package.json +3 -0
  102. package/dist/cjs/proxy-connection.d.ts +33 -0
  103. package/dist/cjs/proxy-connection.js +392 -0
  104. package/dist/cjs/search-compiler.d.ts +34 -0
  105. package/dist/cjs/search-compiler.js +476 -0
  106. package/dist/cjs/special-use.d.ts +22 -0
  107. package/dist/cjs/special-use.js +911 -0
  108. package/dist/cjs/tools.d.ts +427 -0
  109. package/dist/cjs/tools.js +1496 -0
  110. package/{lib/imap-flow.d.ts → dist/cjs/types.d.ts} +387 -517
  111. package/dist/cjs/types.js +5 -0
  112. package/dist/esm/charsets.d.ts +1 -0
  113. package/{lib → dist/esm}/charsets.js +1 -6
  114. package/dist/esm/commands/append.d.ts +22 -0
  115. package/{lib → dist/esm}/commands/append.js +22 -52
  116. package/dist/esm/commands/authenticate.d.ts +24 -0
  117. package/{lib → dist/esm}/commands/authenticate.js +62 -87
  118. package/dist/esm/commands/capability.d.ts +8 -0
  119. package/{lib → dist/esm}/commands/capability.js +6 -9
  120. package/dist/esm/commands/close.d.ts +8 -0
  121. package/{lib → dist/esm}/commands/close.js +6 -10
  122. package/dist/esm/commands/compress.d.ts +8 -0
  123. package/{lib → dist/esm}/commands/compress.js +7 -11
  124. package/dist/esm/commands/copy.d.ts +13 -0
  125. package/{lib → dist/esm}/commands/copy.js +12 -20
  126. package/dist/esm/commands/copyuid-parser.d.ts +11 -0
  127. package/{lib → dist/esm}/commands/copyuid-parser.js +9 -15
  128. package/dist/esm/commands/create.d.ts +11 -0
  129. package/{lib → dist/esm}/commands/create.js +13 -27
  130. package/dist/esm/commands/delete.d.ts +11 -0
  131. package/{lib → dist/esm}/commands/delete.js +9 -14
  132. package/dist/esm/commands/enable.d.ts +9 -0
  133. package/{lib → dist/esm}/commands/enable.js +23 -30
  134. package/dist/esm/commands/esearch-parser.d.ts +17 -0
  135. package/dist/esm/commands/esearch-parser.js +88 -0
  136. package/dist/esm/commands/expunge.d.ts +12 -0
  137. package/{lib → dist/esm}/commands/expunge.js +17 -22
  138. package/dist/esm/commands/fetch.d.ts +30 -0
  139. package/{lib → dist/esm}/commands/fetch.js +32 -64
  140. package/dist/esm/commands/id.d.ts +10 -0
  141. package/{lib → dist/esm}/commands/id.js +17 -23
  142. package/dist/esm/commands/idle.d.ts +9 -0
  143. package/{lib → dist/esm}/commands/idle.js +47 -81
  144. package/dist/esm/commands/list.d.ts +16 -0
  145. package/{lib → dist/esm}/commands/list.js +60 -123
  146. package/dist/esm/commands/login.d.ts +11 -0
  147. package/{lib → dist/esm}/commands/login.js +10 -15
  148. package/dist/esm/commands/logout.d.ts +8 -0
  149. package/{lib → dist/esm}/commands/logout.js +9 -11
  150. package/dist/esm/commands/move.d.ts +13 -0
  151. package/{lib → dist/esm}/commands/move.js +13 -21
  152. package/dist/esm/commands/namespace.d.ts +25 -0
  153. package/{lib → dist/esm}/commands/namespace.js +34 -44
  154. package/dist/esm/commands/noop.d.ts +8 -0
  155. package/{lib → dist/esm}/commands/noop.js +6 -7
  156. package/dist/esm/commands/quota.d.ts +10 -0
  157. package/{lib → dist/esm}/commands/quota.js +18 -36
  158. package/dist/esm/commands/rename.d.ts +12 -0
  159. package/{lib → dist/esm}/commands/rename.js +10 -15
  160. package/dist/esm/commands/search.d.ts +15 -0
  161. package/{lib → dist/esm}/commands/search.js +36 -135
  162. package/dist/esm/commands/select.d.ts +25 -0
  163. package/{lib → dist/esm}/commands/select.js +33 -64
  164. package/dist/esm/commands/starttls.d.ts +8 -0
  165. package/{lib → dist/esm}/commands/starttls.js +6 -8
  166. package/dist/esm/commands/status-fields.d.ts +14 -0
  167. package/{lib → dist/esm}/commands/status-fields.js +5 -16
  168. package/dist/esm/commands/status.d.ts +12 -0
  169. package/{lib → dist/esm}/commands/status.js +18 -29
  170. package/dist/esm/commands/store.d.ts +19 -0
  171. package/{lib → dist/esm}/commands/store.js +24 -37
  172. package/dist/esm/commands/subscribe.d.ts +9 -0
  173. package/{lib → dist/esm}/commands/subscribe.js +8 -12
  174. package/dist/esm/commands/unsubscribe.d.ts +9 -0
  175. package/{lib → dist/esm}/commands/unsubscribe.js +8 -12
  176. package/dist/esm/connection-deadline.d.ts +49 -0
  177. package/{lib → dist/esm}/connection-deadline.js +14 -25
  178. package/dist/esm/errors.d.ts +83 -0
  179. package/dist/esm/errors.js +9 -0
  180. package/dist/esm/handler/imap-compiler.d.ts +24 -0
  181. package/{lib → dist/esm}/handler/imap-compiler.js +22 -80
  182. package/dist/esm/handler/imap-formal-syntax.d.ts +28 -0
  183. package/dist/esm/handler/imap-formal-syntax.js +117 -0
  184. package/dist/esm/handler/imap-handler.d.ts +9 -0
  185. package/dist/esm/handler/imap-handler.js +9 -0
  186. package/dist/esm/handler/imap-parser.d.ts +16 -0
  187. package/{lib → dist/esm}/handler/imap-parser.js +31 -44
  188. package/dist/esm/handler/imap-stream.d.ts +181 -0
  189. package/{lib → dist/esm}/handler/imap-stream.js +29 -121
  190. package/dist/esm/handler/limits.d.ts +25 -0
  191. package/{lib → dist/esm}/handler/limits.js +13 -22
  192. package/dist/esm/handler/parser-instance.d.ts +68 -0
  193. package/{lib → dist/esm}/handler/parser-instance.js +19 -47
  194. package/dist/esm/handler/token-parser.d.ts +91 -0
  195. package/{lib → dist/esm}/handler/token-parser.js +71 -155
  196. package/dist/esm/handler/types.d.ts +91 -0
  197. package/dist/esm/handler/types.js +3 -0
  198. package/dist/esm/imap-commands.d.ts +16 -0
  199. package/dist/esm/imap-commands.js +67 -0
  200. package/dist/esm/imap-flow.d.ts +676 -0
  201. package/{lib → dist/esm}/imap-flow.js +769 -1790
  202. package/dist/esm/jp-decoder.d.ts +12 -0
  203. package/{lib → dist/esm}/jp-decoder.js +6 -21
  204. package/dist/esm/limited-passthrough.d.ts +25 -0
  205. package/{lib → dist/esm}/limited-passthrough.js +7 -20
  206. package/dist/esm/logger.d.ts +3 -0
  207. package/dist/esm/logger.js +4 -0
  208. package/dist/esm/package-info.d.ts +3 -0
  209. package/dist/esm/package-info.js +4 -0
  210. package/dist/esm/package.json +3 -0
  211. package/dist/esm/proxy-connection.d.ts +33 -0
  212. package/{lib → dist/esm}/proxy-connection.js +56 -127
  213. package/dist/esm/search-compiler.d.ts +34 -0
  214. package/{lib → dist/esm}/search-compiler.js +54 -110
  215. package/dist/esm/special-use.d.ts +22 -0
  216. package/dist/esm/special-use.js +907 -0
  217. package/dist/esm/tools.d.ts +427 -0
  218. package/dist/esm/tools.js +1446 -0
  219. package/dist/esm/types.d.ts +828 -0
  220. package/dist/esm/types.js +4 -0
  221. package/package.json +60 -20
  222. package/.gitattributes +0 -1
  223. package/.github/CODE_OF_CONDUCT.md +0 -76
  224. package/.github/FUNDING.yml +0 -4
  225. package/.github/ISSUE_TEMPLATE/bug_report.md +0 -40
  226. package/.github/ISSUE_TEMPLATE/feature_request.md +0 -19
  227. package/.github/contributing.md +0 -17
  228. package/.github/workflows/release.yaml +0 -36
  229. package/.github/workflows/stale.yml +0 -29
  230. package/.github/workflows/test.yml +0 -51
  231. package/.ncurc.js +0 -4
  232. package/.prettierignore +0 -4
  233. package/.prettierrc.js +0 -8
  234. package/.release-please-manifest.json +0 -3
  235. package/CLAUDE.md +0 -104
  236. package/Gruntfile.js +0 -23
  237. package/eslint.config.js +0 -45
  238. package/lib/handler/imap-formal-syntax.js +0 -189
  239. package/lib/handler/imap-handler.js +0 -17
  240. package/lib/imap-commands.js +0 -45
  241. package/lib/logger.js +0 -5
  242. package/lib/special-use.js +0 -923
  243. package/lib/tools.js +0 -1612
  244. package/release-please-config.json +0 -10
  245. package/test/authentication-test.js +0 -101
  246. package/test/auto-idle-test.js +0 -470
  247. package/test/bodystructure-test.js +0 -899
  248. package/test/charsets-test.js +0 -161
  249. package/test/commands-branches-test.js +0 -1095
  250. package/test/commands-integration-test.js +0 -11124
  251. package/test/commands-test.js +0 -73
  252. package/test/connection-edge-cases-test.js +0 -1828
  253. package/test/connection-test.js +0 -162
  254. package/test/copyuid-parser-test.js +0 -173
  255. package/test/fetch-generator-test.js +0 -218
  256. package/test/fixtures/fake-timers.js +0 -115
  257. package/test/fixtures/serialized-mimetorture.js +0 -2738
  258. package/test/fixtures/test-client.js +0 -101
  259. package/test/fixtures/test-tls.js +0 -8
  260. package/test/handler-branches-test.js +0 -310
  261. package/test/idle-polling-test.js +0 -518
  262. package/test/imap-compiler-test.js +0 -809
  263. package/test/imap-flow-compress-test.js +0 -166
  264. package/test/imap-flow-coverage-test.js +0 -612
  265. package/test/imap-flow-fetch-download-test.js +0 -909
  266. package/test/imap-flow-internals-test.js +0 -725
  267. package/test/imap-flow-methods-test.js +0 -889
  268. package/test/imap-flow-proxy-paths-test.js +0 -366
  269. package/test/imap-flow-secure-test.js +0 -573
  270. package/test/imap-flow-server-test.js +0 -1474
  271. package/test/imap-formal-syntax-test.js +0 -293
  272. package/test/imap-parser-test.js +0 -1474
  273. package/test/imap-stream-edge-cases-test.js +0 -666
  274. package/test/imap-stream-test.js +0 -177
  275. package/test/imapflow-test.js +0 -258
  276. package/test/integration/README.md +0 -52
  277. package/test/integration/dovecot-test.conf +0 -27
  278. package/test/integration/rev2-live-test.js +0 -431
  279. package/test/integration/run-rev2-tests.sh +0 -75
  280. package/test/integration-test.js +0 -83
  281. package/test/jp-decoder-test.js +0 -304
  282. package/test/limited-passthrough-test.js +0 -299
  283. package/test/memory-cleanup-test.js +0 -144
  284. package/test/memory-leak-test.js +0 -667
  285. package/test/parser-limits-test.js +0 -292
  286. package/test/proxy-connection-test.js +0 -738
  287. package/test/reliability-improvements-test.js +0 -548
  288. package/test/search-compiler-test.js +0 -1300
  289. package/test/search-test.js +0 -329
  290. package/test/special-use-test.js +0 -418
  291. package/test/starttls-injection-test.js +0 -181
  292. package/test/tag-correlation-test.js +0 -333
  293. package/test/timer-policy-test.js +0 -227
  294. package/test/token-parser-test.js +0 -456
  295. package/test/tools-test.js +0 -2013
  296. package/test/unhandled-rejection-test.js +0 -661
@@ -1,1474 +0,0 @@
1
- /*eslint no-unused-expressions: 0, prefer-arrow-callback: 0 */
2
-
3
- 'use strict';
4
-
5
- const { parser } = require('../lib/handler/imap-handler');
6
- const { ParserInstance } = require('../lib/handler/parser-instance');
7
- const mimetorture = require('./fixtures/serialized-mimetorture');
8
-
9
- let asyncWrapper = (test, handler) => {
10
- handler(test)
11
- .then(() => test.done())
12
- .catch(err => {
13
- test.ifError(err);
14
- test.done();
15
- });
16
- };
17
-
18
- let asyncWrapperFail = (test, handler) => {
19
- handler(test)
20
- .then(() => {
21
- test.ok(false);
22
- test.done();
23
- })
24
- .catch(err => {
25
- test.ok(err);
26
- test.done();
27
- });
28
- };
29
-
30
- // Asserts that `fn` throws (or rejects with) an error carrying the expected `code`,
31
- // not merely that *some* error was thrown.
32
- let expectErrorCode = (test, code, fn) =>
33
- asyncWrapper(test, async test => {
34
- let err;
35
- try {
36
- await fn();
37
- } catch (e) {
38
- err = e;
39
- }
40
- test.ok(err, 'expected an error to be thrown');
41
- test.equal(err && err.code, code);
42
- });
43
-
44
- module.exports['IMAP Parser: Tags: get TAG'] = test => asyncWrapper(test, async test => test.equal((await parser('TAG1 CMD')).tag, 'TAG1'));
45
- module.exports['IMAP Parser: Tags: space before TAG'] = test => asyncWrapperFail(test, async test => test.ok(await parser(' TAG CMD')));
46
- module.exports['IMAP Parser: Tags: fail empty TAG'] = test => asyncWrapperFail(test, async test => test.ok(await parser('')));
47
- module.exports['IMAP Parser: Tags: * TAG'] = test => asyncWrapper(test, async test => test.equal((await parser('* CMD')).tag, '*'));
48
- module.exports['IMAP Parser: Tags: + TAG'] = test => asyncWrapper(test, async test => test.equal((await parser('+ CMD')).tag, '+'));
49
- module.exports['IMAP Parser: Tags: fail TAG only'] = test => asyncWrapperFail(test, async test => test.ok(await parser('TAG1')));
50
- module.exports['IMAP Parser: Tags: fail invalid char in TAG'] = test => asyncWrapperFail(test, async test => test.ok(await parser('TAG"1 CMD')));
51
-
52
- module.exports['IMAP Parser: Command: single'] = test => asyncWrapper(test, async test => test.equal((await parser('TAG1 CMD')).command, 'CMD'));
53
- module.exports['IMAP Parser: Command: multi word'] = test =>
54
- asyncWrapper(test, async test => test.equal((await parser('TAG1 UID FETCH')).command, 'UID FETCH'));
55
- module.exports['IMAP Parser: Command: fail extra ws'] = test => asyncWrapperFail(test, async test => test.ok(await parser('TAG1 CMD')));
56
- module.exports['IMAP Parser: Command: fail empty command'] = test => asyncWrapperFail(test, async test => test.ok(await parser('TAG1 ')));
57
- module.exports['IMAP Parser: Command: fail invalid char in command'] = test => asyncWrapperFail(test, async test => test.ok(await parser('TAG1 CM=D')));
58
-
59
- module.exports['IMAP Parser: Args: allow trailing whitespace and empty arguments'] = test =>
60
- asyncWrapper(test, async test => test.deepEqual(await parser('* SEARCH '), { tag: '*', command: 'SEARCH' }));
61
-
62
- module.exports['IMAP Parser: Attributes: single atom'] = test =>
63
- asyncWrapper(test, async test =>
64
- test.deepEqual((await parser('TAG1 CMD FED')).attributes, [
65
- {
66
- type: 'ATOM',
67
- value: 'FED'
68
- }
69
- ])
70
- );
71
-
72
- module.exports['IMAP Parser: Attributes: multiple atoms'] = test =>
73
- asyncWrapper(test, async test =>
74
- test.deepEqual((await parser('TAG1 CMD FED TED')).attributes, [
75
- {
76
- type: 'ATOM',
77
- value: 'FED'
78
- },
79
- {
80
- type: 'ATOM',
81
- value: 'TED'
82
- }
83
- ])
84
- );
85
-
86
- module.exports['IMAP Parser: Attributes: special char in atom'] = test =>
87
- asyncWrapper(test, async test =>
88
- test.deepEqual((await parser('TAG1 CMD %')).attributes, [
89
- {
90
- type: 'ATOM',
91
- value: '%'
92
- }
93
- ])
94
- );
95
-
96
- module.exports['IMAP Parser: Attributes: escaped char in atom'] = test =>
97
- asyncWrapper(test, async test =>
98
- test.deepEqual((await parser('TAG1 CMD \\*')).attributes, [
99
- {
100
- type: 'ATOM',
101
- value: '\\*'
102
- }
103
- ])
104
- );
105
-
106
- module.exports['IMAP Parser: Attributes: sub list'] = test =>
107
- asyncWrapper(test, async test =>
108
- test.deepEqual((await parser('12.82 STATUS [Gmail].Trash (UIDNEXT UNSEEN HIGHESTMODSEQ)')).attributes, [
109
- {
110
- type: 'ATOM',
111
- value: '[Gmail].Trash'
112
- },
113
- [
114
- {
115
- type: 'ATOM',
116
- value: 'UIDNEXT'
117
- },
118
- {
119
- type: 'ATOM',
120
- value: 'UNSEEN'
121
- },
122
- {
123
- type: 'ATOM',
124
- value: 'HIGHESTMODSEQ'
125
- }
126
- ]
127
- ])
128
- );
129
-
130
- module.exports['IMAP Parser: Attributes: single string'] = test =>
131
- asyncWrapper(test, async test =>
132
- test.deepEqual((await parser('TAG1 CMD "ABCDE"')).attributes, [
133
- {
134
- type: 'STRING',
135
- value: 'ABCDE'
136
- }
137
- ])
138
- );
139
-
140
- module.exports['IMAP Parser: Attributes: multiple strings'] = test =>
141
- asyncWrapper(test, async test =>
142
- test.deepEqual((await parser('TAG1 CMD "ABCDE" "DEFGH"')).attributes, [
143
- {
144
- type: 'STRING',
145
- value: 'ABCDE'
146
- },
147
- {
148
- type: 'STRING',
149
- value: 'DEFGH'
150
- }
151
- ])
152
- );
153
-
154
- module.exports['IMAP Parser: Attributes: invalid char in string'] = test =>
155
- asyncWrapper(test, async test =>
156
- test.deepEqual((await parser('* 1 FETCH (BODY[] "\xc2")')).attributes, [
157
- {
158
- type: 'ATOM',
159
- value: 'FETCH'
160
- },
161
- [
162
- {
163
- type: 'ATOM',
164
- value: 'BODY',
165
- section: []
166
- },
167
- {
168
- type: 'STRING',
169
- value: '\xc2'
170
- }
171
- ]
172
- ])
173
- );
174
-
175
- module.exports['IMAP Parser: Lists: single atom'] = test =>
176
- asyncWrapper(test, async test =>
177
- test.deepEqual((await parser('TAG1 CMD (1234)')).attributes, [
178
- [
179
- {
180
- type: 'ATOM',
181
- value: '1234'
182
- }
183
- ]
184
- ])
185
- );
186
-
187
- module.exports['IMAP Parser: Lists: multiple atoms'] = test =>
188
- asyncWrapper(test, async test =>
189
- test.deepEqual((await parser('TAG1 CMD (1234 TERE)')).attributes, [
190
- [
191
- {
192
- type: 'ATOM',
193
- value: '1234'
194
- },
195
- {
196
- type: 'ATOM',
197
- value: 'TERE'
198
- }
199
- ]
200
- ])
201
- );
202
-
203
- module.exports['IMAP Parser: Lists: multiple lists'] = test =>
204
- asyncWrapper(test, async test =>
205
- test.deepEqual((await parser('TAG1 CMD (1234)(TERE)')).attributes, [
206
- [
207
- {
208
- type: 'ATOM',
209
- value: '1234'
210
- }
211
- ],
212
- [
213
- {
214
- type: 'ATOM',
215
- value: 'TERE'
216
- }
217
- ]
218
- ])
219
- );
220
-
221
- module.exports['IMAP Parser: Lists: extra whitespace in start of list'] = test =>
222
- asyncWrapper(test, async test =>
223
- test.deepEqual((await parser('TAG1 CMD ( 1234)')).attributes, [
224
- [
225
- {
226
- type: 'ATOM',
227
- value: '1234'
228
- }
229
- ]
230
- ])
231
- );
232
-
233
- module.exports['IMAP Parser: Lists: extra whitespace in end of list'] = test =>
234
- asyncWrapper(test, async test =>
235
- test.deepEqual((await parser('TAG1 CMD (1234 )')).attributes, [
236
- [
237
- {
238
- type: 'ATOM',
239
- value: '1234'
240
- }
241
- ]
242
- ])
243
- );
244
-
245
- module.exports['IMAP Parser: Lists: extra whitespace after list'] = test =>
246
- asyncWrapper(test, async test =>
247
- test.deepEqual((await parser('TAG1 CMD (1234) ')).attributes, [
248
- [
249
- {
250
- type: 'ATOM',
251
- value: '1234'
252
- }
253
- ]
254
- ])
255
- );
256
-
257
- module.exports['IMAP Parser: Lists: nested list 1'] = test =>
258
- asyncWrapper(test, async test =>
259
- test.deepEqual((await parser('TAG1 CMD (((TERE)) VANA)')).attributes, [
260
- [
261
- [
262
- [
263
- {
264
- type: 'ATOM',
265
- value: 'TERE'
266
- }
267
- ]
268
- ],
269
- {
270
- type: 'ATOM',
271
- value: 'VANA'
272
- }
273
- ]
274
- ])
275
- );
276
-
277
- module.exports['IMAP Parser: Lists: nested list 2'] = test =>
278
- asyncWrapper(test, async test =>
279
- test.deepEqual((await parser('TAG1 CMD (( (TERE)) VANA)')).attributes, [
280
- [
281
- [
282
- [
283
- {
284
- type: 'ATOM',
285
- value: 'TERE'
286
- }
287
- ]
288
- ],
289
- {
290
- type: 'ATOM',
291
- value: 'VANA'
292
- }
293
- ]
294
- ])
295
- );
296
-
297
- module.exports['IMAP Parser: Lists: nested list 3'] = test =>
298
- asyncWrapper(test, async test =>
299
- test.deepEqual((await parser('TAG1 CMD (((TERE) ) VANA)')).attributes, [
300
- [
301
- [
302
- [
303
- {
304
- type: 'ATOM',
305
- value: 'TERE'
306
- }
307
- ]
308
- ],
309
- {
310
- type: 'ATOM',
311
- value: 'VANA'
312
- }
313
- ]
314
- ])
315
- );
316
-
317
- module.exports['IMAP Parser: Literals: single literal'] = test =>
318
- asyncWrapper(test, async test =>
319
- test.deepEqual((await parser('TAG1 CMD {4}\r\n', { literals: [Buffer.from('abcd')] })).attributes, [
320
- {
321
- type: 'LITERAL',
322
- value: Buffer.from('abcd')
323
- }
324
- ])
325
- );
326
-
327
- module.exports['IMAP Parser: Literals: literal with NULL'] = test =>
328
- asyncWrapper(test, async test =>
329
- test.deepEqual((await parser('TAG1 CMD {4}\r\n', { literals: [Buffer.from('ab\x00d')] })).attributes, [
330
- {
331
- type: 'LITERAL',
332
- value: Buffer.from('ab\x00d')
333
- }
334
- ])
335
- );
336
-
337
- module.exports['IMAP Parser: empty continuation (+) response'] = test =>
338
- asyncWrapper(test, async test => {
339
- let parsed = await parser('+');
340
- test.equal(parsed.tag, '+');
341
- test.equal(parsed.command, '');
342
- });
343
-
344
- module.exports['IMAP Parser: non-space after command throws ParserError5'] = test => expectErrorCode(test, 'ParserError5', () => parser('TAG1 CMD\tx'));
345
-
346
- module.exports['IMAP Parser: leading whitespace in attributes throws ParserError7'] = test =>
347
- expectErrorCode(test, 'ParserError7', () => parser('TAG1 CMD \tx'));
348
-
349
- module.exports['IMAP Parser: getAttributes on empty input throws ParserError6'] = test =>
350
- expectErrorCode(test, 'ParserError6', () => {
351
- // constructed without options to also exercise the options default branch
352
- let pi = new ParserInstance('');
353
- return pi.getAttributes();
354
- });
355
-
356
- module.exports['IMAP Parser: strips leading NUL padding and records count'] = test =>
357
- asyncWrapper(test, async test => {
358
- let buf = Buffer.concat([Buffer.from([0, 0, 0]), Buffer.from('* OK ready')]);
359
- let parsed = await parser(buf);
360
- test.equal(parsed.tag, '*');
361
- test.equal(parsed.command, 'OK');
362
- test.equal(parsed.nullBytesRemoved, 3);
363
- });
364
-
365
- module.exports['IMAP Parser: all-NUL input becomes BAD response'] = test =>
366
- asyncWrapper(test, async test => {
367
- let parsed = await parser(Buffer.from([0, 0, 0, 0]));
368
- test.equal(parsed.tag, '*');
369
- test.equal(parsed.command, 'BAD');
370
- test.deepEqual(parsed.attributes, []);
371
- });
372
-
373
- module.exports['IMAP Parser: Literals: literal8'] = test =>
374
- asyncWrapper(test, async test =>
375
- test.deepEqual((await parser('TAG1 CMD ~{4}\r\n', { literals: [Buffer.from('ab\x00d')] })).attributes, [
376
- {
377
- type: 'LITERAL',
378
- value: Buffer.from('ab\x00d')
379
- }
380
- ])
381
- );
382
-
383
- module.exports['IMAP Parser: Literals: unexpected literal8 prefix'] = test =>
384
- asyncWrapper(test, async test => {
385
- try {
386
- await parser('TAG1 CMD ~\r\n');
387
- test.ok(false, 'Must throw');
388
- } catch (err) {
389
- test.ok(err, 'Error must exist');
390
- }
391
- });
392
-
393
- module.exports['IMAP Parser: Literals: multiple literals'] = test =>
394
- asyncWrapper(test, async test =>
395
- test.deepEqual((await parser('TAG1 CMD {4}\r\n {4}\r\n', { literals: [Buffer.from('abcd'), Buffer.from('kere')] })).attributes, [
396
- {
397
- type: 'LITERAL',
398
- value: Buffer.from('abcd')
399
- },
400
- {
401
- type: 'LITERAL',
402
- value: Buffer.from('kere')
403
- }
404
- ])
405
- );
406
-
407
- module.exports['IMAP Parser: Literals: list'] = test =>
408
- asyncWrapper(test, async test =>
409
- test.deepEqual((await parser('TAG1 CMD ({4}\r\n {4}\r\n)', { literals: [Buffer.from('abcd'), Buffer.from('kere')] })).attributes, [
410
- [
411
- {
412
- type: 'LITERAL',
413
- value: Buffer.from('abcd')
414
- },
415
- {
416
- type: 'LITERAL',
417
- value: Buffer.from('kere')
418
- }
419
- ]
420
- ])
421
- );
422
-
423
- module.exports['IMAP Parser: Tags: fail extra ws after literal'] = test =>
424
- asyncWrapperFail(test, async test => test.ok(await parser('TAG1 CMD {4}\r\n{4} \r\n', { literals: [Buffer.from('abcd'), Buffer.from('kere')] })));
425
-
426
- module.exports['IMAP Parser: Literals: allow zero length literal in the end of a list'] = test =>
427
- asyncWrapper(test, async test =>
428
- test.deepEqual((await parser('TAG1 CMD ({0}\r\n)')).attributes, [
429
- [
430
- {
431
- type: 'LITERAL',
432
- value: Buffer.from('')
433
- }
434
- ]
435
- ])
436
- );
437
-
438
- module.exports['IMAP Parser: Literals: zero length literal keeps the literal queue aligned'] = test =>
439
- asyncWrapper(test, async test =>
440
- // ImapStream queues a Buffer for every literal marker it extracts, including
441
- // {0}, so the parser must consume exactly one queue entry per marker.
442
- // Otherwise every literal after a {0} in the same response is silently
443
- // shifted to the wrong value (RFC 9051 4.3 allows {0} as an empty string).
444
- test.deepEqual((await parser('TAG1 CMD ({0}\r\n {5}\r\n)', { literals: [Buffer.from(''), Buffer.from('hello')] })).attributes, [
445
- [
446
- {
447
- type: 'LITERAL',
448
- value: Buffer.from('')
449
- },
450
- {
451
- type: 'LITERAL',
452
- value: Buffer.from('hello')
453
- }
454
- ]
455
- ])
456
- );
457
-
458
- module.exports['IMAP Parser: Literals: zero length literal between literals keeps values aligned'] = test =>
459
- asyncWrapper(test, async test =>
460
- test.deepEqual(
461
- (await parser('TAG1 CMD ({3}\r\n {0}\r\n {5}\r\n)', { literals: [Buffer.from('abc'), Buffer.from(''), Buffer.from('world')] })).attributes,
462
- [
463
- [
464
- {
465
- type: 'LITERAL',
466
- value: Buffer.from('abc')
467
- },
468
- {
469
- type: 'LITERAL',
470
- value: Buffer.from('')
471
- },
472
- {
473
- type: 'LITERAL',
474
- value: Buffer.from('world')
475
- }
476
- ]
477
- ]
478
- )
479
- );
480
-
481
- // RFC 9051 updated resp-text to allow empty text: resp-text = ["[" resp-text-code "]" SP] [text]
482
- module.exports['IMAP Parser: resp-text: bare OK with no text'] = test =>
483
- asyncWrapper(test, async test => test.deepEqual(await parser('* OK'), { tag: '*', command: 'OK' }));
484
-
485
- module.exports['IMAP Parser: resp-text: tagged OK with no text'] = test =>
486
- asyncWrapper(test, async test => test.deepEqual(await parser('TAG1 OK'), { tag: 'TAG1', command: 'OK' }));
487
-
488
- module.exports['IMAP Parser: resp-text: response code with no trailing text'] = test =>
489
- asyncWrapper(test, async test => {
490
- let parsed = await parser('* OK [UIDNEXT 5]');
491
- test.equal(parsed.command, 'OK');
492
- test.deepEqual(parsed.attributes, [
493
- {
494
- type: 'ATOM',
495
- value: '',
496
- section: [
497
- { type: 'ATOM', value: 'UIDNEXT' },
498
- { type: 'ATOM', value: '5' }
499
- ]
500
- }
501
- ]);
502
- });
503
-
504
- module.exports['IMAP Parser: resp-text: response code with trailing space and no text'] = test =>
505
- asyncWrapper(test, async test => {
506
- let parsed = await parser('* OK [READ-WRITE] ');
507
- test.equal(parsed.command, 'OK');
508
- test.deepEqual(parsed.attributes, [
509
- {
510
- type: 'ATOM',
511
- value: '',
512
- section: [{ type: 'ATOM', value: 'READ-WRITE' }]
513
- }
514
- ]);
515
- });
516
-
517
- // RFC 9051 uses number64 (up to 2^63-1) for message and body sizes - values beyond
518
- // 2^32 must survive the tokenizer without truncation
519
- module.exports['IMAP Parser: number64: RFC822.SIZE beyond 32 bits'] = test =>
520
- asyncWrapper(test, async test => {
521
- let parsed = await parser('* 1 FETCH (RFC822.SIZE 12345678901234)');
522
- test.deepEqual(parsed.attributes, [
523
- { type: 'ATOM', value: 'FETCH' },
524
- [
525
- { type: 'ATOM', value: 'RFC822.SIZE' },
526
- { type: 'ATOM', value: '12345678901234' }
527
- ]
528
- ]);
529
- });
530
-
531
- module.exports['IMAP Parser: number64: response code argument beyond 32 bits'] = test =>
532
- asyncWrapper(test, async test => {
533
- let parsed = await parser('* OK [HIGHESTMODSEQ 90060115194045007] Ok');
534
- test.deepEqual(parsed.attributes, [
535
- {
536
- type: 'ATOM',
537
- value: '',
538
- section: [
539
- { type: 'ATOM', value: 'HIGHESTMODSEQ' },
540
- { type: 'ATOM', value: '90060115194045007' }
541
- ]
542
- },
543
- { type: 'TEXT', value: 'Ok' }
544
- ]);
545
- });
546
-
547
- module.exports['IMAP Parser: Section: empty'] = test =>
548
- asyncWrapper(test, async test =>
549
- test.deepEqual((await parser('TAG1 CMD BODY[]')).attributes, [
550
- {
551
- type: 'ATOM',
552
- value: 'BODY',
553
- section: []
554
- }
555
- ])
556
- );
557
-
558
- module.exports['IMAP Parser: Section: list'] = test =>
559
- asyncWrapper(test, async test =>
560
- test.deepEqual((await parser('TAG1 CMD BODY[(KERE)]')).attributes, [
561
- {
562
- type: 'ATOM',
563
- value: 'BODY',
564
- section: [
565
- [
566
- {
567
- type: 'ATOM',
568
- value: 'KERE'
569
- }
570
- ]
571
- ]
572
- }
573
- ])
574
- );
575
-
576
- module.exports['IMAP Parser: Section: allow trailing ws'] = test =>
577
- asyncWrapper(test, async test =>
578
- test.deepEqual((await parser('TAG1 CMD BODY[HEADER.FIELDS (Subject From) ]')).attributes, [
579
- {
580
- type: 'ATOM',
581
- value: 'BODY',
582
- section: [
583
- {
584
- type: 'ATOM',
585
- value: 'HEADER.FIELDS'
586
- },
587
- [
588
- {
589
- type: 'ATOM',
590
- value: 'Subject'
591
- },
592
- {
593
- type: 'ATOM',
594
- value: 'From'
595
- }
596
- ]
597
- ]
598
- }
599
- ])
600
- );
601
-
602
- module.exports['IMAP Parser: Readable: simple'] = test =>
603
- asyncWrapper(test, async test =>
604
- test.deepEqual(await parser('* OK Hello world!'), {
605
- command: 'OK',
606
- tag: '*',
607
- attributes: [
608
- {
609
- type: 'TEXT',
610
- value: 'Hello world!'
611
- }
612
- ]
613
- })
614
- );
615
-
616
- module.exports['IMAP Parser: Readable: section'] = test =>
617
- asyncWrapper(test, async test =>
618
- test.deepEqual(await parser('* OK [CAPABILITY IDLE] Hello world!'), {
619
- command: 'OK',
620
- tag: '*',
621
- attributes: [
622
- {
623
- section: [
624
- {
625
- type: 'ATOM',
626
- value: 'CAPABILITY'
627
- },
628
- {
629
- type: 'ATOM',
630
- value: 'IDLE'
631
- }
632
- ],
633
- type: 'ATOM',
634
- value: ''
635
- },
636
- {
637
- type: 'TEXT',
638
- value: 'Hello world!'
639
- }
640
- ]
641
- })
642
- );
643
-
644
- // USEATTR is from RFC6154; we are testing that just an ATOM
645
- // on its own will parse successfully here. (All of the
646
- // RFC5530 codes are also single atoms.)
647
- module.exports['IMAP Parser: Section: USEATTR'] = test =>
648
- asyncWrapper(test, async test =>
649
- test.deepEqual(await parser('TAG1 OK [USEATTR] \\All not supported'), {
650
- tag: 'TAG1',
651
- command: 'OK',
652
- attributes: [
653
- {
654
- type: 'ATOM',
655
- value: '',
656
- section: [
657
- {
658
- type: 'ATOM',
659
- value: 'USEATTR'
660
- }
661
- ]
662
- },
663
- {
664
- type: 'TEXT',
665
- value: '\\All not supported'
666
- }
667
- ]
668
- })
669
- );
670
-
671
- // RFC5267 defines the NOUPDATE error. Including for quote /
672
- // string coverage.
673
- module.exports['IMAP Parser: Section: NOUPDATE'] = test =>
674
- asyncWrapper(test, async test =>
675
- test.deepEqual(await parser('* NO [NOUPDATE "B02"] Too many contexts'), {
676
- tag: '*',
677
- command: 'NO',
678
- attributes: [
679
- {
680
- type: 'ATOM',
681
- value: '',
682
- section: [
683
- {
684
- type: 'ATOM',
685
- value: 'NOUPDATE'
686
- },
687
- {
688
- type: 'STRING',
689
- value: 'B02'
690
- }
691
- ]
692
- },
693
- {
694
- type: 'TEXT',
695
- value: 'Too many contexts'
696
- }
697
- ]
698
- })
699
- );
700
-
701
- // RFC5464 defines the METADATA response code; adding this to
702
- // ensure the transition for when '2199' hits ']' is handled
703
- // safely.
704
- module.exports['IMAP Parser: Section: METADATA'] = test =>
705
- asyncWrapper(test, async test =>
706
- test.deepEqual(await parser('TAG1 OK [METADATA LONGENTRIES 2199] GETMETADATA complete'), {
707
- tag: 'TAG1',
708
- command: 'OK',
709
- attributes: [
710
- {
711
- type: 'ATOM',
712
- value: '',
713
- section: [
714
- {
715
- type: 'ATOM',
716
- value: 'METADATA'
717
- },
718
- {
719
- type: 'ATOM',
720
- value: 'LONGENTRIES'
721
- },
722
- {
723
- type: 'ATOM',
724
- value: '2199'
725
- }
726
- ]
727
- },
728
- {
729
- type: 'TEXT',
730
- value: 'GETMETADATA complete'
731
- }
732
- ]
733
- })
734
- );
735
-
736
- // RFC4467 defines URLMECH. Included because of the example
737
- // third atom involves base64-encoding which is somewhat unusual
738
- module.exports['IMAP Parser: Section: URLMECH'] = test =>
739
- asyncWrapper(test, async test =>
740
- test.deepEqual(await parser('TAG1 OK [URLMECH INTERNAL XSAMPLE=P34OKhO7VEkCbsiYY8rGEg==] done'), {
741
- tag: 'TAG1',
742
- command: 'OK',
743
- attributes: [
744
- {
745
- type: 'ATOM',
746
- value: '',
747
- section: [
748
- {
749
- type: 'ATOM',
750
- value: 'URLMECH'
751
- },
752
- {
753
- type: 'ATOM',
754
- value: 'INTERNAL'
755
- },
756
- {
757
- type: 'ATOM',
758
- value: 'XSAMPLE=P34OKhO7VEkCbsiYY8rGEg=='
759
- }
760
- ]
761
- },
762
- {
763
- type: 'TEXT',
764
- value: 'done'
765
- }
766
- ]
767
- })
768
- );
769
-
770
- // RFC2221 defines REFERRAL where the argument is an imapurl
771
- // (defined by RFC2192 which is obsoleted by RFC5092) which
772
- // is significantly more complicated than the rest of the IMAP
773
- // grammar and which was based on the RFC2060 grammar where
774
- // resp_text_code included:
775
- // atom [SPACE 1*<any TEXT_CHAR except ']'>]
776
- // So this is just a test case of our explicit special-casing
777
- // of REFERRAL.
778
- module.exports['IMAP Parser: Section: REFERRAL'] = test =>
779
- asyncWrapper(test, async test =>
780
- test.deepEqual(await parser('TAG1 NO [REFERRAL IMAP://user;AUTH=*@SERVER2/] Remote Server'), {
781
- tag: 'TAG1',
782
- command: 'NO',
783
- attributes: [
784
- {
785
- type: 'ATOM',
786
- value: '',
787
- section: [
788
- {
789
- type: 'ATOM',
790
- value: 'REFERRAL'
791
- },
792
- {
793
- type: 'ATOM',
794
- value: 'IMAP://user;AUTH=*@SERVER2/'
795
- }
796
- ]
797
- },
798
- {
799
- type: 'TEXT',
800
- value: 'Remote Server'
801
- }
802
- ]
803
- })
804
- );
805
-
806
- // PERMANENTFLAGS is from RFC3501. Its syntax is also very
807
- // similar to BADCHARSET, except BADCHARSET has astrings
808
- // inside the list.
809
- module.exports['IMAP Parser: Section: PERMANENTFLAGS'] = test =>
810
- asyncWrapper(test, async test =>
811
- test.deepEqual(await parser('* OK [PERMANENTFLAGS (de:hacking $label kt-evalution [css3-page] \\*)] Flags permitted.'), {
812
- tag: '*',
813
- command: 'OK',
814
- attributes: [
815
- {
816
- type: 'ATOM',
817
- value: '',
818
- section: [
819
- {
820
- type: 'ATOM',
821
- value: 'PERMANENTFLAGS'
822
- },
823
- [
824
- {
825
- type: 'ATOM',
826
- value: 'de:hacking'
827
- },
828
- {
829
- type: 'ATOM',
830
- value: '$label'
831
- },
832
- {
833
- type: 'ATOM',
834
- value: 'kt-evalution'
835
- },
836
- {
837
- type: 'ATOM',
838
- value: '[css3-page]'
839
- },
840
- {
841
- type: 'ATOM',
842
- value: '\\*'
843
- }
844
- ]
845
- ]
846
- },
847
- {
848
- type: 'TEXT',
849
- value: 'Flags permitted.'
850
- }
851
- ]
852
- })
853
- );
854
-
855
- // COPYUID is from RFC4315 and included the previously failing
856
- // parsing situation of a sequence terminated by ']' rather than
857
- // whitespace.
858
- module.exports['IMAP Parser: Section: COPYUID'] = test =>
859
- asyncWrapper(test, async test =>
860
- test.deepEqual(await parser('TAG1 OK [COPYUID 4 1417051618:1417051620 1421730687:1421730689] COPY completed'), {
861
- tag: 'TAG1',
862
- command: 'OK',
863
- attributes: [
864
- {
865
- type: 'ATOM',
866
- value: '',
867
- section: [
868
- {
869
- type: 'ATOM',
870
- value: 'COPYUID'
871
- },
872
- {
873
- type: 'ATOM',
874
- value: '4'
875
- },
876
- {
877
- type: 'SEQUENCE',
878
- value: '1417051618:1417051620'
879
- },
880
- {
881
- type: 'SEQUENCE',
882
- value: '1421730687:1421730689'
883
- }
884
- ]
885
- },
886
- {
887
- type: 'TEXT',
888
- value: 'COPY completed'
889
- }
890
- ]
891
- })
892
- );
893
-
894
- // MODIFIED is from RFC4551 and is basically the same situation
895
- // as the COPYUID case, but in this case our example sequences
896
- // have commas in them. (Note that if there was no comma, the
897
- // '7,9' payload would end up an ATOM.)
898
- module.exports['IMAP Parser: Section: MODIFIED'] = test =>
899
- asyncWrapper(test, async test =>
900
- test.deepEqual(await parser('TAG1 OK [MODIFIED 7,9] Conditional STORE failed'), {
901
- tag: 'TAG1',
902
- command: 'OK',
903
- attributes: [
904
- {
905
- type: 'ATOM',
906
- value: '',
907
- section: [
908
- {
909
- type: 'ATOM',
910
- value: 'MODIFIED'
911
- },
912
- {
913
- type: 'SEQUENCE',
914
- value: '7,9'
915
- }
916
- ]
917
- },
918
- {
919
- type: 'TEXT',
920
- value: 'Conditional STORE failed'
921
- }
922
- ]
923
- })
924
- );
925
-
926
- module.exports['IMAP Parser: Partial: Start'] = test =>
927
- asyncWrapper(test, async test =>
928
- test.deepEqual((await parser('TAG1 CMD BODY[]<0>')).attributes, [
929
- {
930
- type: 'ATOM',
931
- value: 'BODY',
932
- section: [],
933
- partial: [0]
934
- }
935
- ])
936
- );
937
-
938
- module.exports['IMAP Parser: Partial: Start.End'] = test =>
939
- asyncWrapper(test, async test =>
940
- test.deepEqual((await parser('TAG1 CMD BODY[]<12.45>')).attributes, [
941
- {
942
- type: 'ATOM',
943
- value: 'BODY',
944
- section: [],
945
- partial: [12, 45]
946
- }
947
- ])
948
- );
949
-
950
- module.exports['IMAP Parser: Partial: Section'] = test =>
951
- asyncWrapper(test, async test =>
952
- test.deepEqual((await parser('TAG1 CMD BODY[HEADER.FIELDS (Subject From)]<12.45>')).attributes, [
953
- {
954
- type: 'ATOM',
955
- value: 'BODY',
956
- section: [
957
- // keep indentation
958
- {
959
- type: 'ATOM',
960
- value: 'HEADER.FIELDS'
961
- },
962
- [
963
- {
964
- type: 'ATOM',
965
- value: 'Subject'
966
- },
967
- {
968
- type: 'ATOM',
969
- value: 'From'
970
- }
971
- ]
972
- ],
973
- partial: [12, 45]
974
- }
975
- ])
976
- );
977
-
978
- module.exports['IMAP Parser: Partial: fail zero prefix for start'] = test => asyncWrapperFail(test, async test => test.ok(await parser('TAG1 CMD BODY[]<01>')));
979
-
980
- module.exports['IMAP Parser: Partial: fail zero prefix for end'] = test => asyncWrapperFail(test, async test => test.ok(await parser('TAG1 CMD BODY[]<0.01>')));
981
-
982
- module.exports['IMAP Parser: Partial: fail extra separator'] = test => asyncWrapperFail(test, async test => test.ok(await parser('TAG1 CMD BODY[]<0.1.>')));
983
-
984
- module.exports['IMAP Parser: Sequence: mixed'] = test =>
985
- asyncWrapper(test, async test =>
986
- test.deepEqual((await parser('TAG1 CMD *:4,5:7 TEST')).attributes, [
987
- {
988
- type: 'SEQUENCE',
989
- value: '*:4,5:7'
990
- },
991
- {
992
- type: 'ATOM',
993
- value: 'TEST'
994
- }
995
- ])
996
- );
997
-
998
- module.exports['IMAP Parser: Sequence: range'] = test =>
999
- asyncWrapper(test, async test =>
1000
- test.deepEqual((await parser('TAG1 CMD 1:* TEST')).attributes, [
1001
- {
1002
- type: 'SEQUENCE',
1003
- value: '1:*'
1004
- },
1005
- {
1006
- type: 'ATOM',
1007
- value: 'TEST'
1008
- }
1009
- ])
1010
- );
1011
-
1012
- module.exports['IMAP Parser: Sequence: limited range'] = test =>
1013
- asyncWrapper(test, async test =>
1014
- test.deepEqual((await parser('TAG1 CMD *:4 TEST')).attributes, [
1015
- {
1016
- type: 'SEQUENCE',
1017
- value: '*:4'
1018
- },
1019
- {
1020
- type: 'ATOM',
1021
- value: 'TEST'
1022
- }
1023
- ])
1024
- );
1025
-
1026
- module.exports['IMAP Parser: Sequence: fail partial range'] = test => asyncWrapperFail(test, async test => test.ok(await parser('TAG1 CMD *:4,5:')));
1027
-
1028
- module.exports['IMAP Parser: Sequence: fail invalid chars'] = test => asyncWrapperFail(test, async test => test.ok(await parser('TAG1 CMD *:4,5:TEST TEST')));
1029
-
1030
- module.exports['IMAP Parser: Sequence: fail partial range w/ args'] = test =>
1031
- asyncWrapperFail(test, async test => test.ok(await parser('TAG1 CMD *:4,5: TEST')));
1032
-
1033
- module.exports['IMAP Parser: Sequence: fail missing colon'] = test => asyncWrapperFail(test, async test => test.ok(await parser('TAG1 CMD *4,5 TEST')));
1034
-
1035
- module.exports['IMAP Parser: Sequence: fail non-range wildchar 1'] = test => asyncWrapperFail(test, async test => test.ok(await parser('TAG1 CMD *,5 TEST')));
1036
-
1037
- module.exports['IMAP Parser: Sequence: fail non-range wildchar 2'] = test => asyncWrapperFail(test, async test => test.ok(await parser('TAG1 CMD 5,* TEST')));
1038
-
1039
- module.exports['IMAP Parser: Sequence: failextra comma'] = test => asyncWrapperFail(test, async test => test.ok(await parser('TAG1 CMD 5, TEST')));
1040
-
1041
- module.exports['IMAP Parser: escaped quotes'] = test =>
1042
- asyncWrapper(test, async test =>
1043
- test.deepEqual((await parser('* 331 FETCH (ENVELOPE ("=?ISO-8859-1?Q?\\"G=FCnter__Hammerl\\"?="))')).attributes, [
1044
- {
1045
- type: 'ATOM',
1046
- value: 'FETCH'
1047
- },
1048
- [
1049
- {
1050
- type: 'ATOM',
1051
- value: 'ENVELOPE'
1052
- },
1053
- [
1054
- {
1055
- type: 'STRING',
1056
- value: '=?ISO-8859-1?Q?"G=FCnter__Hammerl"?='
1057
- }
1058
- ]
1059
- ]
1060
- ])
1061
- );
1062
-
1063
- module.exports['IMAP Parser: mimetorture'] = test => asyncWrapper(test, async test => test.deepEqual(await parser(mimetorture.input), mimetorture.output));
1064
-
1065
- module.exports['IMAP Parser, unicode select'] = test =>
1066
- asyncWrapper(test, async test =>
1067
- test.deepEqual((await parser('F OK [READ-WRITE] [Gmail]/Visi laiškai selected. (Success) [THROTTLED]')).attributes, [
1068
- {
1069
- type: 'ATOM',
1070
- value: '',
1071
- section: [{ type: 'ATOM', value: 'READ-WRITE' }]
1072
- },
1073
- { type: 'TEXT', value: '[Gmail]/Visi laiškai selected. (Success) [THROTTLED]' }
1074
- ])
1075
- );
1076
-
1077
- module.exports['IMAP Parser, unicode select 2'] = test =>
1078
- asyncWrapper(test, async test =>
1079
- test.deepEqual((await parser('E OK [READ-WRITE] [Gmail]/Вся почта selected. (Success) [THROTTLED]')).attributes, [
1080
- {
1081
- type: 'ATOM',
1082
- value: '',
1083
- section: [{ type: 'ATOM', value: 'READ-WRITE' }]
1084
- },
1085
- { type: 'TEXT', value: '[Gmail]/Вся почта selected. (Success) [THROTTLED]' }
1086
- ])
1087
- );
1088
-
1089
- module.exports['IMAP Parser, single quote in atom'] = test =>
1090
- asyncWrapper(test, async test =>
1091
- test.deepEqual((await parser('* LIST (HasNoChildren UnMarked) "/" \'a')).attributes, [
1092
- [
1093
- { type: 'ATOM', value: 'HasNoChildren' },
1094
- { type: 'ATOM', value: 'UnMarked' }
1095
- ],
1096
- { type: 'STRING', value: '/' },
1097
- { type: 'ATOM', value: "'a" }
1098
- ])
1099
- );
1100
-
1101
- module.exports['IMAP Parser, unicode status 1'] = test =>
1102
- asyncWrapper(test, async test =>
1103
- test.deepEqual((await parser('* STATUS Segregator/Społeczności (MESSAGES 0 UIDNEXT 1 UIDVALIDITY 1)')).attributes, [
1104
- { type: 'ATOM', value: 'Segregator/Społeczności' },
1105
- [
1106
- { type: 'ATOM', value: 'MESSAGES' },
1107
- { type: 'ATOM', value: '0' },
1108
- { type: 'ATOM', value: 'UIDNEXT' },
1109
- { type: 'ATOM', value: '1' },
1110
- { type: 'ATOM', value: 'UIDVALIDITY' },
1111
- { type: 'ATOM', value: '1' }
1112
- ]
1113
- ])
1114
- );
1115
- module.exports['IMAP Parser, unicode status 12'] = test =>
1116
- asyncWrapper(test, async test =>
1117
- test.deepEqual((await parser('* STATUS Šegregator/Społeczności (MESSAGES 0 UIDNEXT 1 UIDVALIDITY 1)')).attributes, [
1118
- { type: 'ATOM', value: 'Šegregator/Społeczności' },
1119
- [
1120
- { type: 'ATOM', value: 'MESSAGES' },
1121
- { type: 'ATOM', value: '0' },
1122
- { type: 'ATOM', value: 'UIDNEXT' },
1123
- { type: 'ATOM', value: '1' },
1124
- { type: 'ATOM', value: 'UIDVALIDITY' },
1125
- { type: 'ATOM', value: '1' }
1126
- ]
1127
- ])
1128
- );
1129
-
1130
- module.exports['IMAP Parser, NO with a dot'] = test =>
1131
- asyncWrapper(test, async test => {
1132
- let parsed = await parser('X NO Server Unavailable. 15');
1133
- test.equal(parsed.command, 'NO');
1134
- test.deepEqual(parsed.attributes, [{ type: 'TEXT', value: 'Server Unavailable. 15' }]);
1135
- });
1136
-
1137
- module.exports['IMAP Parser, no tag or response (Exchange)'] = test =>
1138
- asyncWrapper(test, async test => {
1139
- let parsed = await parser('Server Unavailable. 15');
1140
- test.equal(parsed.command, 'BAD');
1141
- test.deepEqual(parsed.attributes, [{ type: 'TEXT', value: 'Server Unavailable. 15' }]);
1142
- });
1143
-
1144
- module.exports['IMAP Parser, BAD with throttling'] = test =>
1145
- asyncWrapper(test, async test => {
1146
- let parsed = await parser('X BAD Request is throttled. Suggested Backoff Time: 92415 milliseconds');
1147
- test.equal(parsed.command, 'BAD');
1148
- test.deepEqual(parsed.attributes, [{ type: 'TEXT', value: 'Request is throttled. Suggested Backoff Time: 92415 milliseconds' }]);
1149
- });
1150
-
1151
- module.exports['IMAP Parser, subfolder square bracket'] = test =>
1152
- asyncWrapper(test, async test => {
1153
- let parsed = await parser('* LIST (\\UnMarked) "." INBOX.[Airmail].Snooze');
1154
- test.deepEqual(parsed.attributes, [
1155
- [{ type: 'ATOM', value: '\\UnMarked' }],
1156
- { type: 'STRING', value: '.' },
1157
- { type: 'ATOM', value: 'INBOX.[Airmail].Snooze' }
1158
- ]);
1159
- });
1160
-
1161
- module.exports['IMAP Parser, FETCH with full range'] = test =>
1162
- asyncWrapper(test, async test => {
1163
- let parsed = await parser('* 32 FETCH (UID 32 RFC822.SIZE 3991 BODY[2.MIME] "(* 61B literal *)" BODY[2]<0.65536> "(* 6B literal *)")');
1164
- test.deepEqual(parsed.attributes, [
1165
- {
1166
- type: 'ATOM',
1167
- value: 'FETCH'
1168
- },
1169
- [
1170
- {
1171
- type: 'ATOM',
1172
- value: 'UID'
1173
- },
1174
- {
1175
- type: 'ATOM',
1176
- value: '32'
1177
- },
1178
- {
1179
- type: 'ATOM',
1180
- value: 'RFC822.SIZE'
1181
- },
1182
- {
1183
- type: 'ATOM',
1184
- value: '3991'
1185
- },
1186
- {
1187
- type: 'ATOM',
1188
- value: 'BODY',
1189
- section: [
1190
- {
1191
- type: 'ATOM',
1192
- value: '2.MIME'
1193
- }
1194
- ]
1195
- },
1196
- {
1197
- type: 'STRING',
1198
- value: '(* 61B literal *)'
1199
- },
1200
- {
1201
- type: 'ATOM',
1202
- value: 'BODY',
1203
- section: [
1204
- {
1205
- type: 'ATOM',
1206
- value: '2'
1207
- }
1208
- ],
1209
- partial: [0, 65536]
1210
- },
1211
- {
1212
- type: 'STRING',
1213
- value: '(* 6B literal *)'
1214
- }
1215
- ]
1216
- ]);
1217
- });
1218
-
1219
- module.exports['IMAP Parser, FETCH with BODYSTRUCTURE'] = test =>
1220
- asyncWrapper(test, async test => {
1221
- let parsed = await parser(
1222
- '* 1013 FETCH (UID 2986 MODSEQ (4960) BODYSTRUCTURE (("text" "plain" ("charset" "us-ascii") NIL NIL "7bit" 16 1 NIL NIL NIL NIL)("message" "rfc822" ("name" "Tellimuse Microsoft 365 Business Standard arve vaatamine.eml") NIL NIL "7bit" 370684 ("Mon, 16 Dec 2024 03:28:28 +0000" "Tellimuse Microsoft 365 Business Standard arve vaatamine" (("Microsoft" NIL "microsoft-noreply" "microsoft.com")) (("Microsoft" NIL "microsoft-noreply" "microsoft.com")) (("Microsoft" NIL "microsoft-noreply" "microsoft.com")) ((NIL NIL "andris.reinman" "gmail.com")) NIL NIL NIL "<58710631-775f-4c07-96ff-28a776f44d90@az.eastus2.microsoft.com>") ((("text" "plain" ("charset" "utf-8") NIL NIL "quoted-printable" 2866 80 NIL NIL NIL NIL)("text" "html" ("charset" "utf-8") NIL NIL "quoted-printable" 78392 1770 NIL NIL NIL NIL) "alternative" ("boundary" "=-EcWGOW6mwE+0T4lm385OWw==") NIL NIL NIL)("application" "octet-stream" ("name" "52482541500.pdf") NIL NIL "base64" 279430 NIL ("attachment" ("filename" "52482541500.pdf")) NIL NIL) "mixed" ("boundary" "=-1wJq2CLBJ6H+Zk2GPX9FKw==") NIL NIL NIL) 5580 NIL ("attachment" ("filename" "Tellimuse Microsoft 365 Business Standard arve vaatamine.eml")) NIL NIL) "mixed" ("boundary" "Apple-Mail=_F700EE9B-43B1-4EF1-95EE-CAA13391B333") NIL NIL NIL))'
1223
- );
1224
-
1225
- test.deepEqual(parsed.attributes, [
1226
- { type: 'ATOM', value: 'FETCH' },
1227
- [
1228
- { type: 'ATOM', value: 'UID' },
1229
- { type: 'ATOM', value: '2986' },
1230
- { type: 'ATOM', value: 'MODSEQ' },
1231
- [{ type: 'ATOM', value: '4960' }],
1232
- { type: 'ATOM', value: 'BODYSTRUCTURE' },
1233
- [
1234
- [
1235
- { type: 'STRING', value: 'text' },
1236
- { type: 'STRING', value: 'plain' },
1237
- [
1238
- { type: 'STRING', value: 'charset' },
1239
- { type: 'STRING', value: 'us-ascii' }
1240
- ],
1241
- null,
1242
- null,
1243
- { type: 'STRING', value: '7bit' },
1244
- { type: 'ATOM', value: '16' },
1245
- { type: 'ATOM', value: '1' },
1246
- null,
1247
- null,
1248
- null,
1249
- null
1250
- ],
1251
- [
1252
- { type: 'STRING', value: 'message' },
1253
- { type: 'STRING', value: 'rfc822' },
1254
- [
1255
- { type: 'STRING', value: 'name' },
1256
- { type: 'STRING', value: 'Tellimuse Microsoft 365 Business Standard arve vaatamine.eml' }
1257
- ],
1258
- null,
1259
- null,
1260
- { type: 'STRING', value: '7bit' },
1261
- { type: 'ATOM', value: '370684' },
1262
- [
1263
- { type: 'STRING', value: 'Mon, 16 Dec 2024 03:28:28 +0000' },
1264
- { type: 'STRING', value: 'Tellimuse Microsoft 365 Business Standard arve vaatamine' },
1265
- [
1266
- [
1267
- { type: 'STRING', value: 'Microsoft' },
1268
- null,
1269
- { type: 'STRING', value: 'microsoft-noreply' },
1270
- { type: 'STRING', value: 'microsoft.com' }
1271
- ]
1272
- ],
1273
- [
1274
- [
1275
- { type: 'STRING', value: 'Microsoft' },
1276
- null,
1277
- { type: 'STRING', value: 'microsoft-noreply' },
1278
- { type: 'STRING', value: 'microsoft.com' }
1279
- ]
1280
- ],
1281
- [
1282
- [
1283
- { type: 'STRING', value: 'Microsoft' },
1284
- null,
1285
- { type: 'STRING', value: 'microsoft-noreply' },
1286
- { type: 'STRING', value: 'microsoft.com' }
1287
- ]
1288
- ],
1289
- [[null, null, { type: 'STRING', value: 'andris.reinman' }, { type: 'STRING', value: 'gmail.com' }]],
1290
- null,
1291
- null,
1292
- null,
1293
- { type: 'STRING', value: '<58710631-775f-4c07-96ff-28a776f44d90@az.eastus2.microsoft.com>' }
1294
- ],
1295
- [
1296
- [
1297
- [
1298
- { type: 'STRING', value: 'text' },
1299
- { type: 'STRING', value: 'plain' },
1300
- [
1301
- { type: 'STRING', value: 'charset' },
1302
- { type: 'STRING', value: 'utf-8' }
1303
- ],
1304
- null,
1305
- null,
1306
- { type: 'STRING', value: 'quoted-printable' },
1307
- { type: 'ATOM', value: '2866' },
1308
- { type: 'ATOM', value: '80' },
1309
- null,
1310
- null,
1311
- null,
1312
- null
1313
- ],
1314
- [
1315
- { type: 'STRING', value: 'text' },
1316
- { type: 'STRING', value: 'html' },
1317
- [
1318
- { type: 'STRING', value: 'charset' },
1319
- { type: 'STRING', value: 'utf-8' }
1320
- ],
1321
- null,
1322
- null,
1323
- { type: 'STRING', value: 'quoted-printable' },
1324
- { type: 'ATOM', value: '78392' },
1325
- { type: 'ATOM', value: '1770' },
1326
- null,
1327
- null,
1328
- null,
1329
- null
1330
- ],
1331
- { type: 'STRING', value: 'alternative' },
1332
- [
1333
- { type: 'STRING', value: 'boundary' },
1334
- { type: 'STRING', value: '=-EcWGOW6mwE+0T4lm385OWw==' }
1335
- ],
1336
- null,
1337
- null,
1338
- null
1339
- ],
1340
- [
1341
- { type: 'STRING', value: 'application' },
1342
- { type: 'STRING', value: 'octet-stream' },
1343
- [
1344
- { type: 'STRING', value: 'name' },
1345
- { type: 'STRING', value: '52482541500.pdf' }
1346
- ],
1347
- null,
1348
- null,
1349
- { type: 'STRING', value: 'base64' },
1350
- { type: 'ATOM', value: '279430' },
1351
- null,
1352
- [
1353
- { type: 'STRING', value: 'attachment' },
1354
- [
1355
- { type: 'STRING', value: 'filename' },
1356
- { type: 'STRING', value: '52482541500.pdf' }
1357
- ]
1358
- ],
1359
- null,
1360
- null
1361
- ],
1362
- { type: 'STRING', value: 'mixed' },
1363
- [
1364
- { type: 'STRING', value: 'boundary' },
1365
- { type: 'STRING', value: '=-1wJq2CLBJ6H+Zk2GPX9FKw==' }
1366
- ],
1367
- null,
1368
- null,
1369
- null
1370
- ],
1371
- { type: 'ATOM', value: '5580' },
1372
- null,
1373
- [
1374
- { type: 'STRING', value: 'attachment' },
1375
- [
1376
- { type: 'STRING', value: 'filename' },
1377
- { type: 'STRING', value: 'Tellimuse Microsoft 365 Business Standard arve vaatamine.eml' }
1378
- ]
1379
- ],
1380
- null,
1381
- null
1382
- ],
1383
- { type: 'STRING', value: 'mixed' },
1384
- [
1385
- { type: 'STRING', value: 'boundary' },
1386
- { type: 'STRING', value: 'Apple-Mail=_F700EE9B-43B1-4EF1-95EE-CAA13391B333' }
1387
- ],
1388
- null,
1389
- null,
1390
- null
1391
- ]
1392
- ]
1393
- ]);
1394
- });
1395
-
1396
- // NB! must not share a name with the deep-BODYSTRUCTURE test above - a duplicate
1397
- // module.exports key silently overwrites the earlier test and it never runs
1398
- module.exports['IMAP Parser, FETCH exceeding max nesting depth'] = test =>
1399
- asyncWrapper(test, async test => {
1400
- try {
1401
- let parsed = await parser('* 1 FETCH (UID 1 (((((((((((((((((((((((((');
1402
- test.ok(!parsed);
1403
- } catch (err) {
1404
- test.ok(err);
1405
- if (err.code !== 'MAX_IMAP_NESTING_REACHED') {
1406
- throw err;
1407
- }
1408
- }
1409
- });
1410
-
1411
- module.exports['IMAP Parser, ATOM with <, [, ]'] = test =>
1412
- asyncWrapper(test, async test => {
1413
- let password = `<[+=</$]`;
1414
- let parsed = await parser(`3 LOGIN user@domain ${password}`);
1415
- test.deepEqual(parsed, {
1416
- tag: '3',
1417
- command: 'LOGIN',
1418
- attributes: [
1419
- { type: 'ATOM', value: 'user@domain' },
1420
- { type: 'ATOM', value: password }
1421
- ]
1422
- });
1423
- });
1424
-
1425
- module.exports['IMAP Parser: unbalanced bracket in a response code keeps the human-readable text'] = test =>
1426
- asyncWrapper(test, async test => {
1427
- // RFC 9051 lets a response code carry free text containing '[' but not ']'.
1428
- // Counting that '[' as a nested bracket loses the whole human-readable text,
1429
- // which is what NO/BAD error messages are built from.
1430
- const parsed = await parser('A1 NO [XFOO see bar[baz] mailbox is busy');
1431
- const text = (parsed.attributes || [])
1432
- .filter(entry => entry && entry.type === 'TEXT')
1433
- .map(entry => entry.value)
1434
- .join('');
1435
- test.equal(text, 'mailbox is busy');
1436
- });
1437
-
1438
- module.exports['IMAP Parser: balanced brackets inside a response code are still tolerated'] = test =>
1439
- asyncWrapper(test, async test => {
1440
- // Servers do put bracketed values inside a code, so a plain first-']' scan
1441
- // would cut the code in half
1442
- const parsed = await parser('* OK [PERMANENTFLAGS ([css3-page] \\*)] Flags permitted.');
1443
- const text = (parsed.attributes || [])
1444
- .filter(entry => entry && entry.type === 'TEXT')
1445
- .map(entry => entry.value)
1446
- .join('');
1447
- test.equal(text, 'Flags permitted.');
1448
- test.equal(parsed.attributes[0].section[0].value, 'PERMANENTFLAGS');
1449
- });
1450
-
1451
- module.exports['IMAP Parser: a parse failure after the tag exposes the parsed tag'] = test =>
1452
- asyncWrapper(test, async test => {
1453
- // The connection settles the in-flight command from an unparseable tagged
1454
- // completion using this tag - re-deriving it from the raw bytes instead would
1455
- // bypass the leading-NUL workaround and strand the command
1456
- let err = null;
1457
- try {
1458
- await parser(Buffer.from('A5 OK [\x01BAD-CODE] done', 'binary'));
1459
- } catch (e) {
1460
- err = e;
1461
- }
1462
- test.ok(err, 'the line must fail to parse');
1463
- test.equal(err && err.parsedTag, 'A5');
1464
-
1465
- // The NUL-padding workaround is inherited: the exposed tag is the stripped one
1466
- err = null;
1467
- try {
1468
- await parser(Buffer.from('\x00\x00A6 OK [\x01BAD-CODE] done', 'binary'));
1469
- } catch (e) {
1470
- err = e;
1471
- }
1472
- test.ok(err, 'the padded line must fail to parse');
1473
- test.equal(err && err.parsedTag, 'A6');
1474
- });