@cloudpss/ubjson 0.5.35 → 0.5.36

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 (43) hide show
  1. package/{benchmark-string.js → benchmark-string-decode.js} +4 -4
  2. package/benchmark-string-encode.js +32 -0
  3. package/benchmark-string-size-caculation.js +9 -11
  4. package/benchmark.js +1 -0
  5. package/dist/common/decoder.js +2 -1
  6. package/dist/common/decoder.js.map +1 -1
  7. package/dist/common/encoder.d.ts +4 -2
  8. package/dist/common/encoder.js +106 -45
  9. package/dist/common/encoder.js.map +1 -1
  10. package/dist/common/errors.d.ts +4 -0
  11. package/dist/common/errors.js +14 -0
  12. package/dist/common/errors.js.map +1 -0
  13. package/dist/common/string-decoder.d.ts +5 -3
  14. package/dist/common/string-decoder.js +23 -14
  15. package/dist/common/string-decoder.js.map +1 -1
  16. package/dist/common/string-encoder.d.ts +32 -2
  17. package/dist/common/string-encoder.js +105 -12
  18. package/dist/common/string-encoder.js.map +1 -1
  19. package/dist/stream-helper/encoder.d.ts +4 -4
  20. package/dist/stream-helper/encoder.js +116 -41
  21. package/dist/stream-helper/encoder.js.map +1 -1
  22. package/package.json +3 -3
  23. package/src/common/decoder.ts +2 -1
  24. package/src/common/encoder.ts +100 -42
  25. package/src/common/errors.ts +14 -0
  26. package/src/common/string-decoder.ts +26 -17
  27. package/src/common/string-encoder.ts +103 -14
  28. package/src/stream-helper/encoder.ts +118 -39
  29. package/tests/.utils.js +10 -0
  30. package/tests/e2e/.data.js +470 -0
  31. package/tests/e2e/no-buffer-text.js +37 -0
  32. package/tests/e2e/no-buffer.js +30 -0
  33. package/tests/e2e/no-encode-into.js +32 -0
  34. package/tests/e2e/no-textencoder-decoder.js +34 -0
  35. package/tests/e2e/normal.js +27 -0
  36. package/tests/e2e/stream.js +20 -0
  37. package/tests/encode.js +11 -19
  38. package/tests/huge-string.js +7 -9
  39. package/tests/rxjs/encode.js +4 -18
  40. package/tests/stream/encode.js +0 -15
  41. package/tests/string-encoding.js +3 -2
  42. package/tests/tsconfig.json +2 -1
  43. package/tests/e2e.js +0 -415
@@ -0,0 +1,470 @@
1
+ /** @type {Record<string, unknown>} */
2
+ export const INPUTS = {};
3
+ /** @type {Record<string, unknown>} */
4
+ export const EXPECTED = {};
5
+
6
+ INPUTS['number 0'] = 0;
7
+ INPUTS['number 1'] = 1;
8
+ INPUTS['number nan'] = Number.NaN;
9
+ INPUTS['number infinity'] = Number.POSITIVE_INFINITY;
10
+ INPUTS['number negative infinity'] = -Number.NEGATIVE_INFINITY;
11
+ INPUTS['number epsilon'] = Number.EPSILON;
12
+ INPUTS['number int8 max'] = 127;
13
+ INPUTS['number int8 min'] = -128;
14
+ INPUTS['number int16 max'] = 32767;
15
+ INPUTS['number int16 min'] = -32768;
16
+ INPUTS['number int32 max'] = 2_147_483_647;
17
+ INPUTS['number int32 min'] = -2_147_483_648;
18
+ INPUTS['number uint8 max'] = 255;
19
+ INPUTS['number 0.1'] = 0.1;
20
+ INPUTS['number 0.01'] = 0.01;
21
+ INPUTS['number max safe integer'] = Number.MAX_SAFE_INTEGER;
22
+ INPUTS['number min safe integer'] = Number.MIN_SAFE_INTEGER;
23
+ INPUTS['number max value'] = Number.MAX_VALUE;
24
+ INPUTS['number min value'] = Number.MIN_VALUE;
25
+
26
+ INPUTS['has function'] = {
27
+ value: 1,
28
+ func: () => null,
29
+ };
30
+ EXPECTED['has function'] = { value: 1 };
31
+
32
+ INPUTS['function'] = () => null;
33
+ EXPECTED['function'] = new Error('Unsupported type Function');
34
+
35
+ INPUTS['symbol key'] = {
36
+ value: 1,
37
+ [Symbol('key')]: 2,
38
+ };
39
+ EXPECTED['symbol key'] = { value: 1 };
40
+
41
+ INPUTS['symbol value'] = {
42
+ value: Symbol('value'),
43
+ };
44
+ EXPECTED['symbol value'] = new Error('Unsupported type Symbol');
45
+
46
+ INPUTS['has null'] = {
47
+ value: 1,
48
+ null: null,
49
+ };
50
+
51
+ INPUTS['has undefined'] = {
52
+ value: 1,
53
+ undefined: undefined,
54
+ };
55
+ EXPECTED['has undefined'] = { value: 1 };
56
+
57
+ INPUTS['with toJSON'] = new Date(0);
58
+ EXPECTED['with toJSON'] = '1970-01-01T00:00:00.000Z';
59
+
60
+ INPUTS['int8 array'] = new Int8Array([-128, 0, 1, 2, 3, 4, 5, 127]);
61
+ INPUTS['uint8 array'] = new Uint8Array([0, 1, 2, 3, 4, 5, 255]);
62
+ INPUTS['int16 array'] = new Int16Array([-32768, 0, 1, 2, 3, 4, 5, 32767]);
63
+ INPUTS['int32 array'] = new Int32Array([-2_147_483_648, 0, 1, 2, 3, 4, 5, 2_147_483_647]);
64
+ INPUTS['bigint64 array'] = new BigInt64Array([
65
+ -9_223_372_036_854_775_808n,
66
+ 0n,
67
+ 1n,
68
+ 2n,
69
+ 3n,
70
+ 4n,
71
+ 5n,
72
+ 9_223_372_036_854_775_807n,
73
+ ]);
74
+ INPUTS['float32 array'] = new Float32Array([0, Number.NaN, 2, 3, 4, 5, Number.MAX_VALUE, Number.MIN_VALUE]);
75
+ INPUTS['float64 array'] = new Float64Array([0, Number.NaN, 2, 3, 4, 5, Number.MAX_VALUE, Number.MIN_VALUE]);
76
+
77
+ INPUTS['big int8 array'] = new Int8Array(128 * 1024);
78
+ INPUTS['big uint8 array'] = new Uint8Array(128 * 1024);
79
+ INPUTS['big int16 array'] = new Int16Array(64 * 1024);
80
+ INPUTS['big int32 array'] = new Int32Array(32 * 1024);
81
+ INPUTS['big bigint64 array'] = new BigInt64Array(16 * 1024);
82
+ INPUTS['big float32 array'] = new Float32Array(32 * 1024);
83
+ INPUTS['big float64 array'] = new Float64Array(16 * 1024);
84
+
85
+ INPUTS['uint8clamp array'] = new Uint8ClampedArray([0, 1, 2, 3, 4, 5, 255]);
86
+ EXPECTED['uint8clamp array'] = new Error('Unsupported array buffer view of type Uint8ClampedArray');
87
+
88
+ INPUTS['typed arrays'] = {
89
+ int8: new Int8Array([-128, 0, 1, 2, 3, 4, 5, 127]),
90
+ uint8: new Uint8Array([0, 1, 2, 3, 4, 5, 255]),
91
+ int16: new Int16Array([-32768, 0, 1, 2, 3, 4, 5, 32767]),
92
+ int32: new Int32Array([-2_147_483_648, 0, 1, 2, 3, 4, 5, 2_147_483_647]),
93
+ bigint64: new BigInt64Array([-9_223_372_036_854_775_808n, 0n, 1n, 2n, 3n, 4n, 5n, 9_223_372_036_854_775_807n]),
94
+ float32: new Float32Array([0, Number.NaN, 2, 3, 4, 5, Number.MAX_VALUE, Number.MIN_VALUE]),
95
+ float64: new Float64Array([0, Number.NaN, 2, 3, 4, 5, Number.MAX_VALUE, Number.MIN_VALUE]),
96
+ int8_big: new Int8Array(128 * 1024),
97
+ uint8_big: new Uint8Array(128 * 1024),
98
+ int16_big: new Int16Array(64 * 1024),
99
+ int32_big: new Int32Array(32 * 1024),
100
+ bigint64_big: new BigInt64Array(16 * 1024),
101
+ float32_big: new Float32Array(32 * 1024),
102
+ float64_big: new Float64Array(16 * 1024),
103
+ };
104
+
105
+ INPUTS['string empty'] = '';
106
+ INPUTS['string short ascii'] = 'hello world';
107
+ INPUTS['string short 2-byte utf8'] = 'ӒӓӔӕӖӗӘәӚӛӜӝ';
108
+ INPUTS['string short 3-byte utf8'] = '你好世界';
109
+ INPUTS['string short 4-byte utf8'] = '😀😀😀';
110
+ INPUTS['string short 4-byte utf8 unaligned'] = 'a😀😀😀';
111
+ INPUTS['string bad surrogate pair'] = 'a\uD800b\uDC00c';
112
+ EXPECTED['string bad surrogate pair'] = 'a\uFFFDb\uFFFDc';
113
+ INPUTS['string bad high surrogate'] = '\uD800'.repeat(8);
114
+ EXPECTED['string bad high surrogate'] = '\uFFFD'.repeat(8);
115
+ INPUTS['string bad low surrogate'] = '\uDC00'.repeat(8);
116
+ EXPECTED['string bad low surrogate'] = '\uFFFD'.repeat(8);
117
+ INPUTS['long string with surrogate pairs'] = '😀'.repeat(128 * 1024);
118
+ INPUTS['long string with surrogate pairs unaligned'] = 'a' + '😀'.repeat(128 * 1024) + 'b';
119
+ INPUTS['long string bad high surrogate'] = '\uD800'.repeat(128 * 1024);
120
+ EXPECTED['long string bad high surrogate'] = '\uFFFD'.repeat(128 * 1024);
121
+ INPUTS['long string bad low surrogate'] = '\uDC00'.repeat(128 * 1024);
122
+ EXPECTED['long string bad low surrogate'] = '\uFFFD'.repeat(128 * 1024);
123
+
124
+ INPUTS['huge object'] = Object.fromEntries(
125
+ Array.from({ length: 100_000 }, (_, i) => [
126
+ `key${i}`,
127
+ {
128
+ number: i,
129
+ boolean: i % 2 === 0,
130
+ string: `value${i}`,
131
+ null: null,
132
+ },
133
+ ]),
134
+ );
135
+
136
+ INPUTS['huge array'] = Array.from({ length: 100_000 }, (_, i) => {
137
+ switch (i % 7) {
138
+ case 0:
139
+ return i;
140
+ case 1:
141
+ return i % 2 === 0;
142
+ case 2:
143
+ return `value${i}`;
144
+ case 3:
145
+ return null;
146
+ }
147
+ return undefined;
148
+ });
149
+ EXPECTED['huge array'] = Array.from({ length: 100_000 }, (_, i) => {
150
+ switch (i % 7) {
151
+ case 0:
152
+ return i;
153
+ case 1:
154
+ return i % 2 === 0;
155
+ case 2:
156
+ return `value${i}`;
157
+ }
158
+ return null;
159
+ });
160
+
161
+ INPUTS['complex object'] = {
162
+ hello: 'world',
163
+ from: ['UBJSON'],
164
+ colors: [[255, 255, 255], [0, 0, 0], [64, 64, 96], new Uint8Array([255, 0, 1, 2, 3, 127])],
165
+ domains: {
166
+ '': '',
167
+ com: 'commercial',
168
+ org: 'organization',
169
+ net: 'network',
170
+ },
171
+ entires: [
172
+ {
173
+ id: 1,
174
+ name: 'test',
175
+ content: null,
176
+ timestamp: 1_532_432_408.008,
177
+ published: false,
178
+ },
179
+ {
180
+ id: 2,
181
+ name: 'lorem',
182
+ content: 'Lorem ipsum...',
183
+ timestamp: 1_532_432_416.346,
184
+ published: true,
185
+ },
186
+ ],
187
+ plots: {
188
+ traces: [
189
+ {
190
+ name: 'test',
191
+ x: new Float64Array([
192
+ 1,
193
+ 2,
194
+ 3,
195
+ Number.NEGATIVE_INFINITY,
196
+ Number.POSITIVE_INFINITY,
197
+ Number.NaN,
198
+ Number.MAX_VALUE,
199
+ Number.MIN_VALUE,
200
+ ]),
201
+ y: new Int8Array([0, 4, 5, 6, -128, -1, 127]),
202
+ },
203
+ {
204
+ name: 'test2',
205
+ x: new Float32Array([
206
+ 1,
207
+ 2,
208
+ 3,
209
+ Number.NEGATIVE_INFINITY,
210
+ Number.POSITIVE_INFINITY,
211
+ Number.NaN,
212
+ Number.MAX_VALUE,
213
+ Number.MIN_VALUE,
214
+ ]),
215
+ y: new Int16Array([4, 5, 6, -32768, 32767]),
216
+ },
217
+ {
218
+ name: 'test233',
219
+ x: new Int32Array([1, 2, 3, 0, -1]),
220
+ y: new Int32Array([4, 5, 6, -(2 ** 31), 2 ** 31 - 1]),
221
+ },
222
+ ],
223
+ },
224
+ name1: 'short text'.repeat(10),
225
+ name2: 'short text'.repeat(20),
226
+ name3: 'short text'.repeat(30),
227
+ name4: 'short text'.repeat(40),
228
+ name5: 'short text'.repeat(50),
229
+ name6: 'short text'.repeat(60),
230
+ name7: 'short text'.repeat(70),
231
+ name8: 'short text'.repeat(80),
232
+ name9: 'short text'.repeat(90),
233
+ description1: 'medium text'.repeat(100),
234
+ description2: 'medium text'.repeat(200),
235
+ description3: 'medium text'.repeat(500),
236
+ description4: 'medium text'.repeat(1000),
237
+ description5: 'medium text'.repeat(2000),
238
+ description6: 'medium text'.repeat(3000),
239
+ document1: 'long text'.repeat(10000),
240
+ document2: 'long text'.repeat(20000),
241
+ document3: 'long text'.repeat(50000),
242
+ document4: 'long text'.repeat(100_000),
243
+ };
244
+
245
+ INPUTS['cloudpss model'] = {
246
+ rid: 'project/CloudPSS/_SubSysPort',
247
+ name: '模块端口',
248
+ description: '',
249
+ tags: [
250
+ 'project:component',
251
+ 'type:30000',
252
+ 'project-group:模块-基础:101',
253
+ 'project-category:component',
254
+ 'project-support:job-definition/cloudpss/emtp',
255
+ 'project-support:job-definition/cloudpss/sfemt',
256
+ 'project-support:job-definition/cloudpss/power-flow',
257
+ ],
258
+ revision: {
259
+ graphic: {
260
+ pins: {
261
+ input: {
262
+ position: {
263
+ x: 0.999_999_9,
264
+ y: 0.5,
265
+ },
266
+ },
267
+ output: {
268
+ position: {
269
+ x: 0,
270
+ y: 0.5,
271
+ },
272
+ },
273
+ electrical: {
274
+ position: {
275
+ x: 0.999_999_9,
276
+ y: 0.5,
277
+ },
278
+ },
279
+ },
280
+ attrs: {
281
+ p0: {
282
+ fill: 'var(--fill)',
283
+ stroke: 'var(--stroke)',
284
+ refPath: {
285
+ d: 'm90000 0h-60000a10000 10000 0 0 0 0 20000h60000zm0 10000h20000',
286
+ h: 20000,
287
+ w: 110_000,
288
+ },
289
+ fillOpacity: 'var(--fill-opacity)',
290
+ strokeWidth: 'var(--stroke-width)',
291
+ strokeOpacity: 'var(--stroke-opacity)',
292
+ },
293
+ p1: {
294
+ fill: 'var(--fill)',
295
+ stroke: 'var(--stroke)',
296
+ refPath: {
297
+ d: 'm90000 0h-60000a10000 10000 0 0 0 0 20000h60000zm0 10000h20000',
298
+ h: 20000,
299
+ w: 110_000,
300
+ },
301
+ fillOpacity: 'var(--fill-opacity)',
302
+ strokeWidth: 'var(--stroke-width)',
303
+ strokeOpacity: 'var(--stroke-opacity)',
304
+ },
305
+ p2: {
306
+ fill: 'transparent',
307
+ stroke: 'var(--stroke)',
308
+ refPath: {
309
+ d: 'm20000 10000m-5000 -5000l5000 5000l-5000 5000',
310
+ h: 20000,
311
+ w: 110_000,
312
+ },
313
+ fillOpacity: 'var(--fill-opacity)',
314
+ strokeWidth: 'var(--stroke-width)',
315
+ strokeOpacity: 'var(--stroke-opacity)',
316
+ },
317
+ p3: {
318
+ fill: 'var(--fill)',
319
+ stroke: 'var(--stroke)',
320
+ refPath: {
321
+ d: 'm20000 0h60000a10000 10000 0 0 1 0 20000h-60000zm0 10000h-20000',
322
+ h: 20000,
323
+ w: 110_000,
324
+ },
325
+ fillOpacity: 'var(--fill-opacity)',
326
+ strokeWidth: 'var(--stroke-width)',
327
+ strokeOpacity: 'var(--stroke-opacity)',
328
+ },
329
+ p4: {
330
+ fill: 'transparent',
331
+ stroke: 'var(--stroke)',
332
+ refPath: {
333
+ d: 'm110000 10000m-5000 -5000l5000 5000l-5000 5000',
334
+ h: 20000,
335
+ w: 110_000,
336
+ },
337
+ fillOpacity: 'var(--fill-opacity)',
338
+ strokeWidth: 'var(--stroke-width)',
339
+ strokeOpacity: 'var(--stroke-opacity)',
340
+ },
341
+ t0: {
342
+ fill: 'var(--spectrum-global-color-orange-600)',
343
+ refX: 0.5,
344
+ refY: 0.5,
345
+ stroke: 'transparent',
346
+ fontSize: 12,
347
+ textAnchor: 'middle',
348
+ },
349
+ },
350
+ width: 110,
351
+ height: 20,
352
+ markup: [
353
+ {
354
+ tagName: 'path',
355
+ selector: 'p0',
356
+ condition:
357
+ "=finder(p, index, array)= equalText(p.key, Key);\n p = $$.revision.pins.find(finder);\n p == undefined ? true : (not equalText(p.connection, 'input') and not equalText(p.connection, 'output'))",
358
+ },
359
+ {
360
+ tagName: 'path',
361
+ selector: 'p1',
362
+ condition:
363
+ "=finder(p, index, array) = equalText(p.key, Key);\n p = $$.revision.pins.find(finder);\n p != undefined ? equalText(p.connection, 'input') :false",
364
+ },
365
+ {
366
+ tagName: 'path',
367
+ selector: 'p2',
368
+ condition:
369
+ "=finder(p, index, array) = equalText(p.key, Key);\n p = $$.revision.pins.find(finder);\n p != undefined ? equalText(p.connection, 'output') : false",
370
+ },
371
+ {
372
+ tagName: 'path',
373
+ selector: 'p3',
374
+ condition:
375
+ "=finder(p, index, array) = equalText(p.key, Key);\n p = $$.revision.pins.find(finder);\n p != undefined ? equalText(p.connection, 'output') : false",
376
+ },
377
+ {
378
+ tagName: 'path',
379
+ selector: 'p4',
380
+ condition:
381
+ "=finder(p, index, array) = equalText(p.key, Key);\n p = $$.revision.pins.find(finder);\n p != undefined ? equalText(p.connection, 'input') :false",
382
+ },
383
+ {
384
+ attrs: {
385
+ y: '0.35em',
386
+ },
387
+ tagName: 'text',
388
+ selector: 't0',
389
+ condition: '',
390
+ textContent: 'Port: $Key',
391
+ },
392
+ ],
393
+ generator: 'x6',
394
+ },
395
+ parameters: [
396
+ {
397
+ name: 'Configuration',
398
+ items: [
399
+ {
400
+ key: 'Key',
401
+ name: 'Pin Key',
402
+ type: 'choice',
403
+ value: '',
404
+ choices:
405
+ '=mapper(p,index,array) = {key: p.key, name: p.key, description: p.description};\n$$.revision.pins.map(mapper)',
406
+ condition: 'true',
407
+ description: '绑定端口',
408
+ },
409
+ ],
410
+ condition: 'true',
411
+ description: 'Configuration',
412
+ },
413
+ ],
414
+ pins: [
415
+ {
416
+ dim: [
417
+ "=finder(p, index, array) = equalText(p.key, 'a');\np = $$.revision.pins.find(finder);\np!=undefined?p.dim[1]:''",
418
+ "=finder(p, index, array) = equalText(p.key, 'a');\np = $$.revision.pins.find(finder);\np!=undefined?p.dim[2]:''",
419
+ ],
420
+ key: 'input',
421
+ data: 'real',
422
+ name: 'Port',
423
+ visible: true,
424
+ condition:
425
+ "=finder(p, index, array) = equalText(p.key, Key);\np = $$.revision.pins.find(finder);\np != undefined ? equalText(p.connection, 'input') :false",
426
+ connection: 'output',
427
+ },
428
+ {
429
+ dim: [
430
+ "=finder(p, index, array) = equalText(p.key, 'a');\np = $$.revision.pins.find(finder);\np!=undefined?p.dim[2]:''",
431
+ "=finder(p, index, array) = equalText(p.key, 'a');\np = $$.revision.pins.find(finder);\np!=undefined?p.dim[2]:''",
432
+ ],
433
+ key: 'output',
434
+ data: 'real',
435
+ name: 'Port',
436
+ visible: true,
437
+ condition:
438
+ "=finder(p, index, array) = equalText(p.key, Key);\np = $$.revision.pins.find(finder);\np != undefined ? equalText(p.connection, 'output') :false",
439
+ connection: 'input',
440
+ },
441
+ {
442
+ dim: [
443
+ "=finder(p, index, array) = equalText(p.key, 'a');\np = $$.revision.pins.find(finder);\np!=undefined?p.dim[2]:''",
444
+ "=finder(p, index, array) = equalText(p.key, 'a');\np = $$.revision.pins.find(finder);\np!=undefined?p.dim[2]:''",
445
+ ],
446
+ key: 'electrical',
447
+ data: 'real',
448
+ name: 'Port',
449
+ visible: true,
450
+ condition:
451
+ "=finder(p, index, array)= equalText(p.key, Key);\np = $$.revision.pins.find(finder);\np == undefined ? true : (not equalText(p.connection, 'input') and not equalText(p.connection, 'output'))",
452
+ connection: 'electrical',
453
+ },
454
+ ],
455
+ documentation: '@[docs](http://docs.cloudpss.net/components/comp_PSS/comp_PSSSystem/BasicComp/SystemPort)',
456
+ },
457
+ };
458
+
459
+ INPUTS['large array'] = Array.from({ length: 100_000 }).map((_, i) => (i === 12345 ? 'item' : undefined));
460
+ EXPECTED['large array'] = Array.from({ length: 100_000 }).map((_, i) => (i === 12345 ? 'item' : null));
461
+
462
+ INPUTS['object with undefined values'] = { a: 1, b: undefined, c: { d: 2, e: undefined, f: null } };
463
+ EXPECTED['object with undefined values'] = { a: 1, c: { d: 2, f: null } };
464
+
465
+ INPUTS['array with undefined values'] = [1, undefined, 2, undefined, 3];
466
+ EXPECTED['array with undefined values'] = [1, null, 2, null, 3];
467
+
468
+ INPUTS['invalid __proto__'] = JSON.parse('{"__proto__":"xxx"}');
469
+
470
+ INPUTS['null __proto__'] = JSON.parse('{"__proto__":null}');
@@ -0,0 +1,37 @@
1
+ import { resetEnv } from '../.utils.js';
2
+ import { INPUTS, EXPECTED } from './.data.js';
3
+ import { encode, decode } from '../../dist/index.js';
4
+
5
+ describe('no Buffer and no textencoder/decoder', () => {
6
+ const { TextEncoder, TextDecoder } = global;
7
+ beforeAll(() => {
8
+ // @ts-expect-error remove buffer
9
+ global.Buffer = undefined;
10
+ // @ts-expect-error 移除 TextEncoder 以测试兼容性
11
+ global.TextEncoder = undefined;
12
+ // @ts-expect-error 移除 TextDecoder 以测试兼容性
13
+ global.TextDecoder = undefined;
14
+ resetEnv();
15
+ });
16
+ afterAll(() => {
17
+ global.Buffer = Buffer;
18
+ global.TextEncoder = TextEncoder;
19
+ global.TextDecoder = TextDecoder;
20
+ resetEnv();
21
+ });
22
+
23
+ it.each(Object.keys(INPUTS))('%s', (name) => {
24
+ const input = INPUTS[name];
25
+ const expected = EXPECTED[name] ?? input;
26
+ if (expected instanceof Error) {
27
+ expect(() => {
28
+ const encoded = encode(input);
29
+ decode(encoded);
30
+ }).toThrow(expected);
31
+ } else {
32
+ const encoded = encode(input);
33
+ const decoded = decode(encoded);
34
+ expect(decoded).toEqual(expected);
35
+ }
36
+ });
37
+ });
@@ -0,0 +1,30 @@
1
+ import { resetEnv } from '../.utils.js';
2
+ import { INPUTS, EXPECTED } from './.data.js';
3
+ import { encode, decode } from '../../dist/index.js';
4
+
5
+ describe('no Buffer', () => {
6
+ beforeAll(() => {
7
+ // @ts-expect-error remove buffer
8
+ global.Buffer = undefined;
9
+ resetEnv();
10
+ });
11
+ afterAll(() => {
12
+ global.Buffer = Buffer;
13
+ resetEnv();
14
+ });
15
+
16
+ it.each(Object.keys(INPUTS))('%s', (name) => {
17
+ const input = INPUTS[name];
18
+ const expected = EXPECTED[name] ?? input;
19
+ if (expected instanceof Error) {
20
+ expect(() => {
21
+ const encoded = encode(input);
22
+ decode(encoded);
23
+ }).toThrow(expected);
24
+ } else {
25
+ const encoded = encode(input);
26
+ const decoded = decode(encoded);
27
+ expect(decoded).toEqual(expected);
28
+ }
29
+ });
30
+ });
@@ -0,0 +1,32 @@
1
+ import { resetEnv } from '../.utils.js';
2
+ import { INPUTS, EXPECTED } from './.data.js';
3
+ import { encode, decode } from '../../dist/index.js';
4
+
5
+ describe('no encodeInto', () => {
6
+ // eslint-disable-next-line @typescript-eslint/unbound-method
7
+ const encodeInto = TextEncoder.prototype.encodeInto;
8
+ beforeAll(() => {
9
+ // @ts-expect-error 移除 encodeInto 以测试兼容性
10
+ TextEncoder.prototype.encodeInto = undefined;
11
+ resetEnv();
12
+ });
13
+ afterAll(() => {
14
+ TextEncoder.prototype.encodeInto = encodeInto;
15
+ resetEnv();
16
+ });
17
+
18
+ it.each(Object.keys(INPUTS))('%s', (name) => {
19
+ const input = INPUTS[name];
20
+ const expected = EXPECTED[name] ?? input;
21
+ if (expected instanceof Error) {
22
+ expect(() => {
23
+ const encoded = encode(input);
24
+ decode(encoded);
25
+ }).toThrow(expected);
26
+ } else {
27
+ const encoded = encode(input);
28
+ const decoded = decode(encoded);
29
+ expect(decoded).toEqual(expected);
30
+ }
31
+ });
32
+ });
@@ -0,0 +1,34 @@
1
+ import { resetEnv } from '../.utils.js';
2
+ import { INPUTS, EXPECTED } from './.data.js';
3
+ import { encode, decode } from '../../dist/index.js';
4
+
5
+ describe('no textencoder/decoder', () => {
6
+ const { TextEncoder, TextDecoder } = global;
7
+ beforeAll(() => {
8
+ // @ts-expect-error 移除 TextEncoder 以测试兼容性
9
+ global.TextEncoder = undefined;
10
+ // @ts-expect-error 移除 TextDecoder 以测试兼容性
11
+ global.TextDecoder = undefined;
12
+ resetEnv();
13
+ });
14
+ afterAll(() => {
15
+ global.TextEncoder = TextEncoder;
16
+ global.TextDecoder = TextDecoder;
17
+ resetEnv();
18
+ });
19
+
20
+ it.each(Object.keys(INPUTS))('%s', (name) => {
21
+ const input = INPUTS[name];
22
+ const expected = EXPECTED[name] ?? input;
23
+ if (expected instanceof Error) {
24
+ expect(() => {
25
+ const encoded = encode(input);
26
+ decode(encoded);
27
+ }).toThrow(expected);
28
+ } else {
29
+ const encoded = encode(input);
30
+ const decoded = decode(encoded);
31
+ expect(decoded).toEqual(expected);
32
+ }
33
+ });
34
+ });
@@ -0,0 +1,27 @@
1
+ import { EXPECTED, INPUTS } from './.data.js';
2
+ import { encode, decode } from '../../dist/index.js';
3
+
4
+ it.each(Object.keys(INPUTS))('%s', (name) => {
5
+ const input = INPUTS[name];
6
+ const expected = EXPECTED[name] ?? input;
7
+ if (expected instanceof Error) {
8
+ expect(() => {
9
+ const encoded = encode(input);
10
+ decode(encoded);
11
+ }).toThrow(expected);
12
+ } else {
13
+ const encoded = encode(input);
14
+ const decoded = decode(encoded);
15
+ expect(decoded).toEqual(expected);
16
+ }
17
+ });
18
+
19
+ test('decode ArrayBuffer', () => {
20
+ const obj = { a: 1, b: undefined, c: { d: 2, e: undefined, f: null } };
21
+ expect(decode(encode(obj).buffer)).toEqual(obj);
22
+ });
23
+
24
+ test('decode Int8Array', () => {
25
+ const obj = { a: 1, b: undefined, c: { d: 2, e: undefined, f: null } };
26
+ expect(decode(new Int8Array(encode(obj).buffer))).toEqual(obj);
27
+ });
@@ -0,0 +1,20 @@
1
+ import { Readable } from 'node:stream';
2
+ import { encode as encodeStream, decode as decodeStream } from '../../dist/stream/index.js';
3
+ import { EXPECTED, INPUTS } from './.data.js';
4
+
5
+ describe('stream', () => {
6
+ it.each(Object.keys(INPUTS))('%s', async (name) => {
7
+ const input = INPUTS[name];
8
+ const expected = EXPECTED[name] ?? input;
9
+ if (expected instanceof Error) {
10
+ await expect(async () => {
11
+ const encoded = await encodeStream(input).toArray();
12
+ const decoded = await decodeStream(Readable.from(encoded));
13
+ expect(decoded).toEqual(expected);
14
+ }).rejects.toThrow(expected);
15
+ } else {
16
+ const decoded = await decodeStream(encodeStream(input));
17
+ expect(decoded).toEqual(expected);
18
+ }
19
+ });
20
+ });