157 lines
5.0 KiB
TypeScript
157 lines
5.0 KiB
TypeScript
import { assert } from 'chai';
|
|
import { Base64Decoder } from './base64.wasm';
|
|
|
|
// eslint-disable-next-line
|
|
declare const Buffer: any;
|
|
|
|
|
|
// some helpers
|
|
function toBs(bytes: Uint8Array): string {
|
|
let bs = '';
|
|
for (let i = 0; i < bytes.length; ++i) bs += String.fromCharCode(bytes[i]);
|
|
return bs;
|
|
}
|
|
function fromBs(bs: string): Uint8Array {
|
|
const r = new Uint8Array(bs.length);
|
|
for (let i = 0; i < r.length; ++i) r[i] = bs.charCodeAt(i);
|
|
return r;
|
|
}
|
|
function encNative(bytes: Uint8Array): string {
|
|
return typeof Buffer !== 'undefined' ? Buffer.from(bytes).toString('base64') : btoa(toBs(bytes));
|
|
}
|
|
function rtrim(x: string, c: string): string {
|
|
let end = x.length - 1;
|
|
while (c.indexOf(x[end]) >= 0) end -= 1;
|
|
return x.slice(0, end + 1);
|
|
}
|
|
const MAP = new Uint8Array(
|
|
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
|
|
.split('')
|
|
.map(el => el.charCodeAt(0))
|
|
);
|
|
|
|
|
|
describe('Base64Decoder', () => {
|
|
describe('decoding', () => {
|
|
it('single bytes', function() {
|
|
this.timeout(20000);
|
|
const dec = new Base64Decoder(0);
|
|
for (let i = 0; i < 256; ++i) {
|
|
dec.init(1);
|
|
const inp = new Uint8Array([i]);
|
|
const data = fromBs(encNative(inp));
|
|
assert.strictEqual(dec.put(data, 0, data.length), 0);
|
|
assert.strictEqual(dec.end(), 0);
|
|
assert.deepEqual(dec.data8, inp);
|
|
}
|
|
});
|
|
for (let a = 0; a < 256; ++a) {
|
|
it(`1+2 bytes (${a})`, function() {
|
|
const dec = new Base64Decoder(0);
|
|
for (let b = 0; b < 256; ++b) {
|
|
dec.init(2);
|
|
const inp = new Uint8Array([a, b]);
|
|
const data = fromBs(encNative(inp));
|
|
assert.strictEqual(dec.put(data, 0, data.length), 0);
|
|
assert.strictEqual(dec.end(), 0);
|
|
assert.deepEqual(dec.data8, inp);
|
|
}
|
|
});
|
|
}
|
|
for (let a = 0; a < 256; ++a) {
|
|
it(`2+3 bytes (${a})`, function() {
|
|
const dec = new Base64Decoder(0);
|
|
for (let b = 0; b < 256; ++b) {
|
|
dec.init(3);
|
|
const inp = new Uint8Array([0, a, b]);
|
|
const data = fromBs(encNative(inp));
|
|
assert.strictEqual(dec.put(data, 0, data.length), 0);
|
|
assert.strictEqual(dec.end(), 0);
|
|
assert.deepEqual(dec.data8, inp);
|
|
}
|
|
});
|
|
}
|
|
for (let a = 0; a < 256; ++a) {
|
|
it(`3+4 bytes (${a})`, function() {
|
|
const dec = new Base64Decoder(0);
|
|
for (let b = 0; b < 256; ++b) {
|
|
dec.init(4);
|
|
const inp = new Uint8Array([0, 0, a, b]);
|
|
const data = fromBs(encNative(inp));
|
|
assert.strictEqual(dec.put(data, 0, data.length), 0);
|
|
assert.strictEqual(dec.end(), 0);
|
|
assert.deepEqual(dec.data8, inp);
|
|
}
|
|
});
|
|
}
|
|
it('padding', () => {
|
|
const dec = new Base64Decoder(0);
|
|
const d = fromBs('Hello, here comes the mouse');
|
|
const encData = [];
|
|
const encDataTrimmed = [];
|
|
for (let i = 1; i < d.length; ++i) {
|
|
encData.push(encNative(d.slice(0, i)));
|
|
encDataTrimmed.push(rtrim(encNative(d.slice(0, i)), '='));
|
|
}
|
|
for (let i = 0; i < encData.length; ++i) {
|
|
// with padding
|
|
dec.init(i + 1);
|
|
let enc = fromBs(encData[i]);
|
|
assert.strictEqual(dec.put(enc, 0, enc.length), 0);
|
|
assert.strictEqual(dec.end(), 0);
|
|
assert.deepEqual(dec.data8, d.slice(0, i + 1));
|
|
// w'o padding
|
|
dec.init(i + 1);
|
|
enc = fromBs(encDataTrimmed[i]);
|
|
assert.strictEqual(dec.put(enc, 0, enc.length), 0);
|
|
assert.strictEqual(dec.end(), 0);
|
|
assert.deepEqual(dec.data8, d.slice(0, i + 1));
|
|
}
|
|
});
|
|
it('exit on false byte', function() {
|
|
this.timeout(20000);
|
|
const dec = new Base64Decoder(0);
|
|
for (let pos = 0; pos < 8; ++pos) {
|
|
const inp = new Uint8Array([65, 65, 65, 65, 65, 65, 65, 65]);
|
|
for (let i = 0; i < 256; ++i) {
|
|
dec.release();
|
|
dec.init(6);
|
|
inp[pos] = i;
|
|
dec.put(inp, 0, 8);
|
|
assert.strictEqual(dec.end(), MAP.includes(i) ? 0 : 1);
|
|
}
|
|
}
|
|
});
|
|
});
|
|
describe('memory', () => {
|
|
it('always release (keepSize 0)', () => {
|
|
const dec = new Base64Decoder(0);
|
|
dec.init(16);
|
|
dec.put(fromBs('A'.repeat(16)), 0, 16);
|
|
dec.end();
|
|
assert.strictEqual(dec.data8.length, 12);
|
|
dec.release();
|
|
assert.strictEqual(dec.data8.length, 0);
|
|
assert.isNull((dec as any)._mem);
|
|
});
|
|
it('keep 1 page (keepSize 65536)', () => {
|
|
const dec = new Base64Decoder(65536);
|
|
dec.init(384);
|
|
dec.put(fromBs('A'.repeat(512)), 0, 512);
|
|
dec.end();
|
|
assert.strictEqual(dec.data8.length, 384);
|
|
dec.release();
|
|
assert.strictEqual(dec.data8.length, 0);
|
|
assert.isNotNull((dec as any)._mem);
|
|
// grow to 2 pages + free afterwards
|
|
dec.init(65536);
|
|
dec.put(fromBs('A'.repeat(65536)), 0, 65536);
|
|
dec.end();
|
|
assert.strictEqual(dec.data8.length, 49152);
|
|
dec.release();
|
|
assert.strictEqual(dec.data8.length, 0);
|
|
assert.isNull((dec as any)._mem);
|
|
});
|
|
});
|
|
});
|