From 82aaef29f14e3c3006bccd759cbcba5ded46d614 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Breitbart?= Date: Fri, 26 Jul 2019 15:07:24 +0200 Subject: [PATCH] dcs parser tests --- src/common/parser/DcsParser.test.ts | 180 ++++++++++++++++++++++ src/common/parser/DcsParser.ts | 2 +- src/common/parser/EscapeSequenceParser.ts | 2 +- src/common/parser/Types.d.ts | 2 +- 4 files changed, 183 insertions(+), 3 deletions(-) create mode 100644 src/common/parser/DcsParser.test.ts diff --git a/src/common/parser/DcsParser.test.ts b/src/common/parser/DcsParser.test.ts new file mode 100644 index 00000000..d45d2770 --- /dev/null +++ b/src/common/parser/DcsParser.test.ts @@ -0,0 +1,180 @@ +/** + * Copyright (c) 2019 The xterm.js authors. All rights reserved. + * @license MIT + */ +import { assert } from 'chai'; +import { DcsParser, DcsHandlerFactory } from 'common/parser/DcsParser'; +import { IDcsHandler, IParams } from 'common/parser/Types'; +import { utf32ToString, StringToUtf32 } from 'common/input/TextDecoder'; +import { Params } from 'common/parser/Params'; + +function toUtf32(s: string): Uint32Array { + const utf32 = new Uint32Array(s.length); + const decoder = new StringToUtf32(); + const length = decoder.decode(s, utf32); + return utf32.subarray(0, length); +} + +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]); + } + put(data: Uint32Array, start: number, end: number): void { + this.output.push([this.msg, 'PUT', utf32ToString(data, start, end)]); + } + unhook(success: boolean): void | boolean { + this.output.push([this.msg, 'UNHOOK', success]); + if (this.returnFalse) { + return false; + } + } +} + +describe('DcsParser', () => { + let parser: DcsParser; + let reports: any[] = []; + beforeEach(() => { + reports = []; + parser = new DcsParser(); + parser.setDcsHandlerFallback((id, action, data) => { + if (data.params) { + data.params = data.params.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)); + 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, [ + // messages from TestHandler + ['th', 'HOOK', [1, 2, 3], '+', 'p'.charCodeAt(0)], + ['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)); + 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, [ + // 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] + ]); + }); + 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)); + 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', 'PUT', 'Here comes'], + ['th1', 'PUT', 'Here comes'], + ['th2', 'PUT', 'the mouse!'], + ['th1', 'PUT', 'the mouse!'], + ['th2', 'UNHOOK', true], + ['th1', 'UNHOOK', false] // false due being already handled by th2! + ]); + }); + 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)); + 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', 'PUT', 'Here comes'], + ['th1', 'PUT', 'Here comes'], + ['th2', 'PUT', 'the mouse!'], + ['th1', 'PUT', 'the mouse!'], + ['th2', 'UNHOOK', true], + ['th1', 'UNHOOK', true] // true since th2 indicated to keep bubbling + ]); + }); + it('dispose handlers', () => { + parser.setDcsHandler('+p', new TestHandler(reports, 'th1')); + const dispo = parser.addDcsHandler('+p', new TestHandler(reports, 'th2', true)); + dispo.dispose(); + parser.hook('+', Params.fromArray([1, 2, 3]), 'p'.charCodeAt(0)); + 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', 'PUT', 'Here comes'], + ['th1', 'PUT', 'the mouse!'], + ['th1', 'UNHOOK', true] + ]); + }); + }); + describe('DcsHandlerFactory', () => { + it('should be called once on end(true)', () => { + parser.setDcsHandler('+p', new DcsHandlerFactory((params, data) => reports.push([params, data]))); + parser.hook('+', Params.fromArray([1, 2, 3]), 'p'.charCodeAt(0)); + 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, [[[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, data]))); + parser.hook('+', Params.fromArray([1, 2, 3]), 'p'.charCodeAt(0)); + let data = toUtf32('Here comes'); + parser.put(data, 0, data.length); + data = toUtf32(' the mouse!'); + parser.put(data, 0, data.length); + parser.unhook(false); + assert.deepEqual(reports, []); + }); + it('should be disposable', () => { + parser.setDcsHandler('+p', new DcsHandlerFactory((params, data) => reports.push(['one', params, data]))); + const dispo = parser.addDcsHandler('+p', new DcsHandlerFactory((params, data) => reports.push(['two', params, data]))); + parser.hook('+', Params.fromArray([1, 2, 3]), 'p'.charCodeAt(0)); + 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, [['two', [1, 2, 3], 'Here comes the mouse!']]); + dispo.dispose(); + parser.hook('+', Params.fromArray([1, 2, 3]), 'p'.charCodeAt(0)); + data = toUtf32('some other'); + parser.put(data, 0, data.length); + data = toUtf32(' data'); + parser.put(data, 0, data.length); + parser.unhook(true); + assert.deepEqual(reports, [['two', [1, 2, 3], 'Here comes the mouse!'], ['one', [1, 2, 3], 'some other data']]); + }); + }); +}); diff --git a/src/common/parser/DcsParser.ts b/src/common/parser/DcsParser.ts index 46f5d501..aef8c694 100644 --- a/src/common/parser/DcsParser.ts +++ b/src/common/parser/DcsParser.ts @@ -43,7 +43,7 @@ export class DcsParser implements IDcsParser { if (this._handlers[collectAndFlag]) delete this._handlers[collectAndFlag]; } - public setOscHandlerFallback(handler: DcsFallbackHandler): void { + public setDcsHandlerFallback(handler: DcsFallbackHandler): void { this._handlerFb = handler; } diff --git a/src/common/parser/EscapeSequenceParser.ts b/src/common/parser/EscapeSequenceParser.ts index dcd242f5..4d30a549 100644 --- a/src/common/parser/EscapeSequenceParser.ts +++ b/src/common/parser/EscapeSequenceParser.ts @@ -371,7 +371,7 @@ export class EscapeSequenceParser extends Disposable implements IEscapeSequenceP this._dcsParser.clearDcsHandler(collectAndFlag); } setDcsHandlerFallback(handler: DcsFallbackHandler): void { - this._dcsParser.setOscHandlerFallback(handler); + this._dcsParser.setDcsHandlerFallback(handler); } setErrorHandler(callback: (state: IParsingState) => IParsingState): void { diff --git a/src/common/parser/Types.d.ts b/src/common/parser/Types.d.ts index 33849c4e..4ae7ebcc 100644 --- a/src/common/parser/Types.d.ts +++ b/src/common/parser/Types.d.ts @@ -191,7 +191,7 @@ export interface IDcsParser extends IDisposable { addDcsHandler(collectAndFlag: string, handler: IDcsHandler): IDisposable; setDcsHandler(collectAndFlag: string, handler: IDcsHandler): void; clearDcsHandler(collectAndFlag: string): void; - setOscHandlerFallback(handler: DcsFallbackHandler): void; + setDcsHandlerFallback(handler: DcsFallbackHandler): void; reset(): void; hook(collect: string, params: IParams, flag: number): void; put(data: Uint32Array, start: number, end: number): void;