From b81c165bea384532e816621a5e5e4495cbfc39ce Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Wed, 7 Jun 2017 14:15:18 -0700 Subject: [PATCH] Add SelectionModel tests --- src/SelectionManager.ts | 3 + src/SelectionModel.test.ts | 133 +++++++++++++++++++++++++++++++++++++ src/SelectionModel.ts | 13 ++-- 3 files changed, 142 insertions(+), 7 deletions(-) create mode 100644 src/SelectionModel.test.ts diff --git a/src/SelectionManager.ts b/src/SelectionManager.ts index 4a72dd87..cc7a2303 100644 --- a/src/SelectionManager.ts +++ b/src/SelectionManager.ts @@ -82,6 +82,9 @@ export class SelectionManager extends EventEmitter { */ private _dragScrollIntervalTimer: NodeJS.Timer; + /** + * The animation frame ID used for refreshing the selection. + */ private _refreshAnimationFrame: number; private _bufferTrimListener: any; diff --git a/src/SelectionModel.test.ts b/src/SelectionModel.test.ts new file mode 100644 index 00000000..f617772d --- /dev/null +++ b/src/SelectionModel.test.ts @@ -0,0 +1,133 @@ +/** + * @license MIT + */ +import { assert } from 'chai'; +import { ITerminal } from './Interfaces'; +import { SelectionModel } from './SelectionModel'; + +class TestSelectionModel extends SelectionModel { + constructor( + terminal: ITerminal + ) { + super(terminal); + } + + public areSelectionValuesReversed(): boolean { return this._areSelectionValuesReversed(); } +} + +describe('SelectionManager', () => { + let window: Window; + let document: Document; + + let terminal: ITerminal; + let model: TestSelectionModel; + + beforeEach(() => { + terminal = { cols: 80, rows: 2, ybase: 0 }; + model = new TestSelectionModel(terminal); + }); + + describe('clearSelection', () => { + it('should clear the final selection', () => { + model.selectionStart = [0, 0]; + model.selectionEnd = [10, 2]; + assert.deepEqual(model.finalSelectionStart, [0, 0]); + assert.deepEqual(model.finalSelectionEnd, [10, 2]); + model.clearSelection(); + assert.deepEqual(model.finalSelectionStart, null); + assert.deepEqual(model.finalSelectionEnd, null); + }); + }); + + describe('_areSelectionValuesReversed', () => { + it('should return true when the selection end is before selection start', () => { + model.selectionStart = [1, 0]; + model.selectionEnd = [0, 0]; + assert.equal(model.areSelectionValuesReversed(), true); + model.selectionStart = [10, 2]; + model.selectionEnd = [0, 0]; + assert.equal(model.areSelectionValuesReversed(), true); + }); + it('should return false when the selection end is after selection start', () => { + model.selectionStart = [0, 0]; + model.selectionEnd = [1, 0]; + assert.equal(model.areSelectionValuesReversed(), false); + model.selectionStart = [0, 0]; + model.selectionEnd = [10, 2]; + assert.equal(model.areSelectionValuesReversed(), false); + }); + }); + + describe('onTrim', () => { + it('should trim a portion of the selection when a part of it is trimmed', () => { + model.selectionStart = [0, 0]; + model.selectionEnd = [10, 2]; + model.onTrim(1); + assert.deepEqual(model.finalSelectionStart, [0, 0]); + assert.deepEqual(model.finalSelectionEnd, [10, 1]); + model.onTrim(1); + assert.deepEqual(model.finalSelectionStart, [0, 0]); + assert.deepEqual(model.finalSelectionEnd, [10, 0]); + }); + it('should clear selection when it is trimmed in its entirety', () => { + model.selectionStart = [0, 0]; + model.selectionEnd = [10, 0]; + model.onTrim(1); + assert.deepEqual(model.finalSelectionStart, null); + assert.deepEqual(model.finalSelectionEnd, null); + }); + }); + + describe('finalSelectionStart', () => { + it('should return the start of the buffer if select all is active', () => { + model.isSelectAllActive = true; + assert.deepEqual(model.finalSelectionStart, [0, 0]); + }); + it('should return selection start if there is no selection end', () => { + model.selectionStart = [2, 2]; + assert.deepEqual(model.finalSelectionStart, [2, 2]); + }); + it('should return selection end if values are reversed', () => { + model.selectionStart = [2, 2]; + model.selectionEnd = [3, 2]; + assert.deepEqual(model.finalSelectionStart, [2, 2]); + model.selectionEnd = [1, 2]; + assert.deepEqual(model.finalSelectionStart, [1, 2]); + }); + }); + + describe('finalSelectionEnd', () => { + it('should return the end of the buffer if select all is active', () => { + model.isSelectAllActive = true; + assert.deepEqual(model.finalSelectionEnd, [79, 1]); + }); + it('should return null if there is no selection start', () => { + assert.equal(model.finalSelectionEnd, null); + model.selectionEnd = [1, 2]; + assert.equal(model.finalSelectionEnd, null); + }); + it('should return selection start + length if there is no selection end', () => { + model.selectionStart = [2, 2]; + model.selectionStartLength = 2; + assert.deepEqual(model.finalSelectionEnd, [4, 2]); + }); + it('should return selection start + length if values are reversed', () => { + model.selectionStart = [2, 2]; + model.selectionStartLength = 2; + model.selectionEnd = [2, 1]; + assert.deepEqual(model.finalSelectionEnd, [4, 2]); + }); + it('should return selection start + length if selection end is inside the start selection', () => { + model.selectionStart = [2, 2]; + model.selectionStartLength = 2; + model.selectionEnd = [3, 2]; + assert.deepEqual(model.finalSelectionEnd, [4, 2]); + }); + it('should return selection end if selection end is after selection start + length', () => { + model.selectionStart = [2, 2]; + model.selectionStartLength = 2; + model.selectionEnd = [5, 2]; + assert.deepEqual(model.finalSelectionEnd, [5, 2]); + }); + }); +}); diff --git a/src/SelectionModel.ts b/src/SelectionModel.ts index a7f0069f..03c99abe 100644 --- a/src/SelectionModel.ts +++ b/src/SelectionModel.ts @@ -87,7 +87,7 @@ export class SelectionModel { /** * Returns whether the selection start and end are reversed. */ - private _areSelectionValuesReversed(): boolean { + protected _areSelectionValuesReversed(): boolean { const start = this.selectionStart; const end = this.selectionEnd; return start[1] > end[1] || (start[1] === end[1] && start[0] > end[0]); @@ -101,21 +101,20 @@ export class SelectionModel { public onTrim(amount: number): boolean { // Adjust the selection position based on the trimmed amount. if (this.selectionStart) { - this.selectionStart[0] -= amount; + this.selectionStart[1] -= amount; } if (this.selectionEnd) { - this.selectionEnd[0] -= amount; + this.selectionEnd[1] -= amount; } // The selection has moved off the buffer, clear it. - if (this.selectionEnd && this.selectionEnd[0] < 0) { - this.selectionStart = null; - this.selectionEnd = null; + if (this.selectionEnd && this.selectionEnd[1] < 0) { + this.clearSelection(); return true; } // If the selection start is trimmed, ensure the start column is 0. - if (this.selectionStart && this.selectionStart[0] < 0) { + if (this.selectionStart && this.selectionStart[1] < 0) { this.selectionStart[1] = 0; } return false;