import { getTestRunner } from './runtime.ts'; import { Ansi, KeyCommand, readKey } from './ansi.ts'; import { Document, Row } from './document.ts'; import Buffer from './buffer.ts'; import { chars, ctrlKey, isAscii, isControl, noop, ord, strlen, truncate, } from './utils.ts'; import { Editor } from './editor.ts'; import { defaultTerminalSize } from './termios.ts'; const { assertEquals, assertExists, assertInstanceOf, assertNotEquals, assertFalse, assertTrue, testSuite, } = await getTestRunner(); const testObj = { 'ANSI::ANSI utils': { 'Ansi.moveCursor': () => { assertEquals(Ansi.moveCursor(1, 2), '\x1b[2;3H'); }, 'Ansi.moveCursorForward': () => { assertEquals(Ansi.moveCursorForward(2), '\x1b[2C'); }, 'Ansi.moveCursorDown': () => { assertEquals(Ansi.moveCursorDown(7), '\x1b[7B'); }, }, 'ANSI::readKey()': { 'readKey passthrough': () => { // Ignore unhandled escape sequences assertEquals(readKey('\x1b[]'), '\x1b[]'); // Pass explicitly mapped values right through assertEquals(readKey(KeyCommand.ArrowUp), KeyCommand.ArrowUp); assertEquals(readKey(KeyCommand.Home), KeyCommand.Home); assertEquals(readKey(KeyCommand.Delete), KeyCommand.Delete); }, 'readKey Home': () => { ['\x1b[1~', '\x1b[7~', '\x1b[H', '\x1bOH'].forEach((code) => { assertEquals(readKey(code), KeyCommand.Home); }); }, 'readKey End': () => { ['\x1b[4~', '\x1b[8~', '\x1b[F', '\x1bOF'].forEach((code) => { assertEquals(readKey(code), KeyCommand.End); }); }, }, Buffer: { 'Buffer exists': () => { const b = new Buffer(); assertInstanceOf(b, Buffer); assertEquals(b.strlen(), 0); }, 'Buffer.appendLine': () => { const b = new Buffer(); // Carriage return and line feed b.appendLine(); assertEquals(b.strlen(), 2); b.clear(); assertEquals(b.strlen(), 0); b.appendLine('foo'); assertEquals(b.strlen(), 5); }, 'Buffer.append': () => { const b = new Buffer(); b.append('foobar'); assertEquals(b.strlen(), 6); b.clear(); b.append('foobar', 3); assertEquals(b.strlen(), 3); }, 'Buffer.flush': async () => { const b = new Buffer(); b.appendLine('foobarbaz' + Ansi.ClearLine); assertEquals(b.strlen(), 14); await b.flush(); assertEquals(b.strlen(), 0); }, }, Document: { 'Document.empty': () => { const doc = Document.empty(); assertEquals(doc.numRows, 0); assertTrue(doc.isEmpty()); assertEquals(doc.row(0), null); }, 'Document.appendRow': () => { const doc = Document.empty(); doc.appendRow('foobar'); assertEquals(doc.numRows, 1); assertFalse(doc.isEmpty()); assertInstanceOf(doc.row(0), Row); }, }, 'Document::Row': { 'new Row': () => { const row = new Row(); assertEquals(row.toString(), ''); }, }, Editor: { 'new Editor': () => { const e = new Editor(defaultTerminalSize); assertInstanceOf(e, Editor); }, }, 'Util::Misc fns': { 'noop fn': () => { assertExists(noop); assertEquals(noop(), undefined); }, }, 'Util::String fns': { 'ord()': () => { // Invalid output assertEquals(ord(''), 256); // Valid output assertEquals(ord('a'), 97); }, 'chars() properly splits strings into unicode characters': () => { assertEquals(chars('😺😸😹'), ['😺', '😸', '😹']); }, 'ctrl_key()': () => { const ctrl_a = ctrlKey('a'); assertTrue(isControl(ctrl_a)); assertEquals(ctrl_a, String.fromCodePoint(0x01)); const invalid = ctrlKey('😺'); assertFalse(isControl(invalid)); assertEquals(invalid, '😺'); }, 'is_ascii()': () => { assertTrue(isAscii('asjyverkjhsdf1928374')); assertFalse(isAscii('😺acalskjsdf')); assertFalse(isAscii('ab😺ac')); }, 'is_control()': () => { 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), 'πŸ‘¨β€πŸ‘©β€πŸ‘§'); }, }, }; testSuite(testObj);