pure-md5 0.2.0 → 0.2.2

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 (177) hide show
  1. package/README.md +38 -24
  2. package/dist/adapters/ie11.cjs +1 -2
  3. package/dist/adapters/ie11.js +1 -2
  4. package/dist/adapters/node.cjs +1 -2
  5. package/dist/adapters/node.js +1 -2
  6. package/dist/adapters/webcrypto.cjs +1 -2
  7. package/dist/adapters/webcrypto.js +1 -2
  8. package/dist/index.cjs +1 -2
  9. package/dist/index.d.ts +149 -5
  10. package/dist/index.js +3 -2
  11. package/dist/md5.cjs +1 -0
  12. package/dist/md5.d.ts +20 -0
  13. package/dist/md5.js +1 -0
  14. package/dist/stream/md5-stream.cjs +1 -2
  15. package/dist/stream/md5-stream.js +1 -2
  16. package/dist/stream/whatwg-stream.cjs +1 -2
  17. package/dist/stream/whatwg-stream.js +1 -2
  18. package/dist/utils/detect.cjs +1 -2
  19. package/dist/utils/detect.js +3 -2
  20. package/package.json +10 -15
  21. package/pure-md5-0.2.1.tgz +0 -0
  22. package/test-tree-shake.mjs +12 -0
  23. package/.aliases +0 -19
  24. package/.bash_profile +0 -12
  25. package/.bash_prompt +0 -56
  26. package/.changeset/README.md +0 -32
  27. package/.changeset/config.json +0 -16
  28. package/.continue/mcpServers/new-mcp-server.yaml +0 -10
  29. package/.continue/rules +0 -29
  30. package/.github/ISSUE_TEMPLATE/bug_report.md +0 -35
  31. package/.github/ISSUE_TEMPLATE/documentation.md +0 -20
  32. package/.github/ISSUE_TEMPLATE/feature_request.md +0 -20
  33. package/.github/PULL_REQUEST_TEMPLATE.md +0 -35
  34. package/.github/workflows/npm-publish.yml +0 -33
  35. package/.github/workflows/release.yml +0 -42
  36. package/CHANGELOG.md +0 -9
  37. package/CONTRIBUTING.md +0 -203
  38. package/MIGRATION_GUIDE_STREAMS.md +0 -374
  39. package/STREAM_API.md +0 -582
  40. package/STREAM_BENCHMARKS.md +0 -232
  41. package/STREAM_EXAMPLES.md +0 -669
  42. package/STREAM_OPTIMIZATION_REPORT.md +0 -136
  43. package/STREAM_TROUBLESHOOTING.md +0 -537
  44. package/WEB_CRYPTO_TESTS_SUMMARY.md +0 -140
  45. package/WHATWG_STREAMS.md +0 -191
  46. package/__tests__/adapters/node-crypto.test.ts +0 -167
  47. package/__tests__/adapters/web-crypto-node.test.ts +0 -73
  48. package/__tests__/adapters/web-crypto.test.ts +0 -195
  49. package/__tests__/add32.test.ts +0 -33
  50. package/__tests__/fallback.test.ts +0 -345
  51. package/__tests__/hex.test.ts +0 -38
  52. package/__tests__/hex_chr.test.ts +0 -20
  53. package/__tests__/index.test.ts +0 -87
  54. package/__tests__/integration/fixtures/test-file.txt +0 -1
  55. package/__tests__/integration/md5-stream-file.test.ts +0 -293
  56. package/__tests__/integration/node-crypto-file.test.ts +0 -86
  57. package/__tests__/integration/web-crypto.test.ts +0 -38
  58. package/__tests__/md51.test.ts +0 -73
  59. package/__tests__/md5block.test.ts +0 -61
  60. package/__tests__/md5cycle.test.ts +0 -48
  61. package/__tests__/round-functions.test.ts +0 -87
  62. package/__tests__/stream/fs-utils.test.ts +0 -209
  63. package/__tests__/stream/md5-stream-edge-cases.test.ts +0 -461
  64. package/__tests__/stream/md5-stream.test.ts +0 -418
  65. package/__tests__/stream/whatwg-stream.test.ts +0 -355
  66. package/__tests__/stream/whatwg-stream.test.ts.bak2 +0 -335
  67. package/benchmarks/md5-stream.bench.ts +0 -212
  68. package/benchmarks/whatwg-stream.bench.ts +0 -180
  69. package/dist/adapters/ie11.cjs.map +0 -1
  70. package/dist/adapters/ie11.js.map +0 -1
  71. package/dist/adapters/node.cjs.map +0 -1
  72. package/dist/adapters/node.js.map +0 -1
  73. package/dist/adapters/webcrypto.cjs.map +0 -1
  74. package/dist/adapters/webcrypto.js.map +0 -1
  75. package/dist/chunk-2YXXFGBV.js +0 -2
  76. package/dist/chunk-2YXXFGBV.js.map +0 -1
  77. package/dist/chunk-4KSCMS4Q.js +0 -2
  78. package/dist/chunk-4KSCMS4Q.js.map +0 -1
  79. package/dist/chunk-6P2QV5SR.js +0 -4
  80. package/dist/chunk-6P2QV5SR.js.map +0 -1
  81. package/dist/chunk-G5WHEAIQ.js +0 -2
  82. package/dist/chunk-G5WHEAIQ.js.map +0 -1
  83. package/dist/chunk-H2K353LR.js +0 -2
  84. package/dist/chunk-H2K353LR.js.map +0 -1
  85. package/dist/chunk-JKVD5LHZ.js +0 -2
  86. package/dist/chunk-JKVD5LHZ.js.map +0 -1
  87. package/dist/chunk-NWQ4N5RX.js +0 -2
  88. package/dist/chunk-NWQ4N5RX.js.map +0 -1
  89. package/dist/chunk-PHZ7FTYF.js +0 -2
  90. package/dist/chunk-PHZ7FTYF.js.map +0 -1
  91. package/dist/chunk-PNZTVQA7.js +0 -2
  92. package/dist/chunk-PNZTVQA7.js.map +0 -1
  93. package/dist/chunk-R4JB5MBR.js +0 -2
  94. package/dist/chunk-R4JB5MBR.js.map +0 -1
  95. package/dist/chunk-VFOAY6XI.js +0 -2
  96. package/dist/chunk-VFOAY6XI.js.map +0 -1
  97. package/dist/chunk-XB5BQIEX.js +0 -2
  98. package/dist/chunk-XB5BQIEX.js.map +0 -1
  99. package/dist/core/index.cjs +0 -2
  100. package/dist/core/index.cjs.map +0 -1
  101. package/dist/core/index.d.cts +0 -19
  102. package/dist/core/index.d.ts +0 -19
  103. package/dist/core/index.js +0 -2
  104. package/dist/core/index.js.map +0 -1
  105. package/dist/index.cjs.map +0 -1
  106. package/dist/index.d.cts +0 -84
  107. package/dist/index.js.map +0 -1
  108. package/dist/stream/adapter.cjs +0 -2
  109. package/dist/stream/adapter.cjs.map +0 -1
  110. package/dist/stream/adapter.d.cts +0 -63
  111. package/dist/stream/adapter.d.ts +0 -63
  112. package/dist/stream/adapter.js +0 -2
  113. package/dist/stream/adapter.js.map +0 -1
  114. package/dist/stream/fs-utils.cjs +0 -2
  115. package/dist/stream/fs-utils.cjs.map +0 -1
  116. package/dist/stream/fs-utils.d.cts +0 -137
  117. package/dist/stream/fs-utils.d.ts +0 -137
  118. package/dist/stream/fs-utils.js +0 -2
  119. package/dist/stream/fs-utils.js.map +0 -1
  120. package/dist/stream/index.cjs +0 -2
  121. package/dist/stream/index.cjs.map +0 -1
  122. package/dist/stream/index.d.cts +0 -4
  123. package/dist/stream/index.d.ts +0 -4
  124. package/dist/stream/index.js +0 -2
  125. package/dist/stream/index.js.map +0 -1
  126. package/dist/stream/light/index.cjs +0 -2
  127. package/dist/stream/light/index.cjs.map +0 -1
  128. package/dist/stream/light/index.d.cts +0 -4
  129. package/dist/stream/light/index.d.ts +0 -4
  130. package/dist/stream/light/index.js +0 -2
  131. package/dist/stream/light/index.js.map +0 -1
  132. package/dist/stream/md5-stream.cjs.map +0 -1
  133. package/dist/stream/md5-stream.js.map +0 -1
  134. package/dist/stream/whatwg-stream.cjs.map +0 -1
  135. package/dist/stream/whatwg-stream.js.map +0 -1
  136. package/dist/types-edGoGJ5V.d.cts +0 -42
  137. package/dist/types-edGoGJ5V.d.ts +0 -42
  138. package/dist/utils/detect.cjs.map +0 -1
  139. package/dist/utils/detect.js.map +0 -1
  140. package/planning/03-optimization-size-tree-shaking/01-es-modules-tree-shaking.md +0 -152
  141. package/planning/03-optimization-size-tree-shaking/02-consolidate-modules.md +0 -65
  142. package/planning/03-optimization-size-tree-shaking/03-remove-duplicate-add32.md +0 -93
  143. package/planning/03-optimization-size-tree-shaking/04-remove-runtime-check.md +0 -102
  144. package/planning/03-optimization-size-tree-shaking/05-optimize-loops-performance.md +0 -107
  145. package/planning/03-optimization-size-tree-shaking/06-tsup-formats-configuration.md +0 -227
  146. package/planning/03-optimization-size-tree-shaking/07-multiple-build-formats.md +0 -228
  147. package/planning/03-optimization-size-tree-shaking/08-benchmarks-metrics.md +0 -34
  148. package/planning/03-optimization-size-tree-shaking/MIGRATION_GUIDE.md +0 -260
  149. package/planning/03-optimization-size-tree-shaking/README.md +0 -173
  150. package/planning/03-optimization-size-tree-shaking/SUMMARY.md +0 -168
  151. package/planning/04-adapter-backend/03-backend-web-crypto.md +0 -149
  152. package/planning/04-adapter-backend/04-backend-node-crypto.md +0 -181
  153. package/planning/04-adapter-backend/05-backend-pure-js.md +0 -174
  154. package/planning/04-adapter-backend/06-backend-ie11.md +0 -158
  155. package/planning/04-adapter-backend/07-detection-environment.md +0 -232
  156. package/planning/04-adapter-backend/08-detection-backend.md +0 -210
  157. package/planning/04-adapter-backend/09-adapter-unified.md +0 -255
  158. package/planning/04-adapter-backend/10-fallback-mechanism.md +0 -333
  159. package/planning/04-adapter-backend/11-tests-backend-web-crypto.md +0 -191
  160. package/planning/04-adapter-backend/12-tests-backend-node-crypto.md +0 -222
  161. package/planning/04-adapter-backend/README.md +0 -45
  162. package/planning/05-documentation-publishing/01-README-optimization.md +0 -105
  163. package/planning/05-documentation-publishing/02-VitePress-site-evaluation.md +0 -136
  164. package/planning/05-documentation-publishing/03-Changeset-setup.md +0 -192
  165. package/planning/05-documentation-publishing/04-GitHub-templates.md +0 -252
  166. package/planning/05-documentation-publishing/README.md +0 -22
  167. package/planning/05-documentation-publishing/STATUS.md +0 -222
  168. package/planning/prd.md +0 -405
  169. package/planning/streams/01-create-md5stream-class.md +0 -69
  170. package/planning/streams/02-create-factory-api.md +0 -65
  171. package/planning/streams/03-fs-integration.md +0 -37
  172. package/planning/streams/04-whatwg-streams-support.md +0 -37
  173. package/planning/streams/05-audit-optimization.md +0 -121
  174. package/planning/streams/06-comprehensive-tests-docs.md +0 -137
  175. package/planning/streams/07-architecture-integration.md +0 -38
  176. package/planning/streams/README.md +0 -98
  177. package/tsup.config.ts +0 -24
@@ -1,355 +0,0 @@
1
- /**
2
- * WHATWG Streams tests for browser environments
3
- * These tests verify the WHATWG Streams implementation works correctly
4
- */
5
-
6
- import { MD5ReadableStream, hashBlob } from '../../src/stream/whatwg-stream.js';
7
- import { md5Core } from '../../src/core/index.js';
8
-
9
- // Skip tests if WHATWG Streams are not available
10
- const canRunWhatwgTests = typeof ReadableStream !== 'undefined' && typeof Blob !== 'undefined';
11
-
12
- if (!canRunWhatwgTests) {
13
- console.log('WHATWG Streams not available, skipping tests');
14
- // Create empty tests to satisfy Jest requirement
15
- describe('MD5ReadableStream', () => {
16
- it('should skip when WHATWG Streams not available', () => {
17
- console.log('Skipping: WHATWG Streams not available');
18
- });
19
- });
20
-
21
- describe('hashBlob', () => {
22
- it('should skip when WHATWG Streams not available', () => {
23
- console.log('Skipping: WHATWG Streams not available');
24
- });
25
- });
26
-
27
- describe('integration', () => {
28
- it('should skip when WHATWG Streams not available', () => {
29
- console.log('Skipping: WHATWG Streams not available');
30
- });
31
- });
32
- } else {
33
-
34
- // Mock FileReader for Node.js environment
35
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
36
- (global as any).FileReader = class {
37
- static readonly EMPTY = 0;
38
- static readonly LOADING = 1;
39
- static readonly DONE = 2;
40
-
41
- _result: ArrayBuffer | string | null = null;
42
- onload: ((event: any) => void) | null = null;
43
- onerror: ((event: any) => void) | null = null;
44
-
45
- readAsArrayBuffer(blob: Blob) {
46
- blob.arrayBuffer().then((buffer) => {
47
- this._result = buffer;
48
- this.onload?.({
49
- target: {
50
- result: buffer
51
- }
52
- });
53
- }).catch((error) => {
54
- this.onerror?.({ error });
55
- });
56
- }
57
- };
58
-
59
- describe('MD5ReadableStream', () => {
60
- test('should compute MD5 hash for empty stream', async () => {
61
- const source = new ReadableStream({
62
- start(controller) {
63
- controller.close();
64
- }
65
- });
66
-
67
- const result = await MD5ReadableStream.hash(source);
68
-
69
- expect(result.digest).toBe(md5Core(''));
70
- expect(result.bytesProcessed).toBe(0);
71
- }, 10000);
72
-
73
- test('should compute MD5 hash for simple string', async () => {
74
- const input = 'hello';
75
- const source = new ReadableStream({
76
- start(controller) {
77
- controller.enqueue(new TextEncoder().encode(input));
78
- controller.close();
79
- }
80
- });
81
-
82
- const result = await MD5ReadableStream.hash(source);
83
-
84
- expect(result.digest).toBe(md5Core(input));
85
- expect(result.bytesProcessed).toBe(input.length);
86
- }, 10000);
87
-
88
- test('should compute MD5 hash for longer string', async () => {
89
- const input = 'a'.repeat(1000);
90
- const source = new ReadableStream({
91
- start(controller) {
92
- controller.enqueue(new TextEncoder().encode(input));
93
- controller.close();
94
- }
95
- });
96
-
97
- const result = await MD5ReadableStream.hash(source);
98
-
99
- expect(result.digest).toBe(md5Core(input));
100
- expect(result.bytesProcessed).toBe(input.length);
101
- }, 10000);
102
-
103
- test('should process chunked data correctly', async () => {
104
- const input = 'hello world';
105
- const source = new ReadableStream({
106
- start(controller) {
107
- controller.enqueue(new TextEncoder().encode('hello '));
108
- controller.enqueue(new TextEncoder().encode('world'));
109
- controller.close();
110
- }
111
- });
112
-
113
- const result = await MD5ReadableStream.hash(source);
114
-
115
- expect(result.digest).toBe(md5Core(input));
116
- expect(result.bytesProcessed).toBe(input.length);
117
- }, 10000);
118
-
119
- test('should handle multiple chunks of varying sizes', async () => {
120
- const input = 'This is a test string with multiple chunks';
121
- const chunks = ['This ', 'is a', ' test', ' string', ' with', ' multi', 'ple c', 'hunks'];
122
-
123
- const source = new ReadableStream({
124
- start(controller) {
125
- chunks.forEach(chunk => controller.enqueue(new TextEncoder().encode(chunk)));
126
- controller.close();
127
- }
128
- });
129
-
130
- const result = await MD5ReadableStream.hash(source);
131
-
132
- expect(result.digest).toBe(md5Core(input));
133
- expect(result.bytesProcessed).toBe(input.length);
134
- }, 10000);
135
-
136
- test('should handle data that exactly fills 64-byte blocks', async () => {
137
- const input = 'a'.repeat(64);
138
- const source = new ReadableStream({
139
- start(controller) {
140
- controller.enqueue(new TextEncoder().encode(input));
141
- controller.close();
142
- }
143
- });
144
-
145
- const result = await MD5ReadableStream.hash(source);
146
-
147
- expect(result.digest).toBe(md5Core(input));
148
- expect(result.bytesProcessed).toBe(input.length);
149
- }, 10000);
150
-
151
- test('should handle data that is multiple of 64 bytes', async () => {
152
- const input = 'a'.repeat(128);
153
- const source = new ReadableStream({
154
- start(controller) {
155
- controller.enqueue(new TextEncoder().encode(input));
156
- controller.close();
157
- }
158
- });
159
-
160
- const result = await MD5ReadableStream.hash(source);
161
-
162
- expect(result.digest).toBe(md5Core(input));
163
- expect(result.bytesProcessed).toBe(input.length);
164
- }, 10000);
165
-
166
- test('should handle special characters', async () => {
167
- const input = '!@#$%^&*()_+-=[]{}|;:,.<>?';
168
- const source = new ReadableStream({
169
- start(controller) {
170
- controller.enqueue(new TextEncoder().encode(input));
171
- controller.close();
172
- }
173
- });
174
-
175
- const result = await MD5ReadableStream.hash(source);
176
-
177
- expect(result.digest).toBe(md5Core(input));
178
- expect(result.bytesProcessed).toBe(input.length);
179
- }, 10000);
180
-
181
- test('should emit bytesProcessed correctly', async () => {
182
- const totalBytes = 256;
183
- const chunkSize = 64;
184
-
185
- const source = new ReadableStream({
186
- start(controller) {
187
- const chunk = new TextEncoder().encode('a'.repeat(chunkSize));
188
- for (let i = 0; i < 4; i++) {
189
- controller.enqueue(chunk);
190
- }
191
- controller.close();
192
- }
193
- });
194
-
195
- const result = await MD5ReadableStream.hash(source);
196
-
197
- expect(result.bytesProcessed).toBe(totalBytes);
198
- expect(result.digest.length).toBe(32);
199
- }, 10000);
200
-
201
- test('should support custom add32 function', async () => {
202
- const input = 'custom add32 test';
203
- const source = new ReadableStream({
204
- start(controller) {
205
- controller.enqueue(new TextEncoder().encode(input));
206
- controller.close();
207
- }
208
- });
209
-
210
- const customAdd32 = (x: number, y: number) => (x + y) & 0xffffffff;
211
- const result = await MD5ReadableStream.hash(source, { add32: customAdd32 });
212
-
213
- expect(result.digest).toBe(md5Core(input));
214
- expect(result.bytesProcessed).toBe(input.length);
215
- }, 10000);
216
-
217
- test('should handle sequential processing', async () => {
218
- const parts = ['Hello, ', 'World!', ' This is ', 'MD5 streaming.'];
219
- const full = parts.join('');
220
-
221
- const source = new ReadableStream({
222
- start(controller) {
223
- parts.forEach(part => controller.enqueue(new TextEncoder().encode(part)));
224
- controller.close();
225
- }
226
- });
227
-
228
- const result = await MD5ReadableStream.hash(source);
229
-
230
- expect(result.digest).toBe(md5Core(full));
231
- expect(result.bytesProcessed).toBe(full.length);
232
- }, 10000);
233
-
234
- test('should handle single byte chunks', async () => {
235
- const input = 'a';
236
- const source = new ReadableStream({
237
- start(controller) {
238
- controller.enqueue(new TextEncoder().encode(input));
239
- controller.close();
240
- }
241
- });
242
-
243
- const result = await MD5ReadableStream.hash(source);
244
-
245
- expect(result.digest).toBe(md5Core(input));
246
- expect(result.bytesProcessed).toBe(input.length);
247
- }, 10000);
248
-
249
- test('should emit valid hex digest', async () => {
250
- const source = new ReadableStream({
251
- start(controller) {
252
- controller.enqueue(new TextEncoder().encode('test'));
253
- controller.close();
254
- }
255
- });
256
-
257
- const result = await MD5ReadableStream.hash(source);
258
-
259
- // MD5 digest should be 32 hex characters
260
- expect(result.digest).toMatch(/^[0-9a-f]{32}$/);
261
- expect(result.digest.length).toBe(32);
262
- }, 10000);
263
-
264
- test('should get current state during processing', async () => {
265
- const source = new ReadableStream({
266
- start(controller) {
267
- controller.enqueue(new TextEncoder().encode('test'));
268
- controller.close();
269
- }
270
- });
271
-
272
- const stream = new MD5ReadableStream(source);
273
-
274
- // Check initial state before reading
275
- const initialState = stream.getCurrentState();
276
- expect(initialState.state).toHaveLength(4);
277
- expect(initialState.bytesProcessed).toBe(0);
278
-
279
- // Read some data
280
- const reader = stream.getReader();
281
- await reader.read();
282
-
283
- // Check state after reading
284
- const afterDataState = stream.getCurrentState();
285
- expect(afterDataState.bytesProcessed).toBe(4);
286
-
287
- // Check bytes processed getter
288
- expect(stream.getBytesProcessed()).toBe(4);
289
- }, 10000);
290
-
291
- test('should handle empty chunks', async () => {
292
- const input = 'test';
293
- const source = new ReadableStream({
294
- start(controller) {
295
- controller.enqueue(new TextEncoder().encode(''));
296
- controller.enqueue(new TextEncoder().encode(input));
297
- controller.close();
298
- }
299
- });
300
-
301
- const result = await MD5ReadableStream.hash(source);
302
-
303
- expect(result.digest).toBe(md5Core(input));
304
- expect(result.bytesProcessed).toBe(input.length);
305
- }, 10000);
306
- });
307
-
308
- if (typeof Blob !== 'undefined') {
309
- describe('hashBlob', () => {
310
- test('should hash a Blob', async () => {
311
- const input = 'blob hash test';
312
- const blob = new Blob([input]);
313
-
314
- const result = await hashBlob(blob);
315
-
316
- expect(result.digest).toBe(md5Core(input));
317
- expect(result.bytesProcessed).toBe(input.length);
318
- }, 10000);
319
-
320
- test('should hash an empty Blob', async () => {
321
- const blob = new Blob([]);
322
-
323
- const result = await hashBlob(blob);
324
-
325
- expect(result.digest).toBe(md5Core(''));
326
- expect(result.bytesProcessed).toBe(0);
327
- }, 10000);
328
- });
329
- }
330
-
331
- describe('integration', () => {
332
- test('should handle large data correctly', async () => {
333
- const chunkSize = 1024 * 1024; // 1MB
334
- const numChunks = 3;
335
- const totalBytes = chunkSize * numChunks;
336
-
337
- const source = new ReadableStream({
338
- start(controller) {
339
- const chunk = new TextEncoder().encode('a'.repeat(chunkSize));
340
- for (let i = 0; i < numChunks; i++) {
341
- controller.enqueue(chunk);
342
- }
343
- controller.close();
344
- }
345
- });
346
-
347
- const result = await MD5ReadableStream.hash(source);
348
-
349
- // We're just testing that it processes the data without crashing
350
- // The actual hash doesn't matter for this test
351
- expect(result.bytesProcessed).toBe(totalBytes);
352
- expect(result.digest.length).toBe(32); // MD5 is 32 hex chars
353
- }, 10000);
354
- });
355
- }
@@ -1,335 +0,0 @@
1
- /**
2
- * WHATWG Streams tests for browser environments
3
- * These tests verify the WHATWG Streams implementation works correctly
4
- */
5
-
6
- import { MD5ReadableStream, hashReadableStream, createMD5ReadableStream, hashFile, hashBlob } from '../../src/stream/whatwg-stream.js';
7
- import { md5Core } from '../../src/core/index.js';
8
-
9
- describe('MD5ReadableStream', () => {
10
- test('should compute MD5 hash for empty stream', async () => {
11
- const source = new ReadableStream({
12
- start(controller) {
13
- controller.close();
14
- }
15
- });
16
-
17
- const result = await MD5ReadableStream.hash(source);
18
-
19
- expect(result.digest).toBe(md5Core(''));
20
- expect(result.bytesProcessed).toBe(0);
21
- });
22
-
23
- test('should compute MD5 hash for simple string', async () => {
24
- const input = 'hello';
25
- const source = new ReadableStream({
26
- start(controller) {
27
- controller.enqueue(new TextEncoder().encode(input));
28
- controller.close();
29
- }
30
- });
31
-
32
- const result = await MD5ReadableStream.hash(source);
33
-
34
- expect(result.digest).toBe(md5Core(input));
35
- expect(result.bytesProcessed).toBe(input.length);
36
- });
37
-
38
- test('should compute MD5 hash for longer string', async () => {
39
- const input = 'a'.repeat(1000);
40
- const source = new ReadableStream({
41
- start(controller) {
42
- controller.enqueue(new TextEncoder().encode(input));
43
- controller.close();
44
- }
45
- });
46
-
47
- const result = await MD5ReadableStream.hash(source);
48
-
49
- expect(result.digest).toBe(md5Core(input));
50
- expect(result.bytesProcessed).toBe(input.length);
51
- });
52
-
53
- test('should process chunked data correctly', async () => {
54
- const input = 'hello world';
55
- const source = new ReadableStream({
56
- start(controller) {
57
- controller.enqueue(new TextEncoder().encode('hello '));
58
- controller.enqueue(new TextEncoder().encode('world'));
59
- controller.close();
60
- }
61
- });
62
-
63
- const result = await MD5ReadableStream.hash(source);
64
-
65
- expect(result.digest).toBe(md5Core(input));
66
- expect(result.bytesProcessed).toBe(input.length);
67
- });
68
-
69
- test('should handle multiple chunks of varying sizes', async () => {
70
- const input = 'This is a test string with multiple chunks';
71
- const chunks = ['This ', 'is a', ' test', ' string', ' with', ' multi', 'ple c', 'hunks'];
72
-
73
- const source = new ReadableStream({
74
- start(controller) {
75
- chunks.forEach(chunk => controller.enqueue(new TextEncoder().encode(chunk)));
76
- controller.close();
77
- }
78
- });
79
-
80
- const result = await MD5ReadableStream.hash(source);
81
-
82
- expect(result.digest).toBe(md5Core(input));
83
- expect(result.bytesProcessed).toBe(input.length);
84
- });
85
-
86
- test('should handle data that exactly fills 64-byte blocks', async () => {
87
- const input = 'a'.repeat(64);
88
- const source = new ReadableStream({
89
- start(controller) {
90
- controller.enqueue(new TextEncoder().encode(input));
91
- controller.close();
92
- }
93
- });
94
-
95
- const result = await MD5ReadableStream.hash(source);
96
-
97
- expect(result.digest).toBe(md5Core(input));
98
- expect(result.bytesProcessed).toBe(input.length);
99
- });
100
-
101
- test('should handle data that is multiple of 64 bytes', async () => {
102
- const input = 'a'.repeat(128);
103
- const source = new ReadableStream({
104
- start(controller) {
105
- controller.enqueue(new TextEncoder().encode(input));
106
- controller.close();
107
- }
108
- });
109
-
110
- const result = await MD5ReadableStream.hash(source);
111
-
112
- expect(result.digest).toBe(md5Core(input));
113
- expect(result.bytesProcessed).toBe(input.length);
114
- });
115
-
116
- test('should handle special characters', async () => {
117
- const input = '!@#$%^&*()_+-=[]{}|;:,.<>?';
118
- const source = new ReadableStream({
119
- start(controller) {
120
- controller.enqueue(new TextEncoder().encode(input));
121
- controller.close();
122
- }
123
- });
124
-
125
- const result = await MD5ReadableStream.hash(source);
126
-
127
- expect(result.digest).toBe(md5Core(input));
128
- expect(result.bytesProcessed).toBe(input.length);
129
- });
130
-
131
- test('should emit bytesProcessed correctly', async () => {
132
- const totalBytes = 256;
133
- const chunkSize = 64;
134
-
135
- const source = new ReadableStream({
136
- start(controller) {
137
- const chunk = new TextEncoder().encode('a'.repeat(chunkSize));
138
- for (let i = 0; i < 4; i++) {
139
- controller.enqueue(chunk);
140
- }
141
- controller.close();
142
- }
143
- });
144
-
145
- const result = await MD5ReadableStream.hash(source);
146
-
147
- expect(result.bytesProcessed).toBe(totalBytes);
148
- expect(result.digest.length).toBe(32);
149
- });
150
-
151
- test('should support factory function createMD5ReadableStream', async () => {
152
- const input = 'factory test';
153
- const source = new ReadableStream({
154
- start(controller) {
155
- controller.enqueue(new TextEncoder().encode(input));
156
- controller.close();
157
- }
158
- });
159
-
160
- const stream = createMD5ReadableStream(source);
161
- const result = await stream.getResult();
162
-
163
- expect(result.digest).toBe(md5Core(input));
164
- expect(result.bytesProcessed).toBe(input.length);
165
- });
166
-
167
- test('should support custom add32 function', async () => {
168
- const input = 'custom add32 test';
169
- const source = new ReadableStream({
170
- start(controller) {
171
- controller.enqueue(new TextEncoder().encode(input));
172
- controller.close();
173
- }
174
- });
175
-
176
- const customAdd32 = (x: number, y: number) => (x + y) & 0xffffffff;
177
- const result = await MD5ReadableStream.hash(source, { add32: customAdd32 });
178
-
179
- expect(result.digest).toBe(md5Core(input));
180
- expect(result.bytesProcessed).toBe(input.length);
181
- });
182
-
183
- test('should handle sequential processing', async () => {
184
- const parts = ['Hello, ', 'World!', ' This is ', 'MD5 streaming.'];
185
- const full = parts.join('');
186
-
187
- const source = new ReadableStream({
188
- start(controller) {
189
- parts.forEach(part => controller.enqueue(new TextEncoder().encode(part)));
190
- controller.close();
191
- }
192
- });
193
-
194
- const result = await MD5ReadableStream.hash(source);
195
-
196
- expect(result.digest).toBe(md5Core(full));
197
- expect(result.bytesProcessed).toBe(full.length);
198
- });
199
-
200
- test('should handle single byte chunks', async () => {
201
- const input = 'a';
202
- const source = new ReadableStream({
203
- start(controller) {
204
- controller.enqueue(new TextEncoder().encode(input));
205
- controller.close();
206
- }
207
- });
208
-
209
- const result = await MD5ReadableStream.hash(source);
210
-
211
- expect(result.digest).toBe(md5Core(input));
212
- expect(result.bytesProcessed).toBe(input.length);
213
- });
214
-
215
- test('should emit valid hex digest', async () => {
216
- const source = new ReadableStream({
217
- start(controller) {
218
- controller.enqueue(new TextEncoder().encode('test'));
219
- controller.close();
220
- }
221
- });
222
-
223
- const result = await MD5ReadableStream.hash(source);
224
-
225
- // MD5 digest should be 32 hex characters
226
- expect(result.digest).toMatch(/^[0-9a-f]{32}$/);
227
- expect(result.digest.length).toBe(32);
228
- });
229
-
230
- test('should get current state during processing', async () => {
231
- const source = new ReadableStream({
232
- start(controller) {
233
- controller.enqueue(new TextEncoder().encode('test'));
234
- controller.close();
235
- }
236
- });
237
-
238
- const stream = new MD5ReadableStream(source);
239
-
240
- // Check initial state before reading
241
- const initialState = stream.getCurrentState();
242
- expect(initialState.state).toHaveLength(4);
243
- expect(initialState.bytesProcessed).toBe(0);
244
-
245
- // Read some data
246
- const reader = stream.getReader();
247
- await reader.read();
248
-
249
- // Check state after reading
250
- const afterDataState = stream.getCurrentState();
251
- expect(afterDataState.bytesProcessed).toBe(4);
252
-
253
- // Check bytes processed getter
254
- expect(stream.getBytesProcessed()).toBe(4);
255
- });
256
-
257
- test('should handle empty chunks', async () => {
258
- const input = 'test';
259
- const source = new ReadableStream({
260
- start(controller) {
261
- controller.enqueue(new TextEncoder().encode(''));
262
- controller.enqueue(new TextEncoder().encode(input));
263
- controller.close();
264
- }
265
- });
266
-
267
- const result = await MD5ReadableStream.hash(source);
268
-
269
- expect(result.digest).toBe(md5Core(input));
270
- expect(result.bytesProcessed).toBe(input.length);
271
- });
272
- });
273
-
274
- describe('hashReadableStream', () => {
275
- test('should hash a ReadableStream', async () => {
276
- const input = 'hash readable stream test';
277
- const source = new ReadableStream({
278
- start(controller) {
279
- controller.enqueue(new TextEncoder().encode(input));
280
- controller.close();
281
- }
282
- });
283
-
284
- const result = await hashReadableStream(source);
285
-
286
- expect(result.digest).toBe(md5Core(input));
287
- expect(result.bytesProcessed).toBe(input.length);
288
- });
289
- });
290
-
291
- describe('hashBlob', () => {
292
- test('should hash a Blob', async () => {
293
- const input = 'blob hash test';
294
- const blob = new Blob([input]);
295
-
296
- const result = await hashBlob(blob);
297
-
298
- expect(result.digest).toBe(md5Core(input));
299
- expect(result.bytesProcessed).toBe(input.length);
300
- });
301
-
302
- test('should hash an empty Blob', async () => {
303
- const blob = new Blob([]);
304
-
305
- const result = await hashBlob(blob);
306
-
307
- expect(result.digest).toBe(md5Core(''));
308
- expect(result.bytesProcessed).toBe(0);
309
- });
310
- });
311
-
312
- describe('integration', () => {
313
- test('should handle large data correctly', async () => {
314
- const chunkSize = 1024 * 1024; // 1MB
315
- const numChunks = 3;
316
- const totalBytes = chunkSize * numChunks;
317
-
318
- const source = new ReadableStream({
319
- start(controller) {
320
- const chunk = new TextEncoder().encode('a'.repeat(chunkSize));
321
- for (let i = 0; i < numChunks; i++) {
322
- controller.enqueue(chunk);
323
- }
324
- controller.close();
325
- }
326
- });
327
-
328
- const result = await MD5ReadableStream.hash(source);
329
-
330
- // We're just testing that it processes the data without crashing
331
- // The actual hash doesn't matter for this test
332
- expect(result.bytesProcessed).toBe(totalBytes);
333
- expect(result.digest.length).toBe(32); // MD5 is 32 hex chars
334
- });
335
- });