Increase test coverage
All checks were successful
timw4mail/scroll/pipeline/head This commit looks good
All checks were successful
timw4mail/scroll/pipeline/head This commit looks good
This commit is contained in:
parent
82bcc72d21
commit
cf80dce335
@ -2,6 +2,7 @@ import Ansi, * as _Ansi from './ansi.ts';
|
|||||||
import Buffer from './buffer.ts';
|
import Buffer from './buffer.ts';
|
||||||
import Document from './document.ts';
|
import Document from './document.ts';
|
||||||
import Editor from './editor.ts';
|
import Editor from './editor.ts';
|
||||||
|
import { highlightToColor, HighlightType } from './highlight.ts';
|
||||||
import Position from './position.ts';
|
import Position from './position.ts';
|
||||||
import Row from './row.ts';
|
import Row from './row.ts';
|
||||||
|
|
||||||
@ -10,7 +11,8 @@ import { defaultTerminalSize, SCROLL_TAB_SIZE } from './config.ts';
|
|||||||
import { getTestRunner } from './runtime.ts';
|
import { getTestRunner } from './runtime.ts';
|
||||||
|
|
||||||
const {
|
const {
|
||||||
assertEquals,
|
assertStrictEquals: assertEquals,
|
||||||
|
assertEquals: assertLooseEquals,
|
||||||
assertExists,
|
assertExists,
|
||||||
assertInstanceOf,
|
assertInstanceOf,
|
||||||
assertNotEquals,
|
assertNotEquals,
|
||||||
@ -20,6 +22,203 @@ const {
|
|||||||
testSuite,
|
testSuite,
|
||||||
} = await getTestRunner();
|
} = await getTestRunner();
|
||||||
|
|
||||||
|
const THIS_FILE = './src/common/all_test.ts';
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// Helper Function Tests
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
const fnTest = () => {
|
||||||
|
const {
|
||||||
|
some,
|
||||||
|
none,
|
||||||
|
arrayInsert,
|
||||||
|
noop,
|
||||||
|
posSub,
|
||||||
|
minSub,
|
||||||
|
maxAdd,
|
||||||
|
ord,
|
||||||
|
strChars,
|
||||||
|
ctrlKey,
|
||||||
|
isControl,
|
||||||
|
isAscii,
|
||||||
|
isAsciiDigit,
|
||||||
|
strlen,
|
||||||
|
truncate,
|
||||||
|
} = Fn;
|
||||||
|
|
||||||
|
return {
|
||||||
|
'some()': () => {
|
||||||
|
assertFalse(some(null));
|
||||||
|
assertFalse(some(void 0));
|
||||||
|
assertFalse(some(undefined));
|
||||||
|
assertTrue(some(0));
|
||||||
|
assertTrue(some(false));
|
||||||
|
},
|
||||||
|
'none()': () => {
|
||||||
|
assertTrue(none(null));
|
||||||
|
assertTrue(none(void 0));
|
||||||
|
assertTrue(none(undefined));
|
||||||
|
assertFalse(none(0));
|
||||||
|
assertFalse(none(false));
|
||||||
|
},
|
||||||
|
'arrayInsert() strings': () => {
|
||||||
|
const a = ['😺', '😸', '😹'];
|
||||||
|
const b = arrayInsert(a, 1, 'x');
|
||||||
|
const c = ['😺', 'x', '😸', '😹'];
|
||||||
|
assertLooseEquals(b, c);
|
||||||
|
|
||||||
|
const d = arrayInsert(c, 17, 'y');
|
||||||
|
const e = ['😺', 'x', '😸', '😹', 'y'];
|
||||||
|
assertLooseEquals(d, e);
|
||||||
|
|
||||||
|
assertLooseEquals(arrayInsert([], 0, 'foo'), ['foo']);
|
||||||
|
},
|
||||||
|
'arrayInsert() numbers': () => {
|
||||||
|
const a = [1, 3, 5];
|
||||||
|
const b = [1, 3, 4, 5];
|
||||||
|
assertLooseEquals(arrayInsert(a, 2, 4), b);
|
||||||
|
|
||||||
|
const c = [1, 2, 3, 4, 5];
|
||||||
|
assertLooseEquals(arrayInsert(b, 1, 2), c);
|
||||||
|
},
|
||||||
|
'noop fn': () => {
|
||||||
|
assertExists(noop);
|
||||||
|
assertEquals(noop(), undefined);
|
||||||
|
},
|
||||||
|
'posSub()': () => {
|
||||||
|
assertEquals(posSub(14, 15), 0);
|
||||||
|
assertEquals(posSub(15, 1), 14);
|
||||||
|
},
|
||||||
|
'minSub()': () => {
|
||||||
|
assertEquals(minSub(13, 25, -1), -1);
|
||||||
|
assertEquals(minSub(25, 13, 0), 12);
|
||||||
|
},
|
||||||
|
'maxAdd()': () => {
|
||||||
|
assertEquals(maxAdd(99, 99, 75), 75);
|
||||||
|
assertEquals(maxAdd(25, 74, 101), 99);
|
||||||
|
},
|
||||||
|
'ord()': () => {
|
||||||
|
// Invalid output
|
||||||
|
assertEquals(ord(''), 256);
|
||||||
|
|
||||||
|
// Valid output
|
||||||
|
assertEquals(ord('a'), 97);
|
||||||
|
},
|
||||||
|
'strChars() properly splits strings into unicode characters': () => {
|
||||||
|
assertLooseEquals(strChars('😺😸😹'), ['😺', '😸', '😹']);
|
||||||
|
},
|
||||||
|
'ctrlKey()': () => {
|
||||||
|
const ctrl_a = ctrlKey('a');
|
||||||
|
assertTrue(isControl(ctrl_a));
|
||||||
|
assertEquals(ctrl_a, String.fromCodePoint(0x01));
|
||||||
|
|
||||||
|
const invalid = ctrlKey('😺');
|
||||||
|
assertFalse(isControl(invalid));
|
||||||
|
assertEquals(invalid, '😺');
|
||||||
|
},
|
||||||
|
'isAscii()': () => {
|
||||||
|
assertTrue(isAscii('asjyverkjhsdf1928374'));
|
||||||
|
assertFalse(isAscii('😺acalskjsdf'));
|
||||||
|
assertFalse(isAscii('ab😺ac'));
|
||||||
|
},
|
||||||
|
'isAsciiDigit()': () => {
|
||||||
|
assertTrue(isAsciiDigit('1234567890'));
|
||||||
|
assertFalse(isAsciiDigit('A1'));
|
||||||
|
assertFalse(isAsciiDigit('/'));
|
||||||
|
assertFalse(isAsciiDigit(':'));
|
||||||
|
},
|
||||||
|
'isControl()': () => {
|
||||||
|
assertFalse(isControl('abc'));
|
||||||
|
assertTrue(isControl(String.fromCodePoint(0x01)));
|
||||||
|
assertFalse(isControl('😺'));
|
||||||
|
},
|
||||||
|
'strlen()': () => {
|
||||||
|
// Ascii length
|
||||||
|
assertEquals(strlen('abc'), 'abc'.length);
|
||||||
|
|
||||||
|
// Get number of visible unicode characters
|
||||||
|
assertEquals(strlen('😺😸😹'), 3);
|
||||||
|
assertNotEquals('😺😸😹'.length, strlen('😺😸😹'));
|
||||||
|
|
||||||
|
// Skin tone modifier + base character
|
||||||
|
assertEquals(strlen('🤰🏼'), 2);
|
||||||
|
assertNotEquals('🤰🏼'.length, strlen('🤰🏼'));
|
||||||
|
|
||||||
|
// This has 4 sub-characters, and 3 zero-width-joiners
|
||||||
|
assertEquals(strlen('👨👩👧👦'), 7);
|
||||||
|
assertNotEquals('👨👩👧👦'.length, strlen('👨👩👧👦'));
|
||||||
|
},
|
||||||
|
'truncate()': () => {
|
||||||
|
assertEquals(truncate('😺😸😹', 1), '😺');
|
||||||
|
assertEquals(truncate('😺😸😹', 5), '😺😸😹');
|
||||||
|
assertEquals(truncate('👨👩👧👦', 5), '👨👩👧');
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const readKeyTest = () => {
|
||||||
|
const { KeyCommand } = _Ansi;
|
||||||
|
const { readKey, ctrlKey } = Fn;
|
||||||
|
|
||||||
|
const encoder = new TextEncoder();
|
||||||
|
|
||||||
|
const testKeyMap = (codes: string[], expected: string) => {
|
||||||
|
codes.forEach((code) => {
|
||||||
|
assertEquals(readKey(encoder.encode(code)), expected);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
'empty input': () => {
|
||||||
|
assertEquals(readKey(new Uint8Array(0)), '');
|
||||||
|
},
|
||||||
|
'passthrough': () => {
|
||||||
|
// Ignore unhandled escape sequences
|
||||||
|
assertEquals(readKey(encoder.encode('\x1b[]')), '\x1b[]');
|
||||||
|
|
||||||
|
// Pass explicitly mapped values right through
|
||||||
|
assertEquals(
|
||||||
|
readKey(encoder.encode(KeyCommand.ArrowUp)),
|
||||||
|
KeyCommand.ArrowUp,
|
||||||
|
);
|
||||||
|
assertEquals(
|
||||||
|
readKey(encoder.encode(KeyCommand.Home)),
|
||||||
|
KeyCommand.Home,
|
||||||
|
);
|
||||||
|
assertEquals(
|
||||||
|
readKey(encoder.encode(KeyCommand.Delete)),
|
||||||
|
KeyCommand.Delete,
|
||||||
|
);
|
||||||
|
|
||||||
|
// And pass through whatever else
|
||||||
|
assertEquals(readKey(encoder.encode('foobaz')), 'foobaz');
|
||||||
|
},
|
||||||
|
|
||||||
|
'Esc': () => testKeyMap(['\x1b', ctrlKey('l')], KeyCommand.Escape),
|
||||||
|
'Backspace': () =>
|
||||||
|
testKeyMap(
|
||||||
|
[ctrlKey('h'), '\x7f'],
|
||||||
|
KeyCommand.Backspace,
|
||||||
|
),
|
||||||
|
'Home': () =>
|
||||||
|
testKeyMap(['\x1b[1~', '\x1b[7~', '\x1b[H', '\x1bOH'], KeyCommand.Home),
|
||||||
|
'End': () =>
|
||||||
|
testKeyMap(['\x1b[4~', '\x1b[8~', '\x1b[F', '\x1bOF'], KeyCommand.End),
|
||||||
|
'Enter': () => testKeyMap(['\n', '\r', '\v'], KeyCommand.Enter),
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const highlightToColorTest = {
|
||||||
|
'highlightToColor()': () => {
|
||||||
|
assertTrue(highlightToColor(HighlightType.Number).length > 0);
|
||||||
|
assertTrue(highlightToColor(HighlightType.Match).length > 0);
|
||||||
|
assertTrue(highlightToColor(HighlightType.None).length > 0);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// Tests by module
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
const ANSITest = () => {
|
const ANSITest = () => {
|
||||||
@ -100,6 +299,25 @@ const DocumentTest = {
|
|||||||
assertTrue(doc.isEmpty());
|
assertTrue(doc.isEmpty());
|
||||||
assertEquals(doc.row(0), null);
|
assertEquals(doc.row(0), null);
|
||||||
},
|
},
|
||||||
|
'.open': async () => {
|
||||||
|
const oldDoc = Document.default();
|
||||||
|
oldDoc.insert(Position.default(), 'foobarbaz');
|
||||||
|
assertTrue(oldDoc.dirty);
|
||||||
|
assertEquals(oldDoc.numRows, 1);
|
||||||
|
|
||||||
|
const doc = await oldDoc.open(THIS_FILE);
|
||||||
|
assertFalse(doc.dirty);
|
||||||
|
assertFalse(doc.isEmpty());
|
||||||
|
assertTrue(doc.numRows > 1);
|
||||||
|
},
|
||||||
|
'.save': async () => {
|
||||||
|
const doc = await Document.default().open(THIS_FILE);
|
||||||
|
doc.insertNewline(Position.default());
|
||||||
|
assertTrue(doc.dirty);
|
||||||
|
|
||||||
|
await doc.save('test.file');
|
||||||
|
assertFalse(doc.dirty);
|
||||||
|
},
|
||||||
'.insertRow': () => {
|
'.insertRow': () => {
|
||||||
const doc = Document.default();
|
const doc = Document.default();
|
||||||
doc.insertRow(undefined, 'foobar');
|
doc.insertRow(undefined, 'foobar');
|
||||||
@ -130,11 +348,52 @@ const DocumentTest = {
|
|||||||
assertEquals(doc.numRows, 2);
|
assertEquals(doc.numRows, 2);
|
||||||
assertTrue(doc.dirty);
|
assertTrue(doc.dirty);
|
||||||
},
|
},
|
||||||
|
'.insertNewline': () => {
|
||||||
|
// Invalid insert location
|
||||||
|
const doc = Document.default();
|
||||||
|
doc.insertNewline(Position.at(0, 3));
|
||||||
|
assertFalse(doc.dirty);
|
||||||
|
assertTrue(doc.isEmpty());
|
||||||
|
|
||||||
|
// Add new empty row
|
||||||
|
const doc2 = Document.default();
|
||||||
|
doc2.insertNewline(Position.default());
|
||||||
|
assertTrue(doc2.dirty);
|
||||||
|
assertFalse(doc2.isEmpty());
|
||||||
|
|
||||||
|
// Split an existing line
|
||||||
|
const doc3 = Document.default();
|
||||||
|
doc3.insert(Position.default(), 'foobar');
|
||||||
|
doc3.insertNewline(Position.at(3, 0));
|
||||||
|
assertEquals(doc3.numRows, 2);
|
||||||
|
assertEquals(doc3.row(0)?.toString(), 'foo');
|
||||||
|
assertEquals(doc3.row(1)?.toString(), 'bar');
|
||||||
|
},
|
||||||
'.delete': () => {
|
'.delete': () => {
|
||||||
const doc = Document.default();
|
const doc = Document.default();
|
||||||
doc.insert(Position.default(), 'foobar');
|
doc.insert(Position.default(), 'foobar');
|
||||||
doc.delete(Position.at(3, 0));
|
doc.delete(Position.at(3, 0));
|
||||||
assertEquals(doc.row(0)?.toString(), 'fooar');
|
assertEquals(doc.row(0)?.toString(), 'fooar');
|
||||||
|
|
||||||
|
// Merge previous row
|
||||||
|
const doc2 = Document.default();
|
||||||
|
doc2.insertNewline(Position.default());
|
||||||
|
doc2.insert(Position.at(0, 1), 'foobar');
|
||||||
|
doc2.delete(Position.at(0, 1));
|
||||||
|
assertEquals(doc2.row(0)?.toString(), 'foobar');
|
||||||
|
|
||||||
|
// Merge next row
|
||||||
|
const doc3 = Document.default();
|
||||||
|
doc3.insertNewline(Position.default());
|
||||||
|
doc3.insert(Position.at(0, 1), 'foobar');
|
||||||
|
doc3.delete(Position.at(0, 0));
|
||||||
|
assertEquals(doc3.row(0)?.toString(), 'foobar');
|
||||||
|
|
||||||
|
// Invalid delete location
|
||||||
|
const doc4 = Document.default();
|
||||||
|
doc4.insert(Position.default(), 'foobar');
|
||||||
|
doc4.delete(Position.at(0, 1));
|
||||||
|
assertEquals(doc4.row(0)?.toString(), 'foobar');
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -145,6 +404,21 @@ const EditorTest = {
|
|||||||
const e = new Editor(defaultTerminalSize);
|
const e = new Editor(defaultTerminalSize);
|
||||||
assertInstanceOf(e, Editor);
|
assertInstanceOf(e, Editor);
|
||||||
},
|
},
|
||||||
|
'.open': async () => {
|
||||||
|
const e = new Editor(defaultTerminalSize);
|
||||||
|
await e.open(THIS_FILE);
|
||||||
|
assertInstanceOf(e, Editor);
|
||||||
|
},
|
||||||
|
'.processKeyPress - letters': async () => {
|
||||||
|
const e = new Editor(defaultTerminalSize);
|
||||||
|
const res = await e.processKeyPress('a');
|
||||||
|
assertTrue(res);
|
||||||
|
},
|
||||||
|
'.processKeyPress - ctrl-q': async () => {
|
||||||
|
const e = new Editor(defaultTerminalSize);
|
||||||
|
const res = await e.processKeyPress(Fn.ctrlKey('q'));
|
||||||
|
assertFalse(res);
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
@ -262,200 +536,21 @@ const RowTest = {
|
|||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
const fnTest = () => {
|
const SearchTest = {};
|
||||||
const {
|
|
||||||
some,
|
|
||||||
none,
|
|
||||||
arrayInsert,
|
|
||||||
noop,
|
|
||||||
posSub,
|
|
||||||
minSub,
|
|
||||||
maxAdd,
|
|
||||||
ord,
|
|
||||||
strChars,
|
|
||||||
ctrlKey,
|
|
||||||
isControl,
|
|
||||||
isAscii,
|
|
||||||
isAsciiDigit,
|
|
||||||
strlen,
|
|
||||||
truncate,
|
|
||||||
} = Fn;
|
|
||||||
|
|
||||||
return {
|
|
||||||
'some()': () => {
|
|
||||||
assertFalse(some(null));
|
|
||||||
assertFalse(some(void 0));
|
|
||||||
assertFalse(some(undefined));
|
|
||||||
assertTrue(some(0));
|
|
||||||
assertTrue(some(false));
|
|
||||||
},
|
|
||||||
'none()': () => {
|
|
||||||
assertTrue(none(null));
|
|
||||||
assertTrue(none(void 0));
|
|
||||||
assertTrue(none(undefined));
|
|
||||||
assertFalse(none(0));
|
|
||||||
assertFalse(none(false));
|
|
||||||
},
|
|
||||||
'arrayInsert() strings': () => {
|
|
||||||
const a = ['😺', '😸', '😹'];
|
|
||||||
const b = arrayInsert(a, 1, 'x');
|
|
||||||
const c = ['😺', 'x', '😸', '😹'];
|
|
||||||
assertEquals(b, c);
|
|
||||||
|
|
||||||
const d = arrayInsert(c, 17, 'y');
|
|
||||||
const e = ['😺', 'x', '😸', '😹', 'y'];
|
|
||||||
assertEquals(d, e);
|
|
||||||
|
|
||||||
assertEquals(arrayInsert([], 0, 'foo'), ['foo']);
|
|
||||||
},
|
|
||||||
'arrayInsert() numbers': () => {
|
|
||||||
const a = [1, 3, 5];
|
|
||||||
const b = [1, 3, 4, 5];
|
|
||||||
assertEquals(arrayInsert(a, 2, 4), b);
|
|
||||||
|
|
||||||
const c = [1, 2, 3, 4, 5];
|
|
||||||
assertEquals(arrayInsert(b, 1, 2), c);
|
|
||||||
},
|
|
||||||
'noop fn': () => {
|
|
||||||
assertExists(noop);
|
|
||||||
assertEquals(noop(), undefined);
|
|
||||||
},
|
|
||||||
'posSub()': () => {
|
|
||||||
assertEquals(posSub(14, 15), 0);
|
|
||||||
assertEquals(posSub(15, 1), 14);
|
|
||||||
},
|
|
||||||
'minSub()': () => {
|
|
||||||
assertEquals(minSub(13, 25, -1), -1);
|
|
||||||
assertEquals(minSub(25, 13, 0), 12);
|
|
||||||
},
|
|
||||||
'maxAdd()': () => {
|
|
||||||
assertEquals(maxAdd(99, 99, 75), 75);
|
|
||||||
assertEquals(maxAdd(25, 74, 101), 99);
|
|
||||||
},
|
|
||||||
'ord()': () => {
|
|
||||||
// Invalid output
|
|
||||||
assertEquals(ord(''), 256);
|
|
||||||
|
|
||||||
// Valid output
|
|
||||||
assertEquals(ord('a'), 97);
|
|
||||||
},
|
|
||||||
'strChars() properly splits strings into unicode characters': () => {
|
|
||||||
assertEquals(strChars('😺😸😹'), ['😺', '😸', '😹']);
|
|
||||||
},
|
|
||||||
'ctrlKey()': () => {
|
|
||||||
const ctrl_a = ctrlKey('a');
|
|
||||||
assertTrue(isControl(ctrl_a));
|
|
||||||
assertEquals(ctrl_a, String.fromCodePoint(0x01));
|
|
||||||
|
|
||||||
const invalid = ctrlKey('😺');
|
|
||||||
assertFalse(isControl(invalid));
|
|
||||||
assertEquals(invalid, '😺');
|
|
||||||
},
|
|
||||||
'isAscii()': () => {
|
|
||||||
assertTrue(isAscii('asjyverkjhsdf1928374'));
|
|
||||||
assertFalse(isAscii('😺acalskjsdf'));
|
|
||||||
assertFalse(isAscii('ab😺ac'));
|
|
||||||
},
|
|
||||||
'isAsciiDigit()': () => {
|
|
||||||
assertTrue(isAsciiDigit('1234567890'));
|
|
||||||
assertFalse(isAsciiDigit('A1'));
|
|
||||||
assertFalse(isAsciiDigit('/'));
|
|
||||||
assertFalse(isAsciiDigit(':'));
|
|
||||||
},
|
|
||||||
'isControl()': () => {
|
|
||||||
assertFalse(isControl('abc'));
|
|
||||||
assertTrue(isControl(String.fromCodePoint(0x01)));
|
|
||||||
assertFalse(isControl('😺'));
|
|
||||||
},
|
|
||||||
'strlen()': () => {
|
|
||||||
// Ascii length
|
|
||||||
assertEquals(strlen('abc'), 'abc'.length);
|
|
||||||
|
|
||||||
// Get number of visible unicode characters
|
|
||||||
assertEquals(strlen('😺😸😹'), 3);
|
|
||||||
assertNotEquals('😺😸😹'.length, strlen('😺😸😹'));
|
|
||||||
|
|
||||||
// Skin tone modifier + base character
|
|
||||||
assertEquals(strlen('🤰🏼'), 2);
|
|
||||||
assertNotEquals('🤰🏼'.length, strlen('🤰🏼'));
|
|
||||||
|
|
||||||
// This has 4 sub-characters, and 3 zero-width-joiners
|
|
||||||
assertEquals(strlen('👨👩👧👦'), 7);
|
|
||||||
assertNotEquals('👨👩👧👦'.length, strlen('👨👩👧👦'));
|
|
||||||
},
|
|
||||||
'truncate()': () => {
|
|
||||||
assertEquals(truncate('😺😸😹', 1), '😺');
|
|
||||||
assertEquals(truncate('😺😸😹', 5), '😺😸😹');
|
|
||||||
assertEquals(truncate('👨👩👧👦', 5), '👨👩👧');
|
|
||||||
},
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
const readKeyTest = () => {
|
|
||||||
const { KeyCommand } = _Ansi;
|
|
||||||
const { readKey, ctrlKey } = Fn;
|
|
||||||
|
|
||||||
const encoder = new TextEncoder();
|
|
||||||
|
|
||||||
const testKeyMap = (codes: string[], expected: string) => {
|
|
||||||
codes.forEach((code) => {
|
|
||||||
assertEquals(readKey(encoder.encode(code)), expected);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
return {
|
|
||||||
'empty input': () => {
|
|
||||||
assertEquals(readKey(new Uint8Array(0)), '');
|
|
||||||
},
|
|
||||||
'passthrough': () => {
|
|
||||||
// Ignore unhandled escape sequences
|
|
||||||
assertEquals(readKey(encoder.encode('\x1b[]')), '\x1b[]');
|
|
||||||
|
|
||||||
// Pass explicitly mapped values right through
|
|
||||||
assertEquals(
|
|
||||||
readKey(encoder.encode(KeyCommand.ArrowUp)),
|
|
||||||
KeyCommand.ArrowUp,
|
|
||||||
);
|
|
||||||
assertEquals(
|
|
||||||
readKey(encoder.encode(KeyCommand.Home)),
|
|
||||||
KeyCommand.Home,
|
|
||||||
);
|
|
||||||
assertEquals(
|
|
||||||
readKey(encoder.encode(KeyCommand.Delete)),
|
|
||||||
KeyCommand.Delete,
|
|
||||||
);
|
|
||||||
|
|
||||||
// And pass through whatever else
|
|
||||||
assertEquals(readKey(encoder.encode('foobaz')), 'foobaz');
|
|
||||||
},
|
|
||||||
|
|
||||||
'Esc': () => testKeyMap(['\x1b', ctrlKey('l')], KeyCommand.Escape),
|
|
||||||
'Backspace': () =>
|
|
||||||
testKeyMap(
|
|
||||||
[ctrlKey('h'), '\x7f'],
|
|
||||||
KeyCommand.Backspace,
|
|
||||||
),
|
|
||||||
'Home': () =>
|
|
||||||
testKeyMap(['\x1b[1~', '\x1b[7~', '\x1b[H', '\x1bOH'], KeyCommand.Home),
|
|
||||||
'End': () =>
|
|
||||||
testKeyMap(['\x1b[4~', '\x1b[8~', '\x1b[F', '\x1bOF'], KeyCommand.End),
|
|
||||||
'Enter': () => testKeyMap(['\n', '\r', '\v'], KeyCommand.Enter),
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// Test Suite Setup
|
// Test Suite Setup
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
testSuite({
|
testSuite({
|
||||||
|
fns: fnTest(),
|
||||||
|
highlightToColorTest,
|
||||||
|
'readKey()': readKeyTest(),
|
||||||
'ANSI utils': ANSITest(),
|
'ANSI utils': ANSITest(),
|
||||||
Buffer: BufferTest,
|
Buffer: BufferTest,
|
||||||
Document: DocumentTest,
|
Document: DocumentTest,
|
||||||
Editor: EditorTest,
|
Editor: EditorTest,
|
||||||
Position: PositionTest,
|
Position: PositionTest,
|
||||||
Row: RowTest,
|
Row: RowTest,
|
||||||
fns: fnTest(),
|
Search: SearchTest,
|
||||||
'readKey()': readKeyTest(),
|
|
||||||
});
|
});
|
||||||
|
@ -58,7 +58,7 @@ export class Document {
|
|||||||
/**
|
/**
|
||||||
* Save the current document
|
* Save the current document
|
||||||
*/
|
*/
|
||||||
public async save(filename: string) {
|
public async save(filename: string): Promise<void> {
|
||||||
const { file } = await getRuntime();
|
const { file } = await getRuntime();
|
||||||
|
|
||||||
await file.saveFile(filename, this.rowsToString());
|
await file.saveFile(filename, this.rowsToString());
|
||||||
@ -66,7 +66,7 @@ export class Document {
|
|||||||
this.dirty = false;
|
this.dirty = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public resetFind() {
|
public resetFind(): void {
|
||||||
this.#search = new Search();
|
this.#search = new Search();
|
||||||
this.#search.parent = this;
|
this.#search.parent = this;
|
||||||
}
|
}
|
||||||
@ -108,16 +108,23 @@ export class Document {
|
|||||||
this.dirty = true;
|
this.dirty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Insert a new line, splitting and/or creating a new row as needed
|
||||||
|
*/
|
||||||
public insertNewline(at: Position): void {
|
public insertNewline(at: Position): void {
|
||||||
if (at.y > this.numRows) {
|
if (at.y > this.numRows) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Just add a simple blank line
|
||||||
if (at.y === this.numRows) {
|
if (at.y === this.numRows) {
|
||||||
this.#rows.push(Row.default());
|
this.#rows.push(Row.default());
|
||||||
|
this.dirty = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Split the current row, and insert a new
|
||||||
|
// row with the leftovers
|
||||||
const newRow = this.#rows[at.y].split(at.x);
|
const newRow = this.#rows[at.y].split(at.x);
|
||||||
newRow.update();
|
newRow.update();
|
||||||
this.#rows = arrayInsert(this.#rows, at.y + 1, newRow);
|
this.#rows = arrayInsert(this.#rows, at.y + 1, newRow);
|
||||||
|
@ -337,6 +337,7 @@ class Editor {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Filter out any additional unwanted keyboard input
|
* Filter out any additional unwanted keyboard input
|
||||||
|
*
|
||||||
* @param input
|
* @param input
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
|
@ -4,7 +4,6 @@ const {
|
|||||||
assertEquals,
|
assertEquals,
|
||||||
assertExists,
|
assertExists,
|
||||||
assertInstanceOf,
|
assertInstanceOf,
|
||||||
AssertionError,
|
|
||||||
assertNotEquals,
|
assertNotEquals,
|
||||||
assertStrictEquals,
|
assertStrictEquals,
|
||||||
} = stdAssert;
|
} = stdAssert;
|
||||||
@ -24,21 +23,9 @@ const DenoTestBase: ITestBase = {
|
|||||||
assertInstanceOf,
|
assertInstanceOf,
|
||||||
assertNotEquals,
|
assertNotEquals,
|
||||||
assertStrictEquals,
|
assertStrictEquals,
|
||||||
assertTrue: function (actual: boolean): void {
|
assertTrue: (actual: boolean) => assertStrictEquals(actual, true),
|
||||||
if (actual !== true) {
|
assertFalse: (actual: boolean) => assertStrictEquals(actual, false),
|
||||||
throw new AssertionError(`actual: "${actual}" expected to be true"`);
|
assertNull: (actual: any) => assertEquals(actual, null),
|
||||||
}
|
|
||||||
},
|
|
||||||
assertFalse(actual: boolean): void {
|
|
||||||
if (actual !== false) {
|
|
||||||
throw new AssertionError(`actual: "${actual}" expected to be false"`);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
assertNull(actual: boolean): void {
|
|
||||||
if (actual !== null) {
|
|
||||||
throw new AssertionError(`actual: "${actual}" expected to be null"`);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
testSuite,
|
testSuite,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user