And a bit more test refactoring and cleanup
This commit is contained in:
parent
2aaf1c678b
commit
a1aa189e11
3
justfile
3
justfile
@ -52,8 +52,7 @@ deno-test:
|
|||||||
|
|
||||||
# Create test coverage report with deno
|
# Create test coverage report with deno
|
||||||
deno-coverage:
|
deno-coverage:
|
||||||
deno test --allow-all --coverage=.deno-cover
|
./coverage.sh
|
||||||
deno coverage --unstable-ffi .deno-cover
|
|
||||||
|
|
||||||
# Run with deno
|
# Run with deno
|
||||||
deno-run file="":
|
deno-run file="":
|
||||||
|
@ -27,8 +27,6 @@ const BunTestBase: ITestBase = {
|
|||||||
assertStrictEquals: (actual: unknown, expected: unknown) =>
|
assertStrictEquals: (actual: unknown, expected: unknown) =>
|
||||||
expect(actual).toBe(expected),
|
expect(actual).toBe(expected),
|
||||||
assertTrue: (actual: boolean) => expect(actual).toBe(true),
|
assertTrue: (actual: boolean) => expect(actual).toBe(true),
|
||||||
test,
|
|
||||||
testGroup: describe,
|
|
||||||
testSuite,
|
testSuite,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -4,9 +4,9 @@ import { Document, Row } from './document.ts';
|
|||||||
import Buffer from './buffer.ts';
|
import Buffer from './buffer.ts';
|
||||||
import {
|
import {
|
||||||
chars,
|
chars,
|
||||||
ctrl_key,
|
ctrlKey,
|
||||||
is_ascii,
|
isAscii,
|
||||||
is_control,
|
isControl,
|
||||||
noop,
|
noop,
|
||||||
ord,
|
ord,
|
||||||
strlen,
|
strlen,
|
||||||
@ -15,163 +15,173 @@ import {
|
|||||||
import { Editor } from './editor.ts';
|
import { Editor } from './editor.ts';
|
||||||
import { defaultTerminalSize } from './termios.ts';
|
import { defaultTerminalSize } from './termios.ts';
|
||||||
|
|
||||||
const t = await getTestRunner();
|
const {
|
||||||
|
assertEquals,
|
||||||
|
assertExists,
|
||||||
|
assertInstanceOf,
|
||||||
|
assertNotEquals,
|
||||||
|
assertFalse,
|
||||||
|
assertTrue,
|
||||||
|
testSuite,
|
||||||
|
} = await getTestRunner();
|
||||||
|
|
||||||
const testObj = {
|
const testObj = {
|
||||||
'ANSI::ANSI utils': {
|
'ANSI::ANSI utils': {
|
||||||
'Ansi.moveCursor': () => {
|
'Ansi.moveCursor': () => {
|
||||||
t.assertEquals(Ansi.moveCursor(1, 2), '\x1b[2;3H');
|
assertEquals(Ansi.moveCursor(1, 2), '\x1b[2;3H');
|
||||||
},
|
},
|
||||||
'Ansi.moveCursorForward': () => {
|
'Ansi.moveCursorForward': () => {
|
||||||
t.assertEquals(Ansi.moveCursorForward(2), '\x1b[2C');
|
assertEquals(Ansi.moveCursorForward(2), '\x1b[2C');
|
||||||
},
|
},
|
||||||
'Ansi.moveCursorDown': () => {
|
'Ansi.moveCursorDown': () => {
|
||||||
t.assertEquals(Ansi.moveCursorDown(7), '\x1b[7B');
|
assertEquals(Ansi.moveCursorDown(7), '\x1b[7B');
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
'ANSI::readKey()': {
|
'ANSI::readKey()': {
|
||||||
'readKey passthrough': () => {
|
'readKey passthrough': () => {
|
||||||
// Ignore unhandled escape sequences
|
// Ignore unhandled escape sequences
|
||||||
t.assertEquals(readKey('\x1b[]'), '\x1b[]');
|
assertEquals(readKey('\x1b[]'), '\x1b[]');
|
||||||
|
|
||||||
// Pass explicitly mapped values right through
|
// Pass explicitly mapped values right through
|
||||||
t.assertEquals(readKey(KeyCommand.ArrowUp), KeyCommand.ArrowUp);
|
assertEquals(readKey(KeyCommand.ArrowUp), KeyCommand.ArrowUp);
|
||||||
t.assertEquals(readKey(KeyCommand.Home), KeyCommand.Home);
|
assertEquals(readKey(KeyCommand.Home), KeyCommand.Home);
|
||||||
t.assertEquals(readKey(KeyCommand.Delete), KeyCommand.Delete);
|
assertEquals(readKey(KeyCommand.Delete), KeyCommand.Delete);
|
||||||
},
|
},
|
||||||
'readKey Home': () => {
|
'readKey Home': () => {
|
||||||
['\x1b[1~', '\x1b[7~', '\x1b[H', '\x1bOH'].forEach((code) => {
|
['\x1b[1~', '\x1b[7~', '\x1b[H', '\x1bOH'].forEach((code) => {
|
||||||
t.assertEquals(readKey(code), KeyCommand.Home);
|
assertEquals(readKey(code), KeyCommand.Home);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
'readKey End': () => {
|
'readKey End': () => {
|
||||||
['\x1b[4~', '\x1b[8~', '\x1b[F', '\x1bOF'].forEach((code) => {
|
['\x1b[4~', '\x1b[8~', '\x1b[F', '\x1bOF'].forEach((code) => {
|
||||||
t.assertEquals(readKey(code), KeyCommand.End);
|
assertEquals(readKey(code), KeyCommand.End);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Buffer: {
|
Buffer: {
|
||||||
'Buffer exists': () => {
|
'Buffer exists': () => {
|
||||||
const b = new Buffer();
|
const b = new Buffer();
|
||||||
t.assertInstanceOf(b, Buffer);
|
assertInstanceOf(b, Buffer);
|
||||||
t.assertEquals(b.strlen(), 0);
|
assertEquals(b.strlen(), 0);
|
||||||
},
|
},
|
||||||
'Buffer.appendLine': () => {
|
'Buffer.appendLine': () => {
|
||||||
const b = new Buffer();
|
const b = new Buffer();
|
||||||
|
|
||||||
// Carriage return and line feed
|
// Carriage return and line feed
|
||||||
b.appendLine();
|
b.appendLine();
|
||||||
t.assertEquals(b.strlen(), 2);
|
assertEquals(b.strlen(), 2);
|
||||||
|
|
||||||
b.clear();
|
b.clear();
|
||||||
t.assertEquals(b.strlen(), 0);
|
assertEquals(b.strlen(), 0);
|
||||||
|
|
||||||
b.appendLine('foo');
|
b.appendLine('foo');
|
||||||
t.assertEquals(b.strlen(), 5);
|
assertEquals(b.strlen(), 5);
|
||||||
},
|
},
|
||||||
'Buffer.append': () => {
|
'Buffer.append': () => {
|
||||||
const b = new Buffer();
|
const b = new Buffer();
|
||||||
|
|
||||||
b.append('foobar');
|
b.append('foobar');
|
||||||
t.assertEquals(b.strlen(), 6);
|
assertEquals(b.strlen(), 6);
|
||||||
b.clear();
|
b.clear();
|
||||||
|
|
||||||
b.append('foobar', 3);
|
b.append('foobar', 3);
|
||||||
t.assertEquals(b.strlen(), 3);
|
assertEquals(b.strlen(), 3);
|
||||||
},
|
},
|
||||||
'Buffer.flush': async () => {
|
'Buffer.flush': async () => {
|
||||||
const b = new Buffer();
|
const b = new Buffer();
|
||||||
b.appendLine('foobarbaz' + Ansi.ClearLine);
|
b.appendLine('foobarbaz' + Ansi.ClearLine);
|
||||||
t.assertEquals(b.strlen(), 14);
|
assertEquals(b.strlen(), 14);
|
||||||
|
|
||||||
await b.flush();
|
await b.flush();
|
||||||
|
|
||||||
t.assertEquals(b.strlen(), 0);
|
assertEquals(b.strlen(), 0);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Document: {
|
Document: {
|
||||||
'Document.empty': () => {
|
'Document.empty': () => {
|
||||||
const doc = Document.empty();
|
const doc = Document.empty();
|
||||||
t.assertEquals(doc.numRows, 0);
|
assertEquals(doc.numRows, 0);
|
||||||
t.assertTrue(doc.isEmpty());
|
assertTrue(doc.isEmpty());
|
||||||
t.assertEquals(doc.row(0), null);
|
assertEquals(doc.row(0), null);
|
||||||
},
|
},
|
||||||
'Document.appendRow': () => {
|
'Document.appendRow': () => {
|
||||||
const doc = Document.empty();
|
const doc = Document.empty();
|
||||||
doc.appendRow('foobar');
|
doc.appendRow('foobar');
|
||||||
t.assertEquals(doc.numRows, 1);
|
assertEquals(doc.numRows, 1);
|
||||||
t.assertFalse(doc.isEmpty());
|
assertFalse(doc.isEmpty());
|
||||||
t.assertInstanceOf(doc.row(0), Row);
|
assertInstanceOf(doc.row(0), Row);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
'Document::Row': {
|
'Document::Row': {
|
||||||
'new Row': () => {
|
'new Row': () => {
|
||||||
const row = new Row();
|
const row = new Row();
|
||||||
t.assertEquals(row.toString(), '');
|
assertEquals(row.toString(), '');
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Editor: {
|
Editor: {
|
||||||
'new Editor': () => {
|
'new Editor': () => {
|
||||||
const e = new Editor(defaultTerminalSize);
|
const e = new Editor(defaultTerminalSize);
|
||||||
t.assertInstanceOf(e, Editor);
|
assertInstanceOf(e, Editor);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
'Util::Misc fns': {
|
'Util::Misc fns': {
|
||||||
'noop fn': () => {
|
'noop fn': () => {
|
||||||
t.assertExists(noop);
|
assertExists(noop);
|
||||||
t.assertEquals(noop(), undefined);
|
assertEquals(noop(), undefined);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
'Util::String fns': {
|
'Util::String fns': {
|
||||||
'ord() returns 256 on invalid string': () => {
|
'ord()': () => {
|
||||||
t.assertEquals(ord(''), 256);
|
// Invalid output
|
||||||
},
|
assertEquals(ord(''), 256);
|
||||||
'ord() returns number on valid string': () => {
|
|
||||||
t.assertEquals(ord('a'), 97);
|
// Valid output
|
||||||
|
assertEquals(ord('a'), 97);
|
||||||
},
|
},
|
||||||
'chars() properly splits strings into unicode characters': () => {
|
'chars() properly splits strings into unicode characters': () => {
|
||||||
t.assertEquals(chars('😺😸😹'), ['😺', '😸', '😹']);
|
assertEquals(chars('😺😸😹'), ['😺', '😸', '😹']);
|
||||||
},
|
},
|
||||||
'ctrl_key() returns expected values': () => {
|
'ctrl_key()': () => {
|
||||||
const ctrl_a = ctrl_key('a');
|
const ctrl_a = ctrlKey('a');
|
||||||
t.assertTrue(is_control(ctrl_a));
|
assertTrue(isControl(ctrl_a));
|
||||||
t.assertEquals(ctrl_a, String.fromCodePoint(0x01));
|
assertEquals(ctrl_a, String.fromCodePoint(0x01));
|
||||||
|
|
||||||
const invalid = ctrl_key('😺');
|
const invalid = ctrlKey('😺');
|
||||||
t.assertFalse(is_control(invalid));
|
assertFalse(isControl(invalid));
|
||||||
t.assertEquals(invalid, '😺');
|
assertEquals(invalid, '😺');
|
||||||
},
|
},
|
||||||
'is_ascii() properly discerns ascii chars': () => {
|
'is_ascii()': () => {
|
||||||
t.assertTrue(is_ascii('asjyverkjhsdf1928374'));
|
assertTrue(isAscii('asjyverkjhsdf1928374'));
|
||||||
t.assertFalse(is_ascii('😺acalskjsdf'));
|
assertFalse(isAscii('😺acalskjsdf'));
|
||||||
t.assertFalse(is_ascii('ab😺ac'));
|
assertFalse(isAscii('ab😺ac'));
|
||||||
},
|
},
|
||||||
'is_control() works as expected': () => {
|
'is_control()': () => {
|
||||||
t.assertFalse(is_control('abc'));
|
assertFalse(isControl('abc'));
|
||||||
t.assertTrue(is_control(String.fromCodePoint(0x01)));
|
assertTrue(isControl(String.fromCodePoint(0x01)));
|
||||||
t.assertFalse(is_control('😺'));
|
assertFalse(isControl('😺'));
|
||||||
},
|
},
|
||||||
'strlen() returns expected length for ascii strings': () => {
|
'strlen()': () => {
|
||||||
t.assertEquals(strlen('abc'), 'abc'.length);
|
// Ascii length
|
||||||
},
|
assertEquals(strlen('abc'), 'abc'.length);
|
||||||
'strlen() returns expected length for multibyte characters': () => {
|
|
||||||
t.assertEquals(strlen('😺😸😹'), 3);
|
// Get number of visible unicode characters
|
||||||
t.assertNotEquals('😺😸😹'.length, strlen('😺😸😹'));
|
assertEquals(strlen('😺😸😹'), 3);
|
||||||
|
assertNotEquals('😺😸😹'.length, strlen('😺😸😹'));
|
||||||
|
|
||||||
// Skin tone modifier + base character
|
// Skin tone modifier + base character
|
||||||
t.assertEquals(strlen('🤰🏼'), 2);
|
assertEquals(strlen('🤰🏼'), 2);
|
||||||
t.assertNotEquals('🤰🏼'.length, strlen('🤰🏼'));
|
assertNotEquals('🤰🏼'.length, strlen('🤰🏼'));
|
||||||
|
|
||||||
// This has 4 sub-characters, and 3 zero-width-joiners
|
// This has 4 sub-characters, and 3 zero-width-joiners
|
||||||
t.assertEquals(strlen('👨👩👧👦'), 7);
|
assertEquals(strlen('👨👩👧👦'), 7);
|
||||||
t.assertNotEquals('👨👩👧👦'.length, strlen('👨👩👧👦'));
|
assertNotEquals('👨👩👧👦'.length, strlen('👨👩👧👦'));
|
||||||
},
|
},
|
||||||
'truncate() shortens strings': () => {
|
'truncate()': () => {
|
||||||
t.assertEquals(truncate('😺😸😹', 1), '😺');
|
assertEquals(truncate('😺😸😹', 1), '😺');
|
||||||
t.assertEquals(truncate('😺😸😹', 5), '😺😸😹');
|
assertEquals(truncate('😺😸😹', 5), '😺😸😹');
|
||||||
t.assertEquals(truncate('👨👩👧👦', 5), '👨👩👧');
|
assertEquals(truncate('👨👩👧👦', 5), '👨👩👧');
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
t.testSuite(testObj);
|
testSuite(testObj);
|
||||||
|
@ -2,7 +2,7 @@ import Ansi, { KeyCommand } from './ansi.ts';
|
|||||||
import Buffer from './buffer.ts';
|
import Buffer from './buffer.ts';
|
||||||
import Document from './document.ts';
|
import Document from './document.ts';
|
||||||
import { IPoint, ITerminalSize, logToFile, VERSION } from './mod.ts';
|
import { IPoint, ITerminalSize, logToFile, VERSION } from './mod.ts';
|
||||||
import { ctrl_key } from './utils.ts';
|
import { ctrlKey } from './utils.ts';
|
||||||
|
|
||||||
export class Editor {
|
export class Editor {
|
||||||
/**
|
/**
|
||||||
@ -52,7 +52,7 @@ export class Editor {
|
|||||||
*/
|
*/
|
||||||
public processKeyPress(input: string): boolean {
|
public processKeyPress(input: string): boolean {
|
||||||
switch (input) {
|
switch (input) {
|
||||||
case ctrl_key('q'):
|
case ctrlKey('q'):
|
||||||
this.clearScreen().then(() => {});
|
this.clearScreen().then(() => {});
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -22,7 +22,5 @@ export interface ITestBase {
|
|||||||
assertNotEquals(actual: unknown, expected: unknown): void;
|
assertNotEquals(actual: unknown, expected: unknown): void;
|
||||||
assertStrictEquals(actual: unknown, expected: unknown): void;
|
assertStrictEquals(actual: unknown, expected: unknown): void;
|
||||||
assertTrue(actual: boolean): void;
|
assertTrue(actual: boolean): void;
|
||||||
test(name: string, fn: () => void, timeout?: number): void;
|
|
||||||
testGroup(name: string, fn: () => void): void;
|
|
||||||
testSuite(testObj: any): void;
|
testSuite(testObj: any): void;
|
||||||
}
|
}
|
||||||
|
@ -45,7 +45,7 @@ export function strlen(s: string): number {
|
|||||||
*
|
*
|
||||||
* @param char - string to check
|
* @param char - string to check
|
||||||
*/
|
*/
|
||||||
export function is_ascii(char: string): boolean {
|
export function isAscii(char: string): boolean {
|
||||||
return chars(char).every((char) => ord(char) < 0x80);
|
return chars(char).every((char) => ord(char) < 0x80);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -54,9 +54,9 @@ export function is_ascii(char: string): boolean {
|
|||||||
*
|
*
|
||||||
* @param char - a one character string to check
|
* @param char - a one character string to check
|
||||||
*/
|
*/
|
||||||
export function is_control(char: string): boolean {
|
export function isControl(char: string): boolean {
|
||||||
const code = ord(char);
|
const code = ord(char);
|
||||||
return is_ascii(char) && (code === 0x7f || code < 0x20);
|
return isAscii(char) && (code === 0x7f || code < 0x20);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -64,9 +64,9 @@ export function is_control(char: string): boolean {
|
|||||||
*
|
*
|
||||||
* @param char - a one character string
|
* @param char - a one character string
|
||||||
*/
|
*/
|
||||||
export function ctrl_key(char: string): string {
|
export function ctrlKey(char: string): string {
|
||||||
// This is the normal use case, of course
|
// This is the normal use case, of course
|
||||||
if (is_ascii(char)) {
|
if (isAscii(char)) {
|
||||||
const point = ord(char);
|
const point = ord(char);
|
||||||
return String.fromCodePoint(point & 0x1f);
|
return String.fromCodePoint(point & 0x1f);
|
||||||
}
|
}
|
||||||
|
@ -34,8 +34,6 @@ const DenoTestBase: ITestBase = {
|
|||||||
throw new AssertionError(`actual: "${actual}" expected to be false"`);
|
throw new AssertionError(`actual: "${actual}" expected to be false"`);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
test: Deno.test,
|
|
||||||
testGroup: (_name: string, fn) => fn(),
|
|
||||||
testSuite,
|
testSuite,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user