register functions by prefix/intermediate/final bytes
This commit is contained in:
@@ -4,7 +4,7 @@
|
||||
*/
|
||||
import { assert } from 'chai';
|
||||
import { DcsParser, DcsHandlerFactory } from 'common/parser/DcsParser';
|
||||
import { IDcsHandler, IParams } from 'common/parser/Types';
|
||||
import { IDcsHandler, IParams, IFunctionIdentifier } from 'common/parser/Types';
|
||||
import { utf32ToString, StringToUtf32 } from 'common/input/TextDecoder';
|
||||
import { Params } from 'common/parser/Params';
|
||||
import { PAYLOAD_LIMIT } from 'common/parser/Constants';
|
||||
@@ -16,10 +16,47 @@ function toUtf32(s: string): Uint32Array {
|
||||
return utf32.subarray(0, length);
|
||||
}
|
||||
|
||||
function identifier(id: IFunctionIdentifier): number {
|
||||
let res = 0;
|
||||
if (id.prefix) {
|
||||
if (id.prefix.length > 1) {
|
||||
throw new Error('only one byte as prefix supported');
|
||||
}
|
||||
res = id.prefix.charCodeAt(0);
|
||||
if (res && 0x3c > res || res > 0x3f) {
|
||||
throw new Error('prefix must be in range 0x3c .. 0x3f');
|
||||
}
|
||||
}
|
||||
if (id.intermediates) {
|
||||
if (id.intermediates.length > 2) {
|
||||
throw new Error('only two bytes as intermediates are supported');
|
||||
}
|
||||
for (let i = 0; i < id.intermediates.length; ++i) {
|
||||
const intermediate = id.intermediates.charCodeAt(i);
|
||||
if (0x20 > intermediate || intermediate > 0x2f) {
|
||||
throw new Error('intermediate must be in range 0x20 .. 0x2f');
|
||||
}
|
||||
res <<= 8;
|
||||
res |= intermediate;
|
||||
}
|
||||
}
|
||||
if (id.final.length !== 1) {
|
||||
throw new Error('final must be a single byte');
|
||||
}
|
||||
const finalCode = id.final.charCodeAt(0);
|
||||
if (0x40 > finalCode || finalCode > 0x7e) {
|
||||
throw new Error('final must be in range 0x40 .. 0x7e');
|
||||
}
|
||||
res <<= 8;
|
||||
res |= finalCode;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
class TestHandler implements IDcsHandler {
|
||||
constructor(public output: any[], public msg: string, public returnFalse: boolean = false) {}
|
||||
hook(collect: string, params: IParams, flag: number): void {
|
||||
this.output.push([this.msg, 'HOOK', params.toArray(), collect, flag]);
|
||||
hook(params: IParams): void {
|
||||
this.output.push([this.msg, 'HOOK', params.toArray()]);
|
||||
}
|
||||
put(data: Uint32Array, start: number, end: number): void {
|
||||
this.output.push([this.msg, 'PUT', utf32ToString(data, start, end)]);
|
||||
@@ -39,16 +76,16 @@ describe('DcsParser', () => {
|
||||
reports = [];
|
||||
parser = new DcsParser();
|
||||
parser.setDcsHandlerFallback((id, action, data) => {
|
||||
if (data.params) {
|
||||
data.params = data.params.toArray();
|
||||
if (action === 'HOOK') {
|
||||
data = data.toArray();
|
||||
}
|
||||
reports.push([id, action, data]);
|
||||
});
|
||||
});
|
||||
describe('handler registration', () => {
|
||||
it('setDcsHandler', () => {
|
||||
parser.setDcsHandler('+p', new TestHandler(reports, 'th'));
|
||||
parser.hook('+', Params.fromArray([1, 2, 3]), 'p'.charCodeAt(0));
|
||||
parser.setDcsHandler(identifier({intermediates: '+', final: 'p'}), new TestHandler(reports, 'th'));
|
||||
parser.hook(identifier({intermediates: '+', final: 'p'}), Params.fromArray([1, 2, 3]));
|
||||
let data = toUtf32('Here comes');
|
||||
parser.put(data, 0, data.length);
|
||||
data = toUtf32('the mouse!');
|
||||
@@ -56,16 +93,16 @@ describe('DcsParser', () => {
|
||||
parser.unhook(true);
|
||||
assert.deepEqual(reports, [
|
||||
// messages from TestHandler
|
||||
['th', 'HOOK', [1, 2, 3], '+', 'p'.charCodeAt(0)],
|
||||
['th', 'HOOK', [1, 2, 3]],
|
||||
['th', 'PUT', 'Here comes'],
|
||||
['th', 'PUT', 'the mouse!'],
|
||||
['th', 'UNHOOK', true]
|
||||
]);
|
||||
});
|
||||
it('clearDcsHandler', () => {
|
||||
parser.setDcsHandler('+p', new TestHandler(reports, 'th'));
|
||||
parser.clearDcsHandler('+p');
|
||||
parser.hook('+', Params.fromArray([1, 2, 3]), 'p'.charCodeAt(0));
|
||||
parser.setDcsHandler(identifier({intermediates: '+', final: 'p'}), new TestHandler(reports, 'th'));
|
||||
parser.clearDcsHandler(identifier({intermediates: '+', final: 'p'}));
|
||||
parser.hook(identifier({intermediates: '+', final: 'p'}), Params.fromArray([1, 2, 3]));
|
||||
let data = toUtf32('Here comes');
|
||||
parser.put(data, 0, data.length);
|
||||
data = toUtf32('the mouse!');
|
||||
@@ -73,24 +110,24 @@ describe('DcsParser', () => {
|
||||
parser.unhook(true);
|
||||
assert.deepEqual(reports, [
|
||||
// messages from fallback handler
|
||||
['+p', 'HOOK', {collect: '+', params: [1, 2, 3], flag: 'p'.charCodeAt(0)}],
|
||||
['+p', 'PUT', 'Here comes'],
|
||||
['+p', 'PUT', 'the mouse!'],
|
||||
['+p', 'UNHOOK', true]
|
||||
[identifier({intermediates: '+', final: 'p'}), 'HOOK', [1, 2, 3]],
|
||||
[identifier({intermediates: '+', final: 'p'}), 'PUT', 'Here comes'],
|
||||
[identifier({intermediates: '+', final: 'p'}), 'PUT', 'the mouse!'],
|
||||
[identifier({intermediates: '+', final: 'p'}), 'UNHOOK', true]
|
||||
]);
|
||||
});
|
||||
it('addDcsHandler', () => {
|
||||
parser.setDcsHandler('+p', new TestHandler(reports, 'th1'));
|
||||
parser.addDcsHandler('+p', new TestHandler(reports, 'th2'));
|
||||
parser.hook('+', Params.fromArray([1, 2, 3]), 'p'.charCodeAt(0));
|
||||
parser.setDcsHandler(identifier({intermediates: '+', final: 'p'}), new TestHandler(reports, 'th1'));
|
||||
parser.addDcsHandler(identifier({intermediates: '+', final: 'p'}), new TestHandler(reports, 'th2'));
|
||||
parser.hook(identifier({intermediates: '+', final: 'p'}), Params.fromArray([1, 2, 3]));
|
||||
let data = toUtf32('Here comes');
|
||||
parser.put(data, 0, data.length);
|
||||
data = toUtf32('the mouse!');
|
||||
parser.put(data, 0, data.length);
|
||||
parser.unhook(true);
|
||||
assert.deepEqual(reports, [
|
||||
['th2', 'HOOK', [1, 2, 3], '+', 'p'.charCodeAt(0)],
|
||||
['th1', 'HOOK', [1, 2, 3], '+', 'p'.charCodeAt(0)],
|
||||
['th2', 'HOOK', [1, 2, 3]],
|
||||
['th1', 'HOOK', [1, 2, 3]],
|
||||
['th2', 'PUT', 'Here comes'],
|
||||
['th1', 'PUT', 'Here comes'],
|
||||
['th2', 'PUT', 'the mouse!'],
|
||||
@@ -100,17 +137,17 @@ describe('DcsParser', () => {
|
||||
]);
|
||||
});
|
||||
it('addDcsHandler with return false', () => {
|
||||
parser.setDcsHandler('+p', new TestHandler(reports, 'th1'));
|
||||
parser.addDcsHandler('+p', new TestHandler(reports, 'th2', true));
|
||||
parser.hook('+', Params.fromArray([1, 2, 3]), 'p'.charCodeAt(0));
|
||||
parser.setDcsHandler(identifier({intermediates: '+', final: 'p'}), new TestHandler(reports, 'th1'));
|
||||
parser.addDcsHandler(identifier({intermediates: '+', final: 'p'}), new TestHandler(reports, 'th2', true));
|
||||
parser.hook(identifier({intermediates: '+', final: 'p'}), Params.fromArray([1, 2, 3]));
|
||||
let data = toUtf32('Here comes');
|
||||
parser.put(data, 0, data.length);
|
||||
data = toUtf32('the mouse!');
|
||||
parser.put(data, 0, data.length);
|
||||
parser.unhook(true);
|
||||
assert.deepEqual(reports, [
|
||||
['th2', 'HOOK', [1, 2, 3], '+', 'p'.charCodeAt(0)],
|
||||
['th1', 'HOOK', [1, 2, 3], '+', 'p'.charCodeAt(0)],
|
||||
['th2', 'HOOK', [1, 2, 3]],
|
||||
['th1', 'HOOK', [1, 2, 3]],
|
||||
['th2', 'PUT', 'Here comes'],
|
||||
['th1', 'PUT', 'Here comes'],
|
||||
['th2', 'PUT', 'the mouse!'],
|
||||
@@ -120,17 +157,17 @@ describe('DcsParser', () => {
|
||||
]);
|
||||
});
|
||||
it('dispose handlers', () => {
|
||||
parser.setDcsHandler('+p', new TestHandler(reports, 'th1'));
|
||||
const dispo = parser.addDcsHandler('+p', new TestHandler(reports, 'th2', true));
|
||||
parser.setDcsHandler(identifier({intermediates: '+', final: 'p'}), new TestHandler(reports, 'th1'));
|
||||
const dispo = parser.addDcsHandler(identifier({intermediates: '+', final: 'p'}), new TestHandler(reports, 'th2', true));
|
||||
dispo.dispose();
|
||||
parser.hook('+', Params.fromArray([1, 2, 3]), 'p'.charCodeAt(0));
|
||||
parser.hook(identifier({intermediates: '+', final: 'p'}), Params.fromArray([1, 2, 3]));
|
||||
let data = toUtf32('Here comes');
|
||||
parser.put(data, 0, data.length);
|
||||
data = toUtf32('the mouse!');
|
||||
parser.put(data, 0, data.length);
|
||||
parser.unhook(true);
|
||||
assert.deepEqual(reports, [
|
||||
['th1', 'HOOK', [1, 2, 3], '+', 'p'.charCodeAt(0)],
|
||||
['th1', 'HOOK', [1, 2, 3]],
|
||||
['th1', 'PUT', 'Here comes'],
|
||||
['th1', 'PUT', 'the mouse!'],
|
||||
['th1', 'UNHOOK', true]
|
||||
@@ -139,8 +176,8 @@ describe('DcsParser', () => {
|
||||
});
|
||||
describe('DcsHandlerFactory', () => {
|
||||
it('should be called once on end(true)', () => {
|
||||
parser.setDcsHandler('+p', new DcsHandlerFactory((params, data) => reports.push([params.toArray(), data])));
|
||||
parser.hook('+', Params.fromArray([1, 2, 3]), 'p'.charCodeAt(0));
|
||||
parser.setDcsHandler(identifier({intermediates: '+', final: 'p'}), new DcsHandlerFactory((data, params) => reports.push([params.toArray(), data])));
|
||||
parser.hook(identifier({intermediates: '+', final: 'p'}), Params.fromArray([1, 2, 3]));
|
||||
let data = toUtf32('Here comes');
|
||||
parser.put(data, 0, data.length);
|
||||
data = toUtf32(' the mouse!');
|
||||
@@ -149,8 +186,8 @@ describe('DcsParser', () => {
|
||||
assert.deepEqual(reports, [[[1, 2, 3], 'Here comes the mouse!']]);
|
||||
});
|
||||
it('should not be called on end(false)', () => {
|
||||
parser.setDcsHandler('+p', new DcsHandlerFactory((params, data) => reports.push([params.toArray(), data])));
|
||||
parser.hook('+', Params.fromArray([1, 2, 3]), 'p'.charCodeAt(0));
|
||||
parser.setDcsHandler(identifier({intermediates: '+', final: 'p'}), new DcsHandlerFactory((data, params) => reports.push([params.toArray(), data])));
|
||||
parser.hook(identifier({intermediates: '+', final: 'p'}), Params.fromArray([1, 2, 3]));
|
||||
let data = toUtf32('Here comes');
|
||||
parser.put(data, 0, data.length);
|
||||
data = toUtf32(' the mouse!');
|
||||
@@ -159,9 +196,9 @@ describe('DcsParser', () => {
|
||||
assert.deepEqual(reports, []);
|
||||
});
|
||||
it('should be disposable', () => {
|
||||
parser.setDcsHandler('+p', new DcsHandlerFactory((params, data) => reports.push(['one', params.toArray(), data])));
|
||||
const dispo = parser.addDcsHandler('+p', new DcsHandlerFactory((params, data) => reports.push(['two', params.toArray(), data])));
|
||||
parser.hook('+', Params.fromArray([1, 2, 3]), 'p'.charCodeAt(0));
|
||||
parser.setDcsHandler(identifier({intermediates: '+', final: 'p'}), new DcsHandlerFactory((data, params) => reports.push(['one', params.toArray(), data])));
|
||||
const dispo = parser.addDcsHandler(identifier({intermediates: '+', final: 'p'}), new DcsHandlerFactory((data, params) => reports.push(['two', params.toArray(), data])));
|
||||
parser.hook(identifier({intermediates: '+', final: 'p'}), Params.fromArray([1, 2, 3]));
|
||||
let data = toUtf32('Here comes');
|
||||
parser.put(data, 0, data.length);
|
||||
data = toUtf32(' the mouse!');
|
||||
@@ -169,7 +206,7 @@ describe('DcsParser', () => {
|
||||
parser.unhook(true);
|
||||
assert.deepEqual(reports, [['two', [1, 2, 3], 'Here comes the mouse!']]);
|
||||
dispo.dispose();
|
||||
parser.hook('+', Params.fromArray([1, 2, 3]), 'p'.charCodeAt(0));
|
||||
parser.hook(identifier({intermediates: '+', final: 'p'}), Params.fromArray([1, 2, 3]));
|
||||
data = toUtf32('some other');
|
||||
parser.put(data, 0, data.length);
|
||||
data = toUtf32(' data');
|
||||
@@ -178,9 +215,9 @@ describe('DcsParser', () => {
|
||||
assert.deepEqual(reports, [['two', [1, 2, 3], 'Here comes the mouse!'], ['one', [1, 2, 3], 'some other data']]);
|
||||
});
|
||||
it('should respect return false', () => {
|
||||
parser.setDcsHandler('+p', new DcsHandlerFactory((params, data) => reports.push(['one', params.toArray(), data])));
|
||||
parser.addDcsHandler('+p', new DcsHandlerFactory((params, data) => { reports.push(['two', params.toArray(), data]); return false; }));
|
||||
parser.hook('+', Params.fromArray([1, 2, 3]), 'p'.charCodeAt(0));
|
||||
parser.setDcsHandler(identifier({intermediates: '+', final: 'p'}), new DcsHandlerFactory((data, params) => reports.push(['one', params.toArray(), data])));
|
||||
parser.addDcsHandler(identifier({intermediates: '+', final: 'p'}), new DcsHandlerFactory((data, params) => { reports.push(['two', params.toArray(), data]); return false; }));
|
||||
parser.hook(identifier({intermediates: '+', final: 'p'}), Params.fromArray([1, 2, 3]));
|
||||
let data = toUtf32('Here comes');
|
||||
parser.put(data, 0, data.length);
|
||||
data = toUtf32(' the mouse!');
|
||||
@@ -190,8 +227,8 @@ describe('DcsParser', () => {
|
||||
});
|
||||
it('should work up to payload limit', function(): void {
|
||||
this.timeout(10000);
|
||||
parser.setDcsHandler('+p', new DcsHandlerFactory((params, data) => reports.push([params.toArray(), data])));
|
||||
parser.hook('+', Params.fromArray([1, 2, 3]), 'p'.charCodeAt(0));
|
||||
parser.setDcsHandler(identifier({intermediates: '+', final: 'p'}), new DcsHandlerFactory((data, params) => reports.push([params.toArray(), data])));
|
||||
parser.hook(identifier({intermediates: '+', final: 'p'}), Params.fromArray([1, 2, 3]));
|
||||
const data = toUtf32('A'.repeat(1000));
|
||||
for (let i = 0; i < PAYLOAD_LIMIT; i += 1000) {
|
||||
parser.put(data, 0, data.length);
|
||||
@@ -201,8 +238,8 @@ describe('DcsParser', () => {
|
||||
});
|
||||
it('should abort for payload limit +1', function(): void {
|
||||
this.timeout(10000);
|
||||
parser.setDcsHandler('+p', new DcsHandlerFactory((params, data) => reports.push([params.toArray(), data])));
|
||||
parser.hook('+', Params.fromArray([1, 2, 3]), 'p'.charCodeAt(0));
|
||||
parser.setDcsHandler(identifier({intermediates: '+', final: 'p'}), new DcsHandlerFactory((data, params) => reports.push([params.toArray(), data])));
|
||||
parser.hook(identifier({intermediates: '+', final: 'p'}), Params.fromArray([1, 2, 3]));
|
||||
let data = toUtf32('A'.repeat(1000));
|
||||
for (let i = 0; i < PAYLOAD_LIMIT; i += 1000) {
|
||||
parser.put(data, 0, data.length);
|
||||
|
||||
Reference in New Issue
Block a user