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.
- package/README.md +38 -24
- package/dist/adapters/ie11.cjs +1 -2
- package/dist/adapters/ie11.js +1 -2
- package/dist/adapters/node.cjs +1 -2
- package/dist/adapters/node.js +1 -2
- package/dist/adapters/webcrypto.cjs +1 -2
- package/dist/adapters/webcrypto.js +1 -2
- package/dist/index.cjs +1 -2
- package/dist/index.d.ts +149 -5
- package/dist/index.js +3 -2
- package/dist/md5.cjs +1 -0
- package/dist/md5.d.ts +20 -0
- package/dist/md5.js +1 -0
- package/dist/stream/md5-stream.cjs +1 -2
- package/dist/stream/md5-stream.js +1 -2
- package/dist/stream/whatwg-stream.cjs +1 -2
- package/dist/stream/whatwg-stream.js +1 -2
- package/dist/utils/detect.cjs +1 -2
- package/dist/utils/detect.js +3 -2
- package/package.json +10 -15
- package/pure-md5-0.2.1.tgz +0 -0
- package/test-tree-shake.mjs +12 -0
- package/.aliases +0 -19
- package/.bash_profile +0 -12
- package/.bash_prompt +0 -56
- package/.changeset/README.md +0 -32
- package/.changeset/config.json +0 -16
- package/.continue/mcpServers/new-mcp-server.yaml +0 -10
- package/.continue/rules +0 -29
- package/.github/ISSUE_TEMPLATE/bug_report.md +0 -35
- package/.github/ISSUE_TEMPLATE/documentation.md +0 -20
- package/.github/ISSUE_TEMPLATE/feature_request.md +0 -20
- package/.github/PULL_REQUEST_TEMPLATE.md +0 -35
- package/.github/workflows/npm-publish.yml +0 -33
- package/.github/workflows/release.yml +0 -42
- package/CHANGELOG.md +0 -9
- package/CONTRIBUTING.md +0 -203
- package/MIGRATION_GUIDE_STREAMS.md +0 -374
- package/STREAM_API.md +0 -582
- package/STREAM_BENCHMARKS.md +0 -232
- package/STREAM_EXAMPLES.md +0 -669
- package/STREAM_OPTIMIZATION_REPORT.md +0 -136
- package/STREAM_TROUBLESHOOTING.md +0 -537
- package/WEB_CRYPTO_TESTS_SUMMARY.md +0 -140
- package/WHATWG_STREAMS.md +0 -191
- package/__tests__/adapters/node-crypto.test.ts +0 -167
- package/__tests__/adapters/web-crypto-node.test.ts +0 -73
- package/__tests__/adapters/web-crypto.test.ts +0 -195
- package/__tests__/add32.test.ts +0 -33
- package/__tests__/fallback.test.ts +0 -345
- package/__tests__/hex.test.ts +0 -38
- package/__tests__/hex_chr.test.ts +0 -20
- package/__tests__/index.test.ts +0 -87
- package/__tests__/integration/fixtures/test-file.txt +0 -1
- package/__tests__/integration/md5-stream-file.test.ts +0 -293
- package/__tests__/integration/node-crypto-file.test.ts +0 -86
- package/__tests__/integration/web-crypto.test.ts +0 -38
- package/__tests__/md51.test.ts +0 -73
- package/__tests__/md5block.test.ts +0 -61
- package/__tests__/md5cycle.test.ts +0 -48
- package/__tests__/round-functions.test.ts +0 -87
- package/__tests__/stream/fs-utils.test.ts +0 -209
- package/__tests__/stream/md5-stream-edge-cases.test.ts +0 -461
- package/__tests__/stream/md5-stream.test.ts +0 -418
- package/__tests__/stream/whatwg-stream.test.ts +0 -355
- package/__tests__/stream/whatwg-stream.test.ts.bak2 +0 -335
- package/benchmarks/md5-stream.bench.ts +0 -212
- package/benchmarks/whatwg-stream.bench.ts +0 -180
- package/dist/adapters/ie11.cjs.map +0 -1
- package/dist/adapters/ie11.js.map +0 -1
- package/dist/adapters/node.cjs.map +0 -1
- package/dist/adapters/node.js.map +0 -1
- package/dist/adapters/webcrypto.cjs.map +0 -1
- package/dist/adapters/webcrypto.js.map +0 -1
- package/dist/chunk-2YXXFGBV.js +0 -2
- package/dist/chunk-2YXXFGBV.js.map +0 -1
- package/dist/chunk-4KSCMS4Q.js +0 -2
- package/dist/chunk-4KSCMS4Q.js.map +0 -1
- package/dist/chunk-6P2QV5SR.js +0 -4
- package/dist/chunk-6P2QV5SR.js.map +0 -1
- package/dist/chunk-G5WHEAIQ.js +0 -2
- package/dist/chunk-G5WHEAIQ.js.map +0 -1
- package/dist/chunk-H2K353LR.js +0 -2
- package/dist/chunk-H2K353LR.js.map +0 -1
- package/dist/chunk-JKVD5LHZ.js +0 -2
- package/dist/chunk-JKVD5LHZ.js.map +0 -1
- package/dist/chunk-NWQ4N5RX.js +0 -2
- package/dist/chunk-NWQ4N5RX.js.map +0 -1
- package/dist/chunk-PHZ7FTYF.js +0 -2
- package/dist/chunk-PHZ7FTYF.js.map +0 -1
- package/dist/chunk-PNZTVQA7.js +0 -2
- package/dist/chunk-PNZTVQA7.js.map +0 -1
- package/dist/chunk-R4JB5MBR.js +0 -2
- package/dist/chunk-R4JB5MBR.js.map +0 -1
- package/dist/chunk-VFOAY6XI.js +0 -2
- package/dist/chunk-VFOAY6XI.js.map +0 -1
- package/dist/chunk-XB5BQIEX.js +0 -2
- package/dist/chunk-XB5BQIEX.js.map +0 -1
- package/dist/core/index.cjs +0 -2
- package/dist/core/index.cjs.map +0 -1
- package/dist/core/index.d.cts +0 -19
- package/dist/core/index.d.ts +0 -19
- package/dist/core/index.js +0 -2
- package/dist/core/index.js.map +0 -1
- package/dist/index.cjs.map +0 -1
- package/dist/index.d.cts +0 -84
- package/dist/index.js.map +0 -1
- package/dist/stream/adapter.cjs +0 -2
- package/dist/stream/adapter.cjs.map +0 -1
- package/dist/stream/adapter.d.cts +0 -63
- package/dist/stream/adapter.d.ts +0 -63
- package/dist/stream/adapter.js +0 -2
- package/dist/stream/adapter.js.map +0 -1
- package/dist/stream/fs-utils.cjs +0 -2
- package/dist/stream/fs-utils.cjs.map +0 -1
- package/dist/stream/fs-utils.d.cts +0 -137
- package/dist/stream/fs-utils.d.ts +0 -137
- package/dist/stream/fs-utils.js +0 -2
- package/dist/stream/fs-utils.js.map +0 -1
- package/dist/stream/index.cjs +0 -2
- package/dist/stream/index.cjs.map +0 -1
- package/dist/stream/index.d.cts +0 -4
- package/dist/stream/index.d.ts +0 -4
- package/dist/stream/index.js +0 -2
- package/dist/stream/index.js.map +0 -1
- package/dist/stream/light/index.cjs +0 -2
- package/dist/stream/light/index.cjs.map +0 -1
- package/dist/stream/light/index.d.cts +0 -4
- package/dist/stream/light/index.d.ts +0 -4
- package/dist/stream/light/index.js +0 -2
- package/dist/stream/light/index.js.map +0 -1
- package/dist/stream/md5-stream.cjs.map +0 -1
- package/dist/stream/md5-stream.js.map +0 -1
- package/dist/stream/whatwg-stream.cjs.map +0 -1
- package/dist/stream/whatwg-stream.js.map +0 -1
- package/dist/types-edGoGJ5V.d.cts +0 -42
- package/dist/types-edGoGJ5V.d.ts +0 -42
- package/dist/utils/detect.cjs.map +0 -1
- package/dist/utils/detect.js.map +0 -1
- package/planning/03-optimization-size-tree-shaking/01-es-modules-tree-shaking.md +0 -152
- package/planning/03-optimization-size-tree-shaking/02-consolidate-modules.md +0 -65
- package/planning/03-optimization-size-tree-shaking/03-remove-duplicate-add32.md +0 -93
- package/planning/03-optimization-size-tree-shaking/04-remove-runtime-check.md +0 -102
- package/planning/03-optimization-size-tree-shaking/05-optimize-loops-performance.md +0 -107
- package/planning/03-optimization-size-tree-shaking/06-tsup-formats-configuration.md +0 -227
- package/planning/03-optimization-size-tree-shaking/07-multiple-build-formats.md +0 -228
- package/planning/03-optimization-size-tree-shaking/08-benchmarks-metrics.md +0 -34
- package/planning/03-optimization-size-tree-shaking/MIGRATION_GUIDE.md +0 -260
- package/planning/03-optimization-size-tree-shaking/README.md +0 -173
- package/planning/03-optimization-size-tree-shaking/SUMMARY.md +0 -168
- package/planning/04-adapter-backend/03-backend-web-crypto.md +0 -149
- package/planning/04-adapter-backend/04-backend-node-crypto.md +0 -181
- package/planning/04-adapter-backend/05-backend-pure-js.md +0 -174
- package/planning/04-adapter-backend/06-backend-ie11.md +0 -158
- package/planning/04-adapter-backend/07-detection-environment.md +0 -232
- package/planning/04-adapter-backend/08-detection-backend.md +0 -210
- package/planning/04-adapter-backend/09-adapter-unified.md +0 -255
- package/planning/04-adapter-backend/10-fallback-mechanism.md +0 -333
- package/planning/04-adapter-backend/11-tests-backend-web-crypto.md +0 -191
- package/planning/04-adapter-backend/12-tests-backend-node-crypto.md +0 -222
- package/planning/04-adapter-backend/README.md +0 -45
- package/planning/05-documentation-publishing/01-README-optimization.md +0 -105
- package/planning/05-documentation-publishing/02-VitePress-site-evaluation.md +0 -136
- package/planning/05-documentation-publishing/03-Changeset-setup.md +0 -192
- package/planning/05-documentation-publishing/04-GitHub-templates.md +0 -252
- package/planning/05-documentation-publishing/README.md +0 -22
- package/planning/05-documentation-publishing/STATUS.md +0 -222
- package/planning/prd.md +0 -405
- package/planning/streams/01-create-md5stream-class.md +0 -69
- package/planning/streams/02-create-factory-api.md +0 -65
- package/planning/streams/03-fs-integration.md +0 -37
- package/planning/streams/04-whatwg-streams-support.md +0 -37
- package/planning/streams/05-audit-optimization.md +0 -121
- package/planning/streams/06-comprehensive-tests-docs.md +0 -137
- package/planning/streams/07-architecture-integration.md +0 -38
- package/planning/streams/README.md +0 -98
- package/tsup.config.ts +0 -24
|
@@ -1,195 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Tests for Web Crypto Backend
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import { WebCryptoBackend } from '../../src/adapters/webcrypto';
|
|
6
|
-
|
|
7
|
-
describe('WebCryptoBackend', () => {
|
|
8
|
-
let backend: WebCryptoBackend;
|
|
9
|
-
|
|
10
|
-
beforeAll(async () => {
|
|
11
|
-
const available = WebCryptoBackend.isAvailable();
|
|
12
|
-
if (!available) {
|
|
13
|
-
console.log('Web Crypto API not available, skipping tests');
|
|
14
|
-
} else {
|
|
15
|
-
backend = new WebCryptoBackend();
|
|
16
|
-
}
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
describe('Basic hashing', () => {
|
|
20
|
-
it('should hash string correctly', async () => {
|
|
21
|
-
if (!backend) {
|
|
22
|
-
console.log('Skipping test: Web Crypto API not available');
|
|
23
|
-
return;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
const result = await backend.hash('hello');
|
|
27
|
-
expect(result).toBe('5d41402abc4b2a76b9719d911017c592');
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
it('should hash empty string', async () => {
|
|
31
|
-
if (!backend) {
|
|
32
|
-
console.log('Skipping test: Web Crypto API not available');
|
|
33
|
-
return;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
const result = await backend.hash('');
|
|
37
|
-
expect(result).toBe('d41d8cd98f00b204e9800998ecf8427e');
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
it('should hash special characters', async () => {
|
|
41
|
-
if (!backend) {
|
|
42
|
-
console.log('Skipping test: Web Crypto API not available');
|
|
43
|
-
return;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
const result = await backend.hash('!@#$%^&*()');
|
|
47
|
-
expect(result).toBe('05b28d17a7b6e7024b6e5d8cc43a8bf7');
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
it('should hash unicode characters', async () => {
|
|
51
|
-
if (!backend) {
|
|
52
|
-
console.log('Skipping test: Web Crypto API not available');
|
|
53
|
-
return;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
const result = await backend.hash('Привет мир');
|
|
57
|
-
expect(result).toBe('5abca3326cf0cefc00efe7065b5e0cf6');
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
it('should hash long string', async () => {
|
|
61
|
-
if (!backend) {
|
|
62
|
-
console.log('Skipping test: Web Crypto API not available');
|
|
63
|
-
return;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
const longString = 'a'.repeat(10000);
|
|
67
|
-
const result = await backend.hash(longString);
|
|
68
|
-
expect(result.length).toBe(32);
|
|
69
|
-
});
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
describe('Binary data', () => {
|
|
73
|
-
it('should hash Uint8Array', async () => {
|
|
74
|
-
if (!backend) {
|
|
75
|
-
console.log('Skipping test: Web Crypto API not available');
|
|
76
|
-
return;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
const data = new Uint8Array([104, 101, 108, 108, 111]);
|
|
80
|
-
const result = await backend.hashBinary(data);
|
|
81
|
-
expect(result).toBe('5d41402abc4b2a76b9719d911017c592');
|
|
82
|
-
});
|
|
83
|
-
|
|
84
|
-
it('should hash ArrayBuffer', async () => {
|
|
85
|
-
if (!backend) {
|
|
86
|
-
console.log('Skipping test: Web Crypto API not available');
|
|
87
|
-
return;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
const data = new TextEncoder().encode('hello').buffer;
|
|
91
|
-
const result = await backend.hashBinary(data);
|
|
92
|
-
expect(result).toBe('5d41402abc4b2a76b9719d911017c592');
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
it('should hash empty Uint8Array', async () => {
|
|
96
|
-
if (!backend) {
|
|
97
|
-
console.log('Skipping test: Web Crypto API not available');
|
|
98
|
-
return;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
const data = new Uint8Array(0);
|
|
102
|
-
const result = await backend.hashBinary(data);
|
|
103
|
-
expect(result).toBe('d41d8cd98f00b204e9800998ecf8427e');
|
|
104
|
-
});
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
describe('Availability', () => {
|
|
108
|
-
it('should check Web Crypto API availability', async () => {
|
|
109
|
-
const available = WebCryptoBackend.isAvailable();
|
|
110
|
-
expect(typeof available).toBe('boolean');
|
|
111
|
-
});
|
|
112
|
-
});
|
|
113
|
-
|
|
114
|
-
describe('Performance', () => {
|
|
115
|
-
it('should hash 1MB data efficiently', async () => {
|
|
116
|
-
if (!backend) {
|
|
117
|
-
console.log('Skipping test: Web Crypto API not available');
|
|
118
|
-
return;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
const data = 'a'.repeat(1024 * 1024);
|
|
122
|
-
|
|
123
|
-
const start = performance.now();
|
|
124
|
-
const result = await backend.hash(data);
|
|
125
|
-
const duration = performance.now() - start;
|
|
126
|
-
|
|
127
|
-
expect(result.length).toBe(32);
|
|
128
|
-
expect(duration).toBeLessThan(1000);
|
|
129
|
-
});
|
|
130
|
-
});
|
|
131
|
-
|
|
132
|
-
describe('Consistency', () => {
|
|
133
|
-
it('should produce same hash for same input', async () => {
|
|
134
|
-
if (!backend) {
|
|
135
|
-
console.log('Skipping test: Web Crypto API not available');
|
|
136
|
-
return;
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
const input = 'test input';
|
|
140
|
-
const result1 = await backend.hash(input);
|
|
141
|
-
const result2 = await backend.hash(input);
|
|
142
|
-
expect(result1).toBe(result2);
|
|
143
|
-
});
|
|
144
|
-
|
|
145
|
-
it('should produce different hash for different inputs', async () => {
|
|
146
|
-
if (!backend) {
|
|
147
|
-
console.log('Skipping test: Web Crypto API not available');
|
|
148
|
-
return;
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
const result1 = await backend.hash('hello');
|
|
152
|
-
const result2 = await backend.hash('world');
|
|
153
|
-
expect(result1).not.toBe(result2);
|
|
154
|
-
});
|
|
155
|
-
});
|
|
156
|
-
|
|
157
|
-
describe('Interface compliance', () => {
|
|
158
|
-
it('should have correct name and version', async () => {
|
|
159
|
-
if (!backend) {
|
|
160
|
-
console.log('Skipping test: Web Crypto API not available');
|
|
161
|
-
return;
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
expect(backend.name).toBe('webcrypto');
|
|
165
|
-
expect(backend.version).toBe('1.0.0');
|
|
166
|
-
});
|
|
167
|
-
|
|
168
|
-
it('should have reset method', async () => {
|
|
169
|
-
if (!backend) {
|
|
170
|
-
console.log('Skipping test: Web Crypto API not available');
|
|
171
|
-
return;
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
expect(typeof backend.reset).toBe('function');
|
|
175
|
-
});
|
|
176
|
-
|
|
177
|
-
it('should throw error on update (no streaming)', async () => {
|
|
178
|
-
if (!backend) {
|
|
179
|
-
console.log('Skipping test: Web Crypto API not available');
|
|
180
|
-
return;
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
expect(() => backend.update('test')).toThrow('Web Crypto API does not support streaming updates');
|
|
184
|
-
});
|
|
185
|
-
|
|
186
|
-
it('should throw error on digest (no streaming)', async () => {
|
|
187
|
-
if (!backend) {
|
|
188
|
-
console.log('Skipping test: Web Crypto API not available');
|
|
189
|
-
return;
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
expect(() => backend.digest()).toThrow('Web Crypto API does not support streaming');
|
|
193
|
-
});
|
|
194
|
-
});
|
|
195
|
-
});
|
package/__tests__/add32.test.ts
DELETED
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
import add32 from '../src/add32';
|
|
2
|
-
|
|
3
|
-
describe('add32', () => {
|
|
4
|
-
test('should add two numbers and wrap around at 32 bits', () => {
|
|
5
|
-
// Test basic addition
|
|
6
|
-
expect(add32(1, 2)).toBe(3);
|
|
7
|
-
expect(add32(10, 20)).toBe(30);
|
|
8
|
-
expect(add32(100, 200)).toBe(300);
|
|
9
|
-
});
|
|
10
|
-
|
|
11
|
-
test('should handle large numbers correctly (32-bit wrap)', () => {
|
|
12
|
-
// 2^32 - 1 = 4294967295
|
|
13
|
-
expect(add32(4294967295, 1)).toBe(0); // Wrap around
|
|
14
|
-
expect(add32(4294967295, 2)).toBe(1);
|
|
15
|
-
expect(add32(4294967290, 10)).toBe(4); // Fixed: 4294967290 + 10 = 4294967300 mod 2^32 = 4
|
|
16
|
-
});
|
|
17
|
-
|
|
18
|
-
test("should handle negative numbers in two's complement", () => {
|
|
19
|
-
// In two's complement 32-bit, -1 = 4294967295
|
|
20
|
-
expect(add32(-1, 1)).toBe(0);
|
|
21
|
-
expect(add32(-10, 10)).toBe(0);
|
|
22
|
-
expect(add32(-100, 100)).toBe(0);
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
test('should maintain 32-bit integer behavior', () => {
|
|
26
|
-
// Test overflow behavior
|
|
27
|
-
const max32 = 4294967295;
|
|
28
|
-
expect(add32(max32, max32)).toBe(-2); // Fixed: (2^32 - 1) + (2^32 - 1) = 2^33 - 2 = 0x1FFFFFFFE → 0xFFFFFFFE = -2 in two's complement
|
|
29
|
-
|
|
30
|
-
// Test that results stay within 32-bit range
|
|
31
|
-
expect(add32(0xffffffff, 0xffffffff)).toBe(-2); // Same as above
|
|
32
|
-
});
|
|
33
|
-
});
|
|
@@ -1,345 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
FallbackManager,
|
|
3
|
-
robustHash,
|
|
4
|
-
metrics,
|
|
5
|
-
detector
|
|
6
|
-
} from '../src/utils/detect.js';
|
|
7
|
-
import { WebCryptoBackend } from '../src/adapters/webcrypto.js';
|
|
8
|
-
import { NodeCryptoBackend } from '../src/adapters/node.js';
|
|
9
|
-
import { IE11Backend } from '../src/adapters/ie11.js';
|
|
10
|
-
import { PureJSBackend } from '../src/adapters/pure-js.js';
|
|
11
|
-
|
|
12
|
-
describe('FallbackManager', () => {
|
|
13
|
-
let manager: FallbackManager;
|
|
14
|
-
|
|
15
|
-
beforeEach(() => {
|
|
16
|
-
manager = new FallbackManager();
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
describe('Constructor', () => {
|
|
20
|
-
it('should create with default fallback order', () => {
|
|
21
|
-
expect(manager).toBeDefined();
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
it('should create with custom fallback order', () => {
|
|
25
|
-
const customManager = new FallbackManager(['purejs', 'webcrypto']);
|
|
26
|
-
expect(customManager).toBeDefined();
|
|
27
|
-
});
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
describe('getAvailableBackends', () => {
|
|
31
|
-
it('should return available backends in priority order', async () => {
|
|
32
|
-
const available = await manager.getAvailableBackends();
|
|
33
|
-
expect(Array.isArray(available)).toBe(true);
|
|
34
|
-
expect(available.length).toBeGreaterThan(0);
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
it('should include purejs as fallback', async () => {
|
|
38
|
-
const available = await manager.getAvailableBackends();
|
|
39
|
-
expect(available).toContain('purejs');
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
it('should check nodecrypto availability', async () => {
|
|
43
|
-
const available = await manager.getAvailableBackends();
|
|
44
|
-
const hasNodeCrypto = available.includes('nodecrypto');
|
|
45
|
-
const nodeAvailable = NodeCryptoBackend.isAvailable();
|
|
46
|
-
expect(hasNodeCrypto).toBe(nodeAvailable);
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
xit('should check webcrypto availability', async () => {
|
|
50
|
-
const available = await manager.getAvailableBackends();
|
|
51
|
-
const hasWebCrypto = available.includes('webcrypto');
|
|
52
|
-
const webAvailable = WebCryptoBackend.isAvailable();
|
|
53
|
-
// Check consistency between available backends and isAvailable
|
|
54
|
-
expect(hasWebCrypto).toBe(webAvailable);
|
|
55
|
-
});
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
describe('getBestBackend', () => {
|
|
59
|
-
it('should return best available backend', async () => {
|
|
60
|
-
const best = await manager.getBestBackend();
|
|
61
|
-
expect(typeof best).toBe('string');
|
|
62
|
-
expect(['nodecrypto', 'webcrypto', 'ie11', 'purejs']).toContain(best);
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
it('should prioritize nodecrypto if available', async () => {
|
|
66
|
-
const available = await manager.getAvailableBackends();
|
|
67
|
-
const best = await manager.getBestBackend();
|
|
68
|
-
|
|
69
|
-
if (available.includes('nodecrypto')) {
|
|
70
|
-
expect(best).toBe('nodecrypto');
|
|
71
|
-
}
|
|
72
|
-
});
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
describe('execute', () => {
|
|
76
|
-
it('should execute operation with fallback and return success', async () => {
|
|
77
|
-
const result = await manager.execute(async (backend) =>
|
|
78
|
-
backend.hash('hello')
|
|
79
|
-
);
|
|
80
|
-
expect(result.success).toBe(true);
|
|
81
|
-
expect(result.backend).toBeDefined();
|
|
82
|
-
expect(result.data).toBe('5d41402abc4b2a76b9719d911017c592');
|
|
83
|
-
});
|
|
84
|
-
|
|
85
|
-
it('should fallback to available backend when first fails', async () => {
|
|
86
|
-
// Test that fallback works when first backend throws error
|
|
87
|
-
const failingManager = new FallbackManager(['nodecrypto', 'purejs']);
|
|
88
|
-
|
|
89
|
-
// Mock NodeCryptoBackend to throw error
|
|
90
|
-
const originalHash = NodeCryptoBackend.prototype.hash;
|
|
91
|
-
NodeCryptoBackend.prototype.hash = function () {
|
|
92
|
-
throw new Error('Node crypto not available');
|
|
93
|
-
};
|
|
94
|
-
|
|
95
|
-
try {
|
|
96
|
-
const result = await failingManager.execute(async (backend) =>
|
|
97
|
-
backend.hash('hello')
|
|
98
|
-
);
|
|
99
|
-
|
|
100
|
-
expect(result.success).toBe(true);
|
|
101
|
-
expect(result.backend).toBe('purejs');
|
|
102
|
-
} finally {
|
|
103
|
-
// Restore original
|
|
104
|
-
NodeCryptoBackend.prototype.hash = originalHash;
|
|
105
|
-
}
|
|
106
|
-
});
|
|
107
|
-
|
|
108
|
-
it('should handle backend that throws error', async () => {
|
|
109
|
-
const managerWithFailing = new FallbackManager(['purejs']);
|
|
110
|
-
|
|
111
|
-
const result = await managerWithFailing.execute(async () => {
|
|
112
|
-
throw new Error('Direct error');
|
|
113
|
-
});
|
|
114
|
-
|
|
115
|
-
expect(result.success).toBe(false);
|
|
116
|
-
expect(result.errors).toBeDefined();
|
|
117
|
-
});
|
|
118
|
-
});
|
|
119
|
-
|
|
120
|
-
describe('hash', () => {
|
|
121
|
-
it('should hash string with fallback', async () => {
|
|
122
|
-
const result = await manager.hash('hello');
|
|
123
|
-
expect(result.success).toBe(true);
|
|
124
|
-
expect(result.data).toBe('5d41402abc4b2a76b9719d911017c592');
|
|
125
|
-
});
|
|
126
|
-
|
|
127
|
-
it('should hash empty string', async () => {
|
|
128
|
-
const result = await manager.hash('');
|
|
129
|
-
expect(result.success).toBe(true);
|
|
130
|
-
expect(result.data).toBe('d41d8cd98f00b204e9800998ecf8427e');
|
|
131
|
-
});
|
|
132
|
-
|
|
133
|
-
it('should return correct backend name', async () => {
|
|
134
|
-
const result = await manager.hash('test');
|
|
135
|
-
expect(result.backend).toBeDefined();
|
|
136
|
-
expect(['nodecrypto', 'webcrypto', 'ie11', 'purejs']).toContain(
|
|
137
|
-
result.backend
|
|
138
|
-
);
|
|
139
|
-
});
|
|
140
|
-
});
|
|
141
|
-
|
|
142
|
-
describe('hashBinary', () => {
|
|
143
|
-
it('should hash binary data with fallback', async () => {
|
|
144
|
-
const data = new Uint8Array([104, 101, 108, 108, 111]); // "hello"
|
|
145
|
-
const result = await manager.hashBinary(data);
|
|
146
|
-
expect(result.success).toBe(true);
|
|
147
|
-
expect(result.data).toBe('5d41402abc4b2a76b9719d911017c592');
|
|
148
|
-
});
|
|
149
|
-
|
|
150
|
-
it('should hash ArrayBuffer', async () => {
|
|
151
|
-
const data = new TextEncoder().encode('hello').buffer;
|
|
152
|
-
const result = await manager.hashBinary(data);
|
|
153
|
-
expect(result.success).toBe(true);
|
|
154
|
-
});
|
|
155
|
-
});
|
|
156
|
-
|
|
157
|
-
describe('detector integration', () => {
|
|
158
|
-
it('should use detector for backend creation', async () => {
|
|
159
|
-
const backend = await detector.createBackendByName('purejs');
|
|
160
|
-
expect(backend).toBeInstanceOf(PureJSBackend);
|
|
161
|
-
});
|
|
162
|
-
|
|
163
|
-
it('should create different backend types', async () => {
|
|
164
|
-
const nodeBackend = await detector.createBackendByName('nodecrypto');
|
|
165
|
-
expect(nodeBackend).toBeInstanceOf(NodeCryptoBackend);
|
|
166
|
-
|
|
167
|
-
const webBackend = await detector.createBackendByName('webcrypto');
|
|
168
|
-
expect(webBackend).toBeInstanceOf(WebCryptoBackend);
|
|
169
|
-
|
|
170
|
-
const ie11Backend = await detector.createBackendByName('ie11');
|
|
171
|
-
expect(ie11Backend).toBeInstanceOf(IE11Backend);
|
|
172
|
-
|
|
173
|
-
const pureBackend = await detector.createBackendByName('purejs');
|
|
174
|
-
expect(pureBackend).toBeInstanceOf(PureJSBackend);
|
|
175
|
-
});
|
|
176
|
-
});
|
|
177
|
-
});
|
|
178
|
-
|
|
179
|
-
describe('robustHash function', () => {
|
|
180
|
-
beforeEach(() => {
|
|
181
|
-
metrics.reset();
|
|
182
|
-
});
|
|
183
|
-
|
|
184
|
-
it('should hash with default fallback', async () => {
|
|
185
|
-
const result = await robustHash('hello');
|
|
186
|
-
expect(result).toBe('5d41402abc4b2a76b9719d911017c592');
|
|
187
|
-
});
|
|
188
|
-
|
|
189
|
-
it('should hash empty string', async () => {
|
|
190
|
-
const result = await robustHash('');
|
|
191
|
-
expect(result).toBe('d41d8cd98f00b204e9800998ecf8427e');
|
|
192
|
-
});
|
|
193
|
-
|
|
194
|
-
it('should use specific backend when forceBackend is set', async () => {
|
|
195
|
-
const result = await robustHash('hello', { forceBackend: 'purejs' });
|
|
196
|
-
expect(result).toBe('5d41402abc4b2a76b9719d911017c592');
|
|
197
|
-
});
|
|
198
|
-
|
|
199
|
-
it('should skip fallback when fallback: false', async () => {
|
|
200
|
-
const result = await robustHash('hello', { fallback: false });
|
|
201
|
-
expect(result).toBe('5d41402abc4b2a76b9719d911017c592');
|
|
202
|
-
});
|
|
203
|
-
|
|
204
|
-
it('should support reportFallback option', async () => {
|
|
205
|
-
const consoleSpy = jest.spyOn(console, 'info').mockImplementation();
|
|
206
|
-
|
|
207
|
-
const result = await robustHash('hello', {
|
|
208
|
-
fallback: true,
|
|
209
|
-
reportFallback: true
|
|
210
|
-
});
|
|
211
|
-
|
|
212
|
-
expect(result).toBe('5d41402abc4b2a76b9719d911017c592');
|
|
213
|
-
consoleSpy.mockRestore();
|
|
214
|
-
});
|
|
215
|
-
|
|
216
|
-
it('should handle multiple backends in fallback chain', async () => {
|
|
217
|
-
// Test with various inputs
|
|
218
|
-
const testCases = [
|
|
219
|
-
'hello',
|
|
220
|
-
'',
|
|
221
|
-
'The quick brown fox jumps over the lazy dog',
|
|
222
|
-
'a'.repeat(1000)
|
|
223
|
-
];
|
|
224
|
-
|
|
225
|
-
for (const input of testCases) {
|
|
226
|
-
const result = await robustHash(input);
|
|
227
|
-
expect(typeof result).toBe('string');
|
|
228
|
-
expect(result.length).toBe(32);
|
|
229
|
-
expect(result).toMatch(/^[0-9a-f]+$/);
|
|
230
|
-
}
|
|
231
|
-
});
|
|
232
|
-
});
|
|
233
|
-
|
|
234
|
-
describe('MetricsCollector', () => {
|
|
235
|
-
beforeEach(() => {
|
|
236
|
-
metrics.reset();
|
|
237
|
-
});
|
|
238
|
-
|
|
239
|
-
describe('recordSuccess', () => {
|
|
240
|
-
it('should increment success count for nodecrypto', () => {
|
|
241
|
-
metrics.recordSuccess('nodecrypto');
|
|
242
|
-
expect(metrics.getMetrics().nodecrypto.success).toBe(1);
|
|
243
|
-
});
|
|
244
|
-
|
|
245
|
-
it('should increment success count for webcrypto', () => {
|
|
246
|
-
metrics.recordSuccess('webcrypto');
|
|
247
|
-
expect(metrics.getMetrics().webcrypto.success).toBe(1);
|
|
248
|
-
});
|
|
249
|
-
|
|
250
|
-
it('should increment success count for purejs', () => {
|
|
251
|
-
metrics.recordSuccess('purejs');
|
|
252
|
-
expect(metrics.getMetrics().purejs.success).toBe(1);
|
|
253
|
-
});
|
|
254
|
-
|
|
255
|
-
it('should not fail for unknown backend', () => {
|
|
256
|
-
expect(() => metrics.recordSuccess('unknown')).not.toThrow();
|
|
257
|
-
});
|
|
258
|
-
});
|
|
259
|
-
|
|
260
|
-
describe('recordFail', () => {
|
|
261
|
-
it('should increment fail count for nodecrypto', () => {
|
|
262
|
-
metrics.recordFail('nodecrypto');
|
|
263
|
-
expect(metrics.getMetrics().nodecrypto.fail).toBe(1);
|
|
264
|
-
});
|
|
265
|
-
|
|
266
|
-
it('should increment fail count for webcrypto', () => {
|
|
267
|
-
metrics.recordFail('webcrypto');
|
|
268
|
-
expect(metrics.getMetrics().webcrypto.fail).toBe(1);
|
|
269
|
-
});
|
|
270
|
-
|
|
271
|
-
it('should not fail for unknown backend', () => {
|
|
272
|
-
expect(() => metrics.recordFail('unknown')).not.toThrow();
|
|
273
|
-
});
|
|
274
|
-
});
|
|
275
|
-
|
|
276
|
-
describe('getMetrics', () => {
|
|
277
|
-
it('should return all backends metrics', () => {
|
|
278
|
-
const allMetrics = metrics.getMetrics();
|
|
279
|
-
|
|
280
|
-
expect(allMetrics.nodecrypto).toBeDefined();
|
|
281
|
-
expect(allMetrics.webcrypto).toBeDefined();
|
|
282
|
-
expect(allMetrics.ie11).toBeDefined();
|
|
283
|
-
expect(allMetrics.purejs).toBeDefined();
|
|
284
|
-
});
|
|
285
|
-
|
|
286
|
-
it('should return correct structure', () => {
|
|
287
|
-
const metricsObj = metrics.getMetrics();
|
|
288
|
-
|
|
289
|
-
expect(metricsObj.nodecrypto).toEqual({ success: 0, fail: 0 });
|
|
290
|
-
expect(metricsObj.webcrypto).toEqual({ success: 0, fail: 0 });
|
|
291
|
-
expect(metricsObj.ie11).toEqual({ success: 0, fail: 0 });
|
|
292
|
-
expect(metricsObj.purejs).toEqual({ success: 0, fail: 0 });
|
|
293
|
-
});
|
|
294
|
-
});
|
|
295
|
-
|
|
296
|
-
describe('getSummary', () => {
|
|
297
|
-
it('should return summary string', () => {
|
|
298
|
-
metrics.recordSuccess('nodecrypto');
|
|
299
|
-
metrics.recordFail('webcrypto');
|
|
300
|
-
|
|
301
|
-
const summary = metrics.getSummary();
|
|
302
|
-
|
|
303
|
-
expect(typeof summary).toBe('string');
|
|
304
|
-
expect(summary).toContain('Total operations:');
|
|
305
|
-
// Check that it contains some backend stats
|
|
306
|
-
expect(summary).toContain('success');
|
|
307
|
-
expect(summary).toContain('fail');
|
|
308
|
-
});
|
|
309
|
-
|
|
310
|
-
it('should show correct totals', () => {
|
|
311
|
-
metrics.recordSuccess('nodecrypto');
|
|
312
|
-
metrics.recordSuccess('nodecrypto');
|
|
313
|
-
metrics.recordFail('webcrypto');
|
|
314
|
-
|
|
315
|
-
const summary = metrics.getSummary();
|
|
316
|
-
|
|
317
|
-
expect(summary).toContain('Total operations: 3');
|
|
318
|
-
});
|
|
319
|
-
});
|
|
320
|
-
|
|
321
|
-
describe('reset', () => {
|
|
322
|
-
it('should reset all metrics', () => {
|
|
323
|
-
metrics.recordSuccess('nodecrypto');
|
|
324
|
-
metrics.recordFail('webcrypto');
|
|
325
|
-
|
|
326
|
-
metrics.reset();
|
|
327
|
-
|
|
328
|
-
const afterReset = metrics.getMetrics();
|
|
329
|
-
expect(afterReset.nodecrypto).toEqual({ success: 0, fail: 0 });
|
|
330
|
-
expect(afterReset.webcrypto).toEqual({ success: 0, fail: 0 });
|
|
331
|
-
});
|
|
332
|
-
});
|
|
333
|
-
|
|
334
|
-
describe('Integration with FallbackManager', () => {
|
|
335
|
-
it('should track operations through fallback', () => {
|
|
336
|
-
// Since FallbackManager doesn't automatically record metrics,
|
|
337
|
-
// we test that metrics can be manually recorded
|
|
338
|
-
metrics.reset();
|
|
339
|
-
metrics.recordSuccess('purejs');
|
|
340
|
-
|
|
341
|
-
const currentMetrics = metrics.getMetrics();
|
|
342
|
-
expect(currentMetrics.purejs.success).toBe(1);
|
|
343
|
-
});
|
|
344
|
-
});
|
|
345
|
-
});
|
package/__tests__/hex.test.ts
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import hex from '../src/hex';
|
|
2
|
-
|
|
3
|
-
describe('hex', () => {
|
|
4
|
-
test('should convert number array to hex string', () => {
|
|
5
|
-
const input = [0x12345678, 0x9abcdef0];
|
|
6
|
-
const expected = '78563412f0debc9a';
|
|
7
|
-
expect(hex(input)).toBe(expected);
|
|
8
|
-
});
|
|
9
|
-
|
|
10
|
-
test('should handle empty array', () => {
|
|
11
|
-
expect(hex([])).toBe('');
|
|
12
|
-
});
|
|
13
|
-
|
|
14
|
-
test('should handle single number', () => {
|
|
15
|
-
expect(hex([0x00000000])).toBe('00000000');
|
|
16
|
-
expect(hex([0xffffffff])).toBe('ffffffff');
|
|
17
|
-
expect(hex([0x01234567])).toBe('67452301');
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
test('should convert large numbers correctly', () => {
|
|
21
|
-
const input = [0xdeadbeef, 0xcafebabe, 0xfaceb00c];
|
|
22
|
-
const expected = 'efbeaddebebafeca0cb0cefa';
|
|
23
|
-
expect(hex(input)).toBe(expected);
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
test('should handle boundary values', () => {
|
|
27
|
-
// Minimum
|
|
28
|
-
expect(hex([0])).toBe('00000000');
|
|
29
|
-
|
|
30
|
-
// Maximum 32-bit
|
|
31
|
-
expect(hex([4294967295])).toBe('ffffffff');
|
|
32
|
-
|
|
33
|
-
// Test with 4 numbers (typical MD5 output)
|
|
34
|
-
expect(hex([1732584193, -271733879, -1732584194, 271733878])).toBe(
|
|
35
|
-
'0123456789abcdeffedcba9876543210'
|
|
36
|
-
);
|
|
37
|
-
});
|
|
38
|
-
});
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import hex_chr from '../src/hex_chr';
|
|
2
|
-
|
|
3
|
-
describe('hex_chr', () => {
|
|
4
|
-
test('should contain all hex digits', () => {
|
|
5
|
-
expect(hex_chr).toBeInstanceOf(Array);
|
|
6
|
-
expect(hex_chr.length).toBe(16);
|
|
7
|
-
|
|
8
|
-
// Check all hex digits
|
|
9
|
-
const expected = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'];
|
|
10
|
-
expect(hex_chr).toEqual(expected);
|
|
11
|
-
});
|
|
12
|
-
|
|
13
|
-
test('should have correct character at each position', () => {
|
|
14
|
-
// Spot check some positions
|
|
15
|
-
expect(hex_chr[0]).toBe('0');
|
|
16
|
-
expect(hex_chr[9]).toBe('9');
|
|
17
|
-
expect(hex_chr[10]).toBe('a');
|
|
18
|
-
expect(hex_chr[15]).toBe('f');
|
|
19
|
-
});
|
|
20
|
-
});
|