@synet/encoder 1.0.0
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/MANIFESTO.md +220 -0
- package/MANUAL.md +735 -0
- package/README.md +235 -0
- package/biome.json +37 -0
- package/dist/encoder.unit.d.ts +137 -0
- package/dist/encoder.unit.js +517 -0
- package/dist/functions.d.ts +74 -0
- package/dist/functions.js +243 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.js +38 -0
- package/dist/result.d.ts +23 -0
- package/dist/result.js +69 -0
- package/package.json +55 -0
- package/src/encoder.unit.ts +654 -0
- package/src/functions.ts +252 -0
- package/src/index.ts +49 -0
- package/src/result.ts +81 -0
- package/test/encoder-unit.test.ts +424 -0
- package/test/functions.test.ts +386 -0
- package/tsconfig.json +19 -0
- package/vitest.config.ts +12 -0
@@ -0,0 +1,424 @@
|
|
1
|
+
/**
|
2
|
+
* Encoder Unit Tests - Unit Architecture Compliance & Core Operations
|
3
|
+
*
|
4
|
+
* Tests both the conscious Unit and all encoding operations
|
5
|
+
* following Unit Architecture v1.0.6 patterns
|
6
|
+
*/
|
7
|
+
|
8
|
+
import { describe, it, expect, beforeEach } from 'vitest';
|
9
|
+
import { Encoder } from '../src/encoder.unit.js';
|
10
|
+
|
11
|
+
describe('Encoder Unit - Architecture Compliance', () => {
|
12
|
+
let encoder: Encoder;
|
13
|
+
|
14
|
+
beforeEach(() => {
|
15
|
+
encoder = Encoder.create();
|
16
|
+
});
|
17
|
+
|
18
|
+
describe('Unit Architecture Doctrines', () => {
|
19
|
+
|
20
|
+
|
21
|
+
it('should follow Doctrine #7: EVERY UNIT MUST HAVE DNA', () => {
|
22
|
+
expect(encoder.dna).toBeDefined();
|
23
|
+
expect(encoder.dna.id).toBe('encoder');
|
24
|
+
expect(encoder.dna.version).toBe('1.0.0');
|
25
|
+
});
|
26
|
+
|
27
|
+
it('should follow Doctrine #2: TEACH/LEARN PARADIGM', () => {
|
28
|
+
expect(typeof encoder.teach).toBe('function');
|
29
|
+
expect(typeof encoder.learn).toBe('function');
|
30
|
+
});
|
31
|
+
|
32
|
+
it('should follow Doctrine #11: ALWAYS HELP', () => {
|
33
|
+
expect(typeof encoder.help).toBe('function');
|
34
|
+
expect(() => encoder.help()).not.toThrow();
|
35
|
+
});
|
36
|
+
|
37
|
+
it('should follow Doctrine #9: ALWAYS TEACH', () => {
|
38
|
+
const contract = encoder.teach();
|
39
|
+
expect(contract).toBeDefined();
|
40
|
+
expect(contract.unitId).toBe('encoder');
|
41
|
+
expect(contract.capabilities).toBeDefined();
|
42
|
+
|
43
|
+
// Should teach native capabilities
|
44
|
+
expect(contract.capabilities.encode).toBeDefined();
|
45
|
+
expect(contract.capabilities.decode).toBeDefined();
|
46
|
+
expect(contract.capabilities.detect).toBeDefined();
|
47
|
+
expect(contract.capabilities.validate).toBeDefined();
|
48
|
+
});
|
49
|
+
|
50
|
+
it('should follow Doctrine #12: NAMESPACE EVERYTHING', () => {
|
51
|
+
const contract = encoder.teach();
|
52
|
+
expect(contract.unitId).toBe('encoder');
|
53
|
+
|
54
|
+
// When learned by other units, capabilities will be namespaced as "encoder.encode", etc.
|
55
|
+
});
|
56
|
+
|
57
|
+
it('should follow Doctrine #22: STATELESS OPERATIONS', () => {
|
58
|
+
// Capabilities are only for learned abilities, not native methods
|
59
|
+
const learnedCapabilities = encoder.capabilities();
|
60
|
+
expect(Array.isArray(learnedCapabilities)).toBe(true);
|
61
|
+
// New encoder has no learned capabilities
|
62
|
+
expect(learnedCapabilities).toHaveLength(0);
|
63
|
+
});
|
64
|
+
|
65
|
+
it('should provide proper whoami identification', () => {
|
66
|
+
const identity = encoder.whoami();
|
67
|
+
expect(identity).toContain('EncoderUnit');
|
68
|
+
expect(identity).toContain('encoder');
|
69
|
+
expect(identity).toContain('1.0.0');
|
70
|
+
});
|
71
|
+
});
|
72
|
+
|
73
|
+
describe('Configuration & State Management', () => {
|
74
|
+
it('should create with default configuration', () => {
|
75
|
+
const defaultEncoder = Encoder.create();
|
76
|
+
const state = defaultEncoder.toJSON();
|
77
|
+
|
78
|
+
expect(state.defaultFormat).toBe('base64');
|
79
|
+
expect(state.strictMode).toBe(false);
|
80
|
+
expect(state.autoDetect).toBe(true);
|
81
|
+
});
|
82
|
+
|
83
|
+
it('should create with custom configuration', () => {
|
84
|
+
const customEncoder = Encoder.create({
|
85
|
+
defaultFormat: 'hex',
|
86
|
+
strictMode: true,
|
87
|
+
autoDetect: false,
|
88
|
+
maxInputSize: 1024
|
89
|
+
});
|
90
|
+
|
91
|
+
const state = customEncoder.toJSON();
|
92
|
+
expect(state.defaultFormat).toBe('hex');
|
93
|
+
expect(state.strictMode).toBe(true);
|
94
|
+
expect(state.autoDetect).toBe(false);
|
95
|
+
});
|
96
|
+
|
97
|
+
it('should track stateless operation design', () => {
|
98
|
+
const encoder = Encoder.create();
|
99
|
+
|
100
|
+
// Perform operations - should not change unit state
|
101
|
+
encoder.encode('test1', 'base64');
|
102
|
+
encoder.encode('test2', 'hex');
|
103
|
+
|
104
|
+
// Unit should remain stateless - capabilities are only for learned abilities
|
105
|
+
const learnedCapabilities = encoder.capabilities();
|
106
|
+
expect(learnedCapabilities).toHaveLength(0); // No learned capabilities initially
|
107
|
+
});
|
108
|
+
});
|
109
|
+
});
|
110
|
+
|
111
|
+
describe('Encoder Unit - Core Encoding Operations', () => {
|
112
|
+
let encoder: Encoder;
|
113
|
+
|
114
|
+
beforeEach(() => {
|
115
|
+
encoder = Encoder.create();
|
116
|
+
});
|
117
|
+
|
118
|
+
describe('Base64 Encoding', () => {
|
119
|
+
it('should encode text to base64', () => {
|
120
|
+
const result = encoder.encode('Hello World', 'base64');
|
121
|
+
expect(result.isSuccess).toBe(true);
|
122
|
+
expect(result.value.encoded).toBe('SGVsbG8gV29ybGQ=');
|
123
|
+
expect(result.value.format).toBe('base64');
|
124
|
+
expect(result.value.originalSize).toBe(11);
|
125
|
+
});
|
126
|
+
|
127
|
+
it('should decode base64 text', () => {
|
128
|
+
const result = encoder.decode('SGVsbG8gV29ybGQ=', 'base64');
|
129
|
+
expect(result.isSuccess).toBe(true);
|
130
|
+
expect(result.value.decoded).toBe('Hello World');
|
131
|
+
expect(result.value.detectedFormat).toBe('base64');
|
132
|
+
});
|
133
|
+
|
134
|
+
it('should handle unicode characters', () => {
|
135
|
+
const unicode = '🚀 Hello 世界';
|
136
|
+
const encoded = encoder.encode(unicode, 'base64');
|
137
|
+
expect(encoded.isSuccess).toBe(true);
|
138
|
+
|
139
|
+
const decoded = encoder.decode(encoded.value.encoded, 'base64');
|
140
|
+
expect(decoded.isSuccess).toBe(true);
|
141
|
+
expect(decoded.value.decoded).toBe(unicode);
|
142
|
+
});
|
143
|
+
|
144
|
+
it('should validate base64 format', () => {
|
145
|
+
const validation = encoder.validate('SGVsbG8gV29ybGQ=', 'base64');
|
146
|
+
expect(validation.isValid).toBe(true);
|
147
|
+
expect(validation.errors).toHaveLength(0);
|
148
|
+
|
149
|
+
const invalidValidation = encoder.validate('SGVsbG8gV29ybGQ', 'base64');
|
150
|
+
expect(invalidValidation.isValid).toBe(false);
|
151
|
+
expect(invalidValidation.errors.length).toBeGreaterThan(0);
|
152
|
+
});
|
153
|
+
});
|
154
|
+
|
155
|
+
describe('Base64URL Encoding', () => {
|
156
|
+
it('should encode text to base64url', () => {
|
157
|
+
const result = encoder.encode('Hello World!', 'base64url');
|
158
|
+
expect(result.isSuccess).toBe(true);
|
159
|
+
expect(result.value.encoded).toBe('SGVsbG8gV29ybGQh');
|
160
|
+
expect(result.value.format).toBe('base64url');
|
161
|
+
});
|
162
|
+
|
163
|
+
it('should decode base64url text', () => {
|
164
|
+
const result = encoder.decode('SGVsbG8gV29ybGQh', 'base64url');
|
165
|
+
expect(result.isSuccess).toBe(true);
|
166
|
+
expect(result.value.decoded).toBe('Hello World!');
|
167
|
+
});
|
168
|
+
|
169
|
+
it('should handle URL-unsafe characters correctly', () => {
|
170
|
+
const text = 'Hello+World/Test=';
|
171
|
+
const encoded = encoder.encode(text, 'base64url');
|
172
|
+
expect(encoded.isSuccess).toBe(true);
|
173
|
+
expect(encoded.value.encoded).not.toContain('+');
|
174
|
+
expect(encoded.value.encoded).not.toContain('/');
|
175
|
+
expect(encoded.value.encoded).not.toContain('=');
|
176
|
+
|
177
|
+
const decoded = encoder.decode(encoded.value.encoded, 'base64url');
|
178
|
+
expect(decoded.value.decoded).toBe(text);
|
179
|
+
});
|
180
|
+
});
|
181
|
+
|
182
|
+
describe('Hexadecimal Encoding', () => {
|
183
|
+
it('should encode text to hex', () => {
|
184
|
+
const result = encoder.encode('Hello', 'hex');
|
185
|
+
expect(result.isSuccess).toBe(true);
|
186
|
+
expect(result.value.encoded).toBe('48656c6c6f');
|
187
|
+
});
|
188
|
+
|
189
|
+
it('should decode hex text', () => {
|
190
|
+
const result = encoder.decode('48656c6c6f', 'hex');
|
191
|
+
expect(result.isSuccess).toBe(true);
|
192
|
+
expect(result.value.decoded).toBe('Hello');
|
193
|
+
});
|
194
|
+
|
195
|
+
it('should handle both uppercase and lowercase hex', () => {
|
196
|
+
const lowerResult = encoder.decode('48656c6c6f', 'hex');
|
197
|
+
const upperResult = encoder.decode('48656C6C6F', 'hex');
|
198
|
+
|
199
|
+
expect(lowerResult.value.decoded).toBe('Hello');
|
200
|
+
expect(upperResult.value.decoded).toBe('Hello');
|
201
|
+
});
|
202
|
+
|
203
|
+
it('should validate hex format', () => {
|
204
|
+
const validation = encoder.validate('48656c6c6f', 'hex');
|
205
|
+
expect(validation.isValid).toBe(true);
|
206
|
+
|
207
|
+
const invalidValidation = encoder.validate('48656c6c6g', 'hex');
|
208
|
+
expect(invalidValidation.isValid).toBe(false);
|
209
|
+
expect(invalidValidation.errors).toContain('Contains invalid hexadecimal characters');
|
210
|
+
});
|
211
|
+
});
|
212
|
+
|
213
|
+
describe('URI Encoding', () => {
|
214
|
+
it('should encode text for URI', () => {
|
215
|
+
const result = encoder.encode('Hello World!', 'uri');
|
216
|
+
expect(result.isSuccess).toBe(true);
|
217
|
+
expect(result.value.encoded).toBe('Hello%20World!');
|
218
|
+
});
|
219
|
+
|
220
|
+
it('should decode URI encoded text', () => {
|
221
|
+
const result = encoder.decode('Hello%20World!', 'uri');
|
222
|
+
expect(result.isSuccess).toBe(true);
|
223
|
+
expect(result.value.decoded).toBe('Hello World!');
|
224
|
+
});
|
225
|
+
|
226
|
+
it('should handle special characters', () => {
|
227
|
+
const special = 'test@example.com?param=value&other=test';
|
228
|
+
const encoded = encoder.encode(special, 'uri');
|
229
|
+
expect(encoded.isSuccess).toBe(true);
|
230
|
+
|
231
|
+
const decoded = encoder.decode(encoded.value.encoded, 'uri');
|
232
|
+
expect(decoded.value.decoded).toBe(special);
|
233
|
+
});
|
234
|
+
});
|
235
|
+
|
236
|
+
describe('ASCII Encoding', () => {
|
237
|
+
it('should encode ASCII text', () => {
|
238
|
+
const result = encoder.encode('Hello World', 'ascii');
|
239
|
+
expect(result.isSuccess).toBe(true);
|
240
|
+
expect(result.value.encoded).toBe('Hello World');
|
241
|
+
});
|
242
|
+
|
243
|
+
it('should reject non-ASCII characters in strict mode', () => {
|
244
|
+
const strictEncoder = Encoder.create({ strictMode: true });
|
245
|
+
const result = strictEncoder.encode('Hello 世界', 'ascii');
|
246
|
+
expect(result.isFailure).toBe(true);
|
247
|
+
expect(result.error).toContain('Non-ASCII character found');
|
248
|
+
});
|
249
|
+
|
250
|
+
it('should validate ASCII format', () => {
|
251
|
+
const validation = encoder.validate('Hello World', 'ascii');
|
252
|
+
expect(validation.isValid).toBe(true);
|
253
|
+
|
254
|
+
const invalidValidation = encoder.validate('Hello 世界', 'ascii');
|
255
|
+
expect(invalidValidation.isValid).toBe(false);
|
256
|
+
});
|
257
|
+
});
|
258
|
+
});
|
259
|
+
|
260
|
+
describe('Encoder Unit - Advanced Operations', () => {
|
261
|
+
let encoder: Encoder;
|
262
|
+
|
263
|
+
beforeEach(() => {
|
264
|
+
encoder = Encoder.create();
|
265
|
+
});
|
266
|
+
|
267
|
+
describe('Format Detection', () => {
|
268
|
+
it('should detect base64 format', () => {
|
269
|
+
const detection = encoder.detect('SGVsbG8gV29ybGQ=');
|
270
|
+
expect(detection.format).toBe('base64');
|
271
|
+
expect(detection.confidence).toBeGreaterThan(0.8);
|
272
|
+
});
|
273
|
+
|
274
|
+
it('should detect hex format', () => {
|
275
|
+
const detection = encoder.detect('48656c6c6f');
|
276
|
+
expect(detection.format).toBe('hex');
|
277
|
+
expect(detection.confidence).toBeGreaterThan(0.9);
|
278
|
+
});
|
279
|
+
|
280
|
+
it('should detect base64url format', () => {
|
281
|
+
const detection = encoder.detect('SGVsbG8gV29ybGQh');
|
282
|
+
expect(detection.format).toBe('base64url');
|
283
|
+
expect(detection.confidence).toBeGreaterThan(0.8);
|
284
|
+
});
|
285
|
+
|
286
|
+
it('should detect URI encoding', () => {
|
287
|
+
const detection = encoder.detect('Hello%20World!');
|
288
|
+
expect(detection.format).toBe('uri');
|
289
|
+
expect(detection.confidence).toBeGreaterThan(0.7);
|
290
|
+
});
|
291
|
+
|
292
|
+
it('should detect ASCII format', () => {
|
293
|
+
const detection = encoder.detect('Hello World');
|
294
|
+
expect(detection.format).toBe('ascii');
|
295
|
+
expect(detection.confidence).toBeGreaterThan(0.6);
|
296
|
+
});
|
297
|
+
|
298
|
+
it('should throw for undetectable formats', () => {
|
299
|
+
expect(() => encoder.detect('🚀💫🌟')).toThrow();
|
300
|
+
});
|
301
|
+
});
|
302
|
+
|
303
|
+
describe('Chain Operations', () => {
|
304
|
+
it('should chain multiple encodings', () => {
|
305
|
+
const result = encoder.chain('Hello', ['hex', 'base64']);
|
306
|
+
expect(result.isSuccess).toBe(true);
|
307
|
+
|
308
|
+
// First hex: 'Hello' -> '48656c6c6f'
|
309
|
+
// Then base64: '48656c6c6f' -> 'NDg2NTZjNmM2Zg=='
|
310
|
+
expect(result.value.encoded).toBe('NDg2NTZjNmM2Zg==');
|
311
|
+
expect(result.value.format).toBe('base64');
|
312
|
+
});
|
313
|
+
|
314
|
+
it('should reverse chain decodings', () => {
|
315
|
+
const original = 'Hello World';
|
316
|
+
const chained = encoder.chain(original, ['hex', 'base64', 'uri']);
|
317
|
+
expect(chained.isSuccess).toBe(true);
|
318
|
+
|
319
|
+
const reversed = encoder.reverse(chained.value.encoded, ['hex', 'base64', 'uri']);
|
320
|
+
expect(reversed.isSuccess).toBe(true);
|
321
|
+
expect(reversed.value.decoded).toBe(original);
|
322
|
+
});
|
323
|
+
|
324
|
+
it('should handle chain failures gracefully', () => {
|
325
|
+
// Create an encoder that will fail during encoding
|
326
|
+
const encoder_strict = Encoder.create({ strictMode: true, maxInputSize: 5 });
|
327
|
+
|
328
|
+
// This should fail because input exceeds maxInputSize
|
329
|
+
const result = encoder_strict.chain('Hello World - this is too long', ['base64', 'hex']);
|
330
|
+
|
331
|
+
|
332
|
+
expect(result.isFailure).toBe(true);
|
333
|
+
expect(result.error).toContain('Chain failed');
|
334
|
+
});
|
335
|
+
|
336
|
+
it('should calculate compression ratios', () => {
|
337
|
+
const result = encoder.chain('Hello', ['hex']);
|
338
|
+
expect(result.isSuccess).toBe(true);
|
339
|
+
expect(result.value.compressionRatio).toBeCloseTo(2.0); // hex doubles size
|
340
|
+
|
341
|
+
const base64Result = encoder.encode('Hello', 'base64');
|
342
|
+
expect(base64Result.value.compressionRatio).toBeCloseTo(1.6); // base64 ~60% increase
|
343
|
+
});
|
344
|
+
});
|
345
|
+
|
346
|
+
describe('Auto-detection Decoding', () => {
|
347
|
+
it('should auto-detect and decode base64', () => {
|
348
|
+
const result = encoder.decode('SGVsbG8gV29ybGQ='); // no format specified
|
349
|
+
expect(result.isSuccess).toBe(true);
|
350
|
+
expect(result.value.decoded).toBe('Hello World');
|
351
|
+
expect(result.value.detectedFormat).toBe('base64');
|
352
|
+
});
|
353
|
+
|
354
|
+
it('should auto-detect and decode hex', () => {
|
355
|
+
const result = encoder.decode('48656c6c6f'); // no format specified
|
356
|
+
expect(result.isSuccess).toBe(true);
|
357
|
+
expect(result.value.decoded).toBe('Hello');
|
358
|
+
expect(result.value.detectedFormat).toBe('hex');
|
359
|
+
});
|
360
|
+
|
361
|
+
it('should disable auto-detection when configured', () => {
|
362
|
+
const noAutoDetect = Encoder.create({ autoDetect: false, defaultFormat: 'hex' });
|
363
|
+
const result = noAutoDetect.decode('SGVsbG8gV29ybGQ='); // base64 data
|
364
|
+
|
365
|
+
|
366
|
+
expect(result.isFailure).toBe(true); // should fail as it tries to decode as hex
|
367
|
+
expect(result.error).toContain('Invalid hex format');
|
368
|
+
});
|
369
|
+
});
|
370
|
+
|
371
|
+
describe('Error Handling & Validation', () => {
|
372
|
+
it('should handle large input validation', () => {
|
373
|
+
const smallLimitEncoder = Encoder.create({ maxInputSize: 10 });
|
374
|
+
const result = smallLimitEncoder.encode('This is a very long string that exceeds the limit');
|
375
|
+
expect(result.isFailure).toBe(true);
|
376
|
+
expect(result.error).toContain('Input too large');
|
377
|
+
});
|
378
|
+
|
379
|
+
it('should provide detailed validation errors', () => {
|
380
|
+
const validation = encoder.validate('SGVsbG8', 'base64'); // missing padding
|
381
|
+
expect(validation.isValid).toBe(false);
|
382
|
+
expect(validation.errors).toContain('Invalid base64 length (must be multiple of 4)');
|
383
|
+
expect(validation.suggestions).toContain('Add padding with = characters');
|
384
|
+
});
|
385
|
+
|
386
|
+
it('should handle output validation', () => {
|
387
|
+
// This test verifies that output validation works
|
388
|
+
const encoder_with_validation = Encoder.create({ validateOutput: true });
|
389
|
+
const result = encoder_with_validation.encode('Hello', 'base64');
|
390
|
+
expect(result.isSuccess).toBe(true); // Should pass validation
|
391
|
+
});
|
392
|
+
|
393
|
+
it('should provide error causes in Result failures', () => {
|
394
|
+
const result = encoder.decode('invalid-base64-data!@#$', 'base64');
|
395
|
+
|
396
|
+
expect(result.isFailure).toBe(true);
|
397
|
+
expect(result.errorCause).toBeDefined();
|
398
|
+
});
|
399
|
+
});
|
400
|
+
|
401
|
+
describe('Teaching & Learning Integration', () => {
|
402
|
+
it('should teach capabilities with proper signatures', () => {
|
403
|
+
const contract = encoder.teach();
|
404
|
+
|
405
|
+
// Test that taught capabilities work
|
406
|
+
const encodeCapability = contract.capabilities.encode as Function;
|
407
|
+
expect(typeof encodeCapability).toBe('function');
|
408
|
+
|
409
|
+
// Should work when called through teaching contract
|
410
|
+
const result = encodeCapability('Hello', 'base64');
|
411
|
+
expect(result.isSuccess).toBe(true);
|
412
|
+
});
|
413
|
+
|
414
|
+
it('should maintain consistent metadata access', () => {
|
415
|
+
const contract = encoder.teach();
|
416
|
+
|
417
|
+
const getDefaultFormat = contract.capabilities.getDefaultFormat as Function;
|
418
|
+
const isStrictMode = contract.capabilities.isStrictMode as Function;
|
419
|
+
|
420
|
+
expect(getDefaultFormat()).toBe('base64');
|
421
|
+
expect(typeof isStrictMode()).toBe('boolean');
|
422
|
+
});
|
423
|
+
});
|
424
|
+
});
|