Support multi-cursor in test harness

Now you can just put multiple cursors into the 'start' or 'end' of a test, a few examples are in multicursor.test.ts.
I've also done some general refactor of testSimplifier.ts to make it more straightforward.
ALSO, a slight refactor in VimState (making isMultiCursor a function of cursors.length)
Fixes #4582
This commit is contained in:
Jason Fields 2020-02-24 23:48:24 -05:00
parent c915239068
commit d80c8c8550
12 changed files with 196 additions and 187 deletions

View File

@ -511,7 +511,7 @@ class CommandEsc extends BaseCommand {
}
if (vimState.currentMode === Mode.Normal && vimState.isMultiCursor) {
vimState.isMultiCursor = false;
vimState.collapseCursors();
}
if (vimState.currentMode === Mode.EasyMotionMode) {
@ -533,10 +533,6 @@ class CommandEsc extends BaseCommand {
await vimState.setCurrentMode(Mode.Normal);
if (!vimState.isMultiCursor) {
vimState.cursors = [vimState.cursors[0]];
}
return vimState;
}
}
@ -2649,7 +2645,6 @@ class CommandInsertNewLineAbove extends BaseCommand {
}
vimState.cursors = vimState.cursors.reverse();
vimState.isFakeMultiCursor = true;
vimState.isMultiCursor = true;
return vimState;
}
}
@ -2689,7 +2684,6 @@ class CommandInsertNewLineBefore extends BaseCommand {
}
vimState.cursors = vimState.cursors.reverse();
vimState.isFakeMultiCursor = true;
vimState.isMultiCursor = true;
return vimState;
}
}
@ -3594,7 +3588,6 @@ class ActionGoToInsertVisualBlockMode extends BaseCommand {
public async exec(position: Position, vimState: VimState): Promise<VimState> {
await vimState.setCurrentMode(Mode.Insert);
vimState.isMultiCursor = true;
vimState.isFakeMultiCursor = true;
for (const { line, start } of TextEditor.iterateLinesInBlock(vimState)) {
@ -3626,7 +3619,6 @@ class ActionChangeInVisualBlockMode extends BaseCommand {
}
await vimState.setCurrentMode(Mode.Insert);
vimState.isMultiCursor = true;
vimState.isFakeMultiCursor = true;
for (const { start } of TextEditor.iterateLinesInBlock(vimState)) {
@ -3656,7 +3648,6 @@ class ActionChangeToEOLInVisualBlockMode extends BaseCommand {
}
await vimState.setCurrentMode(Mode.Insert);
vimState.isMultiCursor = true;
vimState.isFakeMultiCursor = true;
for (const { end } of TextEditor.iterateLinesInBlock(vimState)) {
@ -3681,7 +3672,6 @@ abstract class ActionGoToInsertVisualLineModeCommand extends BaseCommand {
public async exec(position: Position, vimState: VimState): Promise<VimState> {
await vimState.setCurrentMode(Mode.Insert);
vimState.isMultiCursor = true;
vimState.isFakeMultiCursor = true;
vimState.cursors = [];
@ -3778,7 +3768,6 @@ class ActionGoToInsertVisualBlockModeAppend extends BaseCommand {
public async exec(position: Position, vimState: VimState): Promise<VimState> {
await vimState.setCurrentMode(Mode.Insert);
vimState.isMultiCursor = true;
vimState.isFakeMultiCursor = true;
for (const { line, end } of TextEditor.iterateLinesInBlock(vimState)) {

View File

@ -102,8 +102,7 @@ class CommandEscInsertMode extends BaseCommand {
}
if (vimState.isFakeMultiCursor) {
vimState.cursors = [vimState.cursors[0]];
vimState.isMultiCursor = false;
vimState.collapseCursors();
vimState.isFakeMultiCursor = false;
}
return vimState;

View File

@ -162,10 +162,6 @@ export class ModeHandler implements vscode.Disposable {
return;
}
if (e.selections.length === 1) {
this.vimState.isMultiCursor = false;
}
if (isStatusBarMode(this.vimState.currentMode)) {
return;
}

View File

@ -50,12 +50,6 @@ export class VimState implements vscode.Disposable {
*/
public lastKeyPressedTimestamp = 0;
/**
* Are multiple cursors currently present?
*/
// TODO: why isn't this a function?
public isMultiCursor = false;
/**
* Is the multicursor something like visual block "multicursor", where
* natively in vim there would only be one cursor whose changes were applied
@ -174,7 +168,6 @@ export class VimState implements vscode.Disposable {
}
this._cursors = Array.from(map.values());
this.isMultiCursor = this._cursors.length > 1;
}
/**
@ -188,6 +181,16 @@ export class VimState implements vscode.Disposable {
this._cursorsInitialState = Object.assign([], value);
}
/**
* Are multiple cursors currently present?
*/
public get isMultiCursor(): boolean {
return this.cursors.length > 1;
}
public collapseCursors(): void {
this.cursors = [this.cursors[0]];
}
public isRecordingMacro: boolean = false;
public isReplayingMacro: boolean = false;

View File

@ -139,6 +139,10 @@ export class TextEditor {
return vscode.window.activeTextEditor!.selection;
}
static getSelections(): vscode.Range[] {
return vscode.window.activeTextEditor!.selections;
}
static getText(selection?: vscode.Range): string {
return vscode.window.activeTextEditor!.document.getText(selection);
}

View File

@ -1940,8 +1940,8 @@ suite('Mode Normal', () => {
});
newTest({
title: 'can ctrl-a on an octal ',
start: ['07|'],
title: 'can ctrl-a on an octal',
start: ['0|7'],
keysPressed: '<C-a>',
end: ['01|0'],
});
@ -2309,10 +2309,10 @@ suite('Mode Normal', () => {
title: "Can 'D'elete the characters under multiple cursors until the end of the line",
start: [
'test aaa test aaa test aaa test |aaa test',
'test aaa test aaa test aaa test aaa test',
'test aaa test aaa test aaa test |aaa test',
],
keysPressed: '<C-alt+down>D<Esc>',
end: ['test aaa test aaa test aaa test| ', 'test aaa test aaa test aaa test '],
keysPressed: 'D',
end: ['test aaa test aaa test aaa test| ', 'test aaa test aaa test aaa test| '],
});
newTest({

View File

@ -1338,21 +1338,24 @@ suite('Mode Visual', () => {
title: 'multiline insert from bottom up selection',
start: ['111', '222', '333', '4|44', '555'],
keysPressed: 'vkkI_',
end: ['111', '2_|22', '_333', '_444', '555'],
end: ['111', '2_|22', '_|333', '_|444', '555'],
endMode: Mode.Insert,
});
newTest({
title: 'multiline insert from top down selection',
start: ['111', '2|22', '333', '444', '555'],
keysPressed: 'vjjI_',
end: ['111', '2_|22', '_333', '_444', '555'],
end: ['111', '2_|22', '_|333', '_|444', '555'],
endMode: Mode.Insert,
});
newTest({
title: 'skips blank lines',
start: ['111', '2|22', ' ', '444', '555'],
keysPressed: 'vjjI_',
end: ['111', '2_|22', ' ', '_444', '555'],
end: ['111', '2_|22', ' ', '_|444', '555'],
endMode: Mode.Insert,
});
});
@ -1361,21 +1364,24 @@ suite('Mode Visual', () => {
title: 'multiline append from bottom up selection',
start: ['111', '222', '333', '4|44', '555'],
keysPressed: 'vkkA_',
end: ['111', '222_|', '333_', '44_4', '555'],
end: ['111', '222_|', '333_|', '44_|4', '555'],
endMode: Mode.Insert,
});
newTest({
title: 'multiline append from top down selection',
start: ['111', '2|22', '333', '444', '555'],
keysPressed: 'vjjA_',
end: ['111', '222_|', '333_', '44_4', '555'],
end: ['111', '222_|', '333_|', '44_|4', '555'],
endMode: Mode.Insert,
});
newTest({
title: 'skips blank lines',
start: ['111', '2|22', ' ', '444', '555'],
keysPressed: 'vjjA_',
end: ['111', '222_|', ' ', '44_4', '555'],
end: ['111', '222_|', ' ', '44_|4', '555'],
endMode: Mode.Insert,
});
});

View File

@ -33,63 +33,64 @@ suite('Mode Visual Block', () => {
title: 'Can handle A forward select',
start: ['|test', 'test'],
keysPressed: 'l<C-v>ljA123',
end: ['tes123|t', 'tes123t'],
end: ['tes123|t', 'tes123|t'],
});
newTest({
title: 'Can handle A backwards select',
start: ['tes|t', 'test'],
keysPressed: 'h<C-v>hjA123',
end: ['tes123|t', 'tes123t'],
end: ['tes123|t', 'tes123|t'],
});
newTest({
title: 'Can handle I forward select',
start: ['|test', 'test'],
keysPressed: 'l<C-v>ljI123',
end: ['t123|est', 't123est'],
end: ['t123|est', 't123|est'],
});
newTest({
title: 'Can handle I backwards select',
start: ['tes|t', 'test'],
keysPressed: 'h<C-v>hjI123',
end: ['t123|est', 't123est'],
end: ['t123|est', 't123|est'],
});
newTest({
title: 'Can handle I with empty lines on first character (inserts on empty line)',
start: ['|test', '', 'test'],
keysPressed: '<C-v>lljjI123',
end: ['123|test', '123', '123test'],
end: ['123|test', '123|', '123|test'],
});
newTest({
title: 'Can handle I with empty lines on non-first character (does not insert on empty line)',
start: ['t|est', '', 'test'],
keysPressed: '<C-v>lljjI123',
end: ['t123|est', '', 't123est'],
end: ['t123|est', '', 't123|est'],
});
newTest({
title: 'Can handle c forward select',
start: ['|test', 'test'],
keysPressed: 'l<C-v>ljc123',
end: ['t123|t', 't123t'],
end: ['t123|t', 't123|t'],
});
newTest({
title: 'Can handle c backwards select',
start: ['tes|t', 'test'],
keysPressed: 'h<C-v>hjc123',
end: ['t123|t', 't123t'],
end: ['t123|t', 't123|t'],
});
newTest({
title: 'Can handle C',
start: ['tes|t', 'test'],
keysPressed: 'h<C-v>hjC123',
end: ['t123|', 't123'],
end: ['t123|', 't123|'],
endMode: Mode.Insert,
});
newTest({
@ -144,7 +145,7 @@ suite('Mode Visual Block', () => {
title: 'Properly add to end of lines j then $',
start: ['|Dog', 'Angry', 'Dog', 'Angry', 'Dog'],
keysPressed: '<C-v>4j$Aaa',
end: ['Dogaa|', 'Angryaa', 'Dogaa', 'Angryaa', 'Dogaa'],
end: ['Dogaa|', 'Angryaa|', 'Dogaa|', 'Angryaa|', 'Dogaa|'],
});
newTest({

View File

@ -441,21 +441,24 @@ suite('Mode Visual Line', () => {
title: 'multiline insert from bottom up selection',
start: ['111', '222', '333', '4|44', '555'],
keysPressed: 'VkkI_',
end: ['111', '_|222', '_333', '_444', '555'],
end: ['111', '_|222', '_|333', '_|444', '555'],
endMode: Mode.Insert,
});
newTest({
title: 'multiline insert from top down selection',
start: ['111', '2|22', '333', '444', '555'],
keysPressed: 'VjjI_',
end: ['111', '_|222', '_333', '_444', '555'],
end: ['111', '_|222', '_|333', '_|444', '555'],
endMode: Mode.Insert,
});
newTest({
title: 'skips blank lines',
start: ['111', '2|22', ' ', '444', '555'],
keysPressed: 'VjjI_',
end: ['111', '_|222', ' ', '_444', '555'],
end: ['111', '_|222', ' ', '_|444', '555'],
endMode: Mode.Insert,
});
});
@ -464,21 +467,24 @@ suite('Mode Visual Line', () => {
title: 'multiline append from bottom up selection',
start: ['111', '222', '333', '4|44', '555'],
keysPressed: 'VkkA_',
end: ['111', '222_|', '333_', '444_', '555'],
end: ['111', '222_|', '333_|', '444_|', '555'],
endMode: Mode.Insert,
});
newTest({
title: 'multiline append from top down selection',
start: ['111', '2|22', '333', '444', '555'],
keysPressed: 'VjjA_',
end: ['111', '222_|', '333_', '444_', '555'],
end: ['111', '222_|', '333_|', '444_|', '555'],
endMode: Mode.Insert,
});
newTest({
title: 'skips blank lines',
start: ['111', '2|22', ' ', '444', '555'],
keysPressed: 'VjjA_',
end: ['111', '222_|', ' ', '444_', '555'],
end: ['111', '222_|', ' ', '444_|', '555'],
endMode: Mode.Insert,
});
newTest({

View File

@ -2,9 +2,12 @@ import * as assert from 'assert';
import { getAndUpdateModeHandler } from '../extension';
import { ModeHandler } from '../src/mode/modeHandler';
import { assertEqualLines, cleanUpWorkspace, setupWorkspace } from './testUtils';
import { getTestingFunctions } from './testSimplifier';
import { Mode } from '../src/mode/mode';
suite('Multicursor', () => {
let modeHandler: ModeHandler;
const { newTest, newTestOnly, newTestSkip } = getTestingFunctions();
setup(async () => {
await setupWorkspace();
@ -24,7 +27,7 @@ suite('Multicursor', () => {
await modeHandler.handleMultipleKeyEvents(['<C-alt+down>']);
}
assert.strictEqual(modeHandler.vimState.cursors.length, 2, 'Cursor succesfully created.');
assert.strictEqual(modeHandler.vimState.cursors.length, 2, 'Cursor successfully created.');
await modeHandler.handleMultipleKeyEvents(['c', 'w', '3', '3', '<Esc>']);
assertEqualLines(['33', '33']);
});
@ -40,7 +43,7 @@ suite('Multicursor', () => {
await modeHandler.handleMultipleKeyEvents(['<C-alt+up>', '<C-alt+up>']);
}
assert.strictEqual(modeHandler.vimState.cursors.length, 3, 'Cursor succesfully created.');
assert.strictEqual(modeHandler.vimState.cursors.length, 3, 'Cursor successfully created.');
await modeHandler.handleMultipleKeyEvents(['c', 'w', '4', '4', '<Esc>']);
assertEqualLines(['44', '44', '44']);
});
@ -122,4 +125,61 @@ suite('Multicursor', () => {
assertEqualLines(['<div></div> asd', '<div></div>']);
assert.strictEqual(modeHandler.vimState.cursors.length, 2);
});
newTest({
title: 'dd works with multi-cursor',
start: ['on|e', 'two', 't|hree', 'four'],
keysPressed: 'dd',
end: ['|two', '|four'],
endMode: Mode.Normal,
});
// TODO - this actually doesn't work, but it should
// newTest({
// title: 'dab works with multi-cursor',
// start: ['(on|e)', 'two', '(thre|e', 'four)'],
// keysPressed: 'dd',
// end: ['|', 'two', '|'],
// endMode: Mode.Normal,
// });
newTest({
title: 'Vd works with multi-cursor',
start: ['on|e', 'two', 't|hree', 'four'],
keysPressed: 'dd',
end: ['|two', '|four'],
endMode: Mode.Normal,
});
newTest({
title: '<C-v>d works with multi-cursor',
start: ['|one', 'two', 't|hree', 'four'],
keysPressed: '<C-v>jld',
end: ['|e', 'o', 't|ee', 'fr'],
endMode: Mode.Normal,
});
newTest({
title: 'cw works with multi-cursor',
start: ['one |two three |four five'],
keysPressed: 'cw',
end: ['one | three | five'],
endMode: Mode.Insert,
});
newTest({
title: '<count>f<char> works with multi-cursor',
start: ['|apple. banana! cucumber!', '|date! eggplant! fig.'],
keysPressed: '2f!',
end: ['apple. banana! cucumber|!', 'date! eggplant|! fig.'],
endMode: Mode.Normal,
});
newTest({
title: 'o works with multi-cursor',
start: ['li|ne1', 'l|ine2'],
keysPressed: 'o',
end: ['line1', '|', 'line2', '|'],
endMode: Mode.Insert,
});
});

View File

@ -9,13 +9,15 @@ import { ModeHandler } from '../src/mode/modeHandler';
import { TextEditor } from '../src/textEditor';
import { assertEqualLines } from './testUtils';
import { globalState } from '../src/state/globalState';
import { Range } from '../src/common/motion/range';
import { RecordedState } from '../src/state/recordedState';
export function getTestingFunctions() {
const getNiceStack = (stack: string | undefined): string => {
return stack ? stack.split('\n').splice(2, 1).join('\n') : 'no stack available :(';
};
const newTest = (testObj: ITestObject): void => {
const newTest = (testObj: ITestParams): void => {
const stack = new Error().stack;
const niceStack = getNiceStack(stack);
@ -32,7 +34,7 @@ export function getTestingFunctions() {
);
};
const newTestOnly = (testObj: ITestObject): void => {
const newTestOnly = (testObj: ITestParams): void => {
console.log('!!! Running single test !!!');
const stack = new Error().stack;
const niceStack = getNiceStack(stack);
@ -50,7 +52,7 @@ export function getTestingFunctions() {
);
};
const newTestSkip = (testObj: ITestObject): void => {
const newTestSkip = (testObj: ITestParams): void => {
const stack = new Error().stack;
const niceStack = getNiceStack(stack);
@ -74,113 +76,35 @@ export function getTestingFunctions() {
};
}
interface ITestObject {
// TODO: add start mode, start/end registers, end status bar
interface ITestParams {
/** What behavior does this test enforce? */
title: string;
/** Lines in the document at the test's start */
start: string[];
/** Simulated user input; control characters like <Esc> will be parsed */
keysPressed: string;
/** Expected lines in the document when the test ends */
end: string[];
/** Expected mode when the test ends */
endMode?: Mode;
/** Expected jumps */
jumps?: string[];
}
class TestObjectHelper {
/**
* Position that the test says that the cursor starts at.
*/
startPosition = new Position(0, 0);
/**
* Position that the test says that the cursor ends at.
*/
endPosition = new Position(0, 0);
private _isValid = false;
private _testObject: ITestObject;
constructor(_testObject: ITestObject) {
this._testObject = _testObject;
this._parse(_testObject);
}
public get isValid(): boolean {
return this._isValid;
}
private _setStartCursorPosition(lines: string[]): boolean {
const result = this._getCursorPosition(lines);
this.startPosition = result.position;
return result.success;
}
private _setEndCursorPosition(lines: string[]): boolean {
const result = this._getCursorPosition(lines);
this.endPosition = result.position;
return result.success;
}
private _getCursorPosition(lines: string[]): { success: boolean; position: Position } {
const ret = { success: false, position: new Position(0, 0) };
for (let i = 0; i < lines.length; i++) {
const columnIdx = lines[i].indexOf('|');
if (columnIdx >= 0) {
ret.position = new Position(i, columnIdx);
ret.success = true;
function parseCursors(lines: string[]): Position[] {
let cursors = [] as Position[];
for (let line = 0; line < lines.length; line++) {
let cursorsOnLine = 0;
for (let column = 0; column < lines[line].length; column++) {
if (lines[line][column] === '|') {
cursors.push(new Position(line, column - cursorsOnLine));
cursorsOnLine++;
}
}
return ret;
}
private _parse(t: ITestObject): void {
this._isValid = true;
if (!this._setStartCursorPosition(t.start)) {
this._isValid = false;
}
if (!this._setEndCursorPosition(t.end)) {
this._isValid = false;
}
}
public asVimInputText(): string[] {
const ret = 'i' + this._testObject.start.join('\n').replace('|', '');
return ret.split('');
}
public asVimOutputText(): string[] {
const ret = this._testObject.end.slice(0);
ret[this.endPosition.line] = ret[this.endPosition.line].replace('|', '');
return ret;
}
/**
* Returns a sequence of Vim movement characters 'hjkl' as a string array
* which will move the cursor to the start position given in the test.
*/
public getKeyPressesToMoveToStartPosition(): string[] {
let ret = '';
const linesToMove = this.startPosition.line;
const cursorPosAfterEsc =
this._testObject.start[this._testObject.start.length - 1].replace('|', '').length - 1;
const numCharsInCursorStartLine =
this._testObject.start[this.startPosition.line].replace('|', '').length - 1;
const charactersToMove = this.startPosition.character;
if (linesToMove > 0) {
ret += Array(linesToMove + 1).join('j');
} else if (linesToMove < 0) {
ret += Array(Math.abs(linesToMove) + 1).join('k');
}
if (charactersToMove > 0) {
ret += Array(charactersToMove + 1).join('l');
} else if (charactersToMove < 0) {
ret += Array(Math.abs(charactersToMove) + 1).join('h');
}
return ret.split('');
}
return cursors;
}
/**
@ -230,80 +154,98 @@ function tokenizeKeySequence(sequence: string): string[] {
return result;
}
async function testIt(modeHandler: ModeHandler, testObj: ITestObject): Promise<void> {
async function testIt(modeHandler: ModeHandler, testParams: ITestParams): Promise<void> {
modeHandler.vimState.editor = vscode.window.activeTextEditor!;
const helper = new TestObjectHelper(testObj);
const jumpTracker = globalState.jumpTracker;
// Find the cursors in the start/end strings
const cursorStartPositions = parseCursors(testParams.start);
const expectedCursorPositions = parseCursors(testParams.end);
assert(cursorStartPositions.length > 0, "Missing '|' in test object's start.");
assert(expectedCursorPositions.length > 0, "Missing '|' in test object's end.");
// Don't try this at home, kids.
(modeHandler as any).vimState.cursorPosition = new Position(0, 0);
await modeHandler.handleKeyEvent('<Esc>');
// Take the cursor characters out of the start/end strings
testParams.start = testParams.start.map((line) => line.replace('|', ''));
testParams.end = testParams.end.map((line) => line.replace('|', ''));
// Insert all the text as a single action.
await modeHandler.vimState.editor.edit((builder) => {
builder.insert(new Position(0, 0), testObj.start.join('\n').replace('|', ''));
builder.insert(new Position(0, 0), testParams.start.join('\n'));
});
await modeHandler.handleMultipleKeyEvents(['<Esc>', 'g', 'g']);
// Since we bypassed VSCodeVim to add text,
// we need to tell the history tracker that we added it.
modeHandler.vimState.historyTracker.addChange();
modeHandler.vimState.historyTracker.finishCurrentStep();
// move cursor to start position using 'hjkl'
await modeHandler.handleMultipleKeyEvents(helper.getKeyPressesToMoveToStartPosition());
modeHandler.handleMultipleKeyEvents(['<Esc>', '<Esc>']);
// Move cursors to starting positions
modeHandler.vimState.recordedState = new RecordedState();
modeHandler.vimState.cursors = cursorStartPositions.map((pos) => new Range(pos, pos));
modeHandler.updateView(modeHandler.vimState);
Globals.mockModeHandler = modeHandler;
let keysPressed = testObj.keysPressed;
let keysPressed = testParams.keysPressed;
if (process.platform === 'win32') {
keysPressed = keysPressed.replace(/\\n/g, '\\r\\n');
}
const jumpTracker = globalState.jumpTracker;
jumpTracker.clearJumps();
// Assumes key presses are single characters for now
await modeHandler.handleMultipleKeyEvents(tokenizeKeySequence(keysPressed));
// Check valid test object input
assert(helper.isValid, "Missing '|' in test object.");
// Check given end output is correct
const lines = helper.asVimOutputText();
assertEqualLines(lines);
assertEqualLines(testParams.end);
// Check final cursor position
const actualPosition = Position.FromVSCodePosition(TextEditor.getSelection().start);
const expectedPosition = helper.endPosition;
assert.strictEqual(actualPosition.line, expectedPosition.line, 'Cursor LINE position is wrong.');
assert.strictEqual(
actualPosition.character,
expectedPosition.character,
'Cursor CHARACTER position is wrong.'
// Check final positions of all cursors
const actualCursorPositions = TextEditor.getSelections().map((sel) =>
Position.FromVSCodePosition(sel.start)
);
assert.strictEqual(
actualCursorPositions.length,
expectedCursorPositions.length,
'Wrong number of cursors'
);
for (let i = 0; i < actualCursorPositions.length; i++) {
const actual = actualCursorPositions[i];
const expected = expectedCursorPositions[i];
assert.deepStrictEqual(
{
line: actual.line,
character: actual.character,
},
{
line: expected.line,
character: expected.character,
},
`Cursor #${i + 1}'s position is wrong.`
);
}
// endMode: check end mode is correct if given
if (testObj.endMode !== undefined) {
if (testParams.endMode !== undefined) {
const actualMode = Mode[modeHandler.currentMode].toUpperCase();
const expectedMode = Mode[testObj.endMode].toUpperCase();
const expectedMode = Mode[testParams.endMode].toUpperCase();
assert.strictEqual(actualMode, expectedMode, "Didn't enter correct mode.");
}
// jumps: check jumps are correct if given
if (testObj.jumps !== undefined) {
if (testParams.jumps !== undefined) {
assert.deepEqual(
jumpTracker.jumps.map((j) => lines[j.position.line] || '<MISSING>'),
testObj.jumps.map((t) => t.replace('|', '')),
jumpTracker.jumps.map((j) => testParams.end[j.position.line] || '<MISSING>'),
testParams.jumps.map((t) => t.replace('|', '')),
'Incorrect jumps found'
);
const stripBar = (text: string | undefined) => (text ? text.replace('|', '') : text);
const actualJumpPosition =
(jumpTracker.currentJump && lines[jumpTracker.currentJump.position.line]) || '<FRONT>';
const expectedJumpPosition = stripBar(testObj.jumps.find((t) => t.includes('|'))) || '<FRONT>';
(jumpTracker.currentJump && testParams.end[jumpTracker.currentJump.position.line]) ||
'<FRONT>';
const expectedJumpPosition =
stripBar(testParams.jumps.find((t) => t.includes('|'))) || '<FRONT>';
assert.deepEqual(
actualJumpPosition.toString(),
@ -313,4 +255,4 @@ async function testIt(modeHandler: ModeHandler, testObj: ITestObject): Promise<v
}
}
export { ITestObject, testIt };
export { ITestParams as ITestObject, testIt };

View File

@ -76,6 +76,9 @@ export async function WaitForEditorsToClose(numExpectedEditors: number = 0): Pro
}
}
/**
* Asserts that the contents of the active editor matches what's given
*/
export function assertEqualLines(expectedLines: string[]) {
for (let i = 0; i < expectedLines.length; i++) {
const expected = expectedLines[i];
@ -83,7 +86,7 @@ export function assertEqualLines(expectedLines: string[]) {
assert.strictEqual(
actual,
expected,
`Content does not match; Expected=${expected}. Actual=${actual}.`
`Content of line ${i + 1} does not match; Expected=${expected}. Actual=${actual}.`
);
}