Add util functions for null/undefined checks, organize tests into sections
Some checks failed
timw4mail/scroll/pipeline/head There was a failure building this commit
Some checks failed
timw4mail/scroll/pipeline/head There was a failure building this commit
This commit is contained in:
parent
e6b53ef327
commit
8093683f92
@ -19,15 +19,7 @@ const {
|
||||
testSuite,
|
||||
} = await getTestRunner();
|
||||
|
||||
const encoder = new TextEncoder();
|
||||
const testKeyMap = (codes: string[], expected: string) => {
|
||||
codes.forEach((code) => {
|
||||
assertEquals(Fn.readKey(encoder.encode(code)), expected);
|
||||
});
|
||||
};
|
||||
|
||||
testSuite({
|
||||
'ANSI utils': {
|
||||
const ANSITest = {
|
||||
'moveCursor()': () => {
|
||||
assertEquals(Ansi.moveCursor(1, 2), '\x1b[2;3H');
|
||||
},
|
||||
@ -37,8 +29,11 @@ testSuite({
|
||||
'moveCursorDown()': () => {
|
||||
assertEquals(Ansi.moveCursorDown(7), '\x1b[7B');
|
||||
},
|
||||
},
|
||||
Buffer: {
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
const BufferTest = {
|
||||
'new Buffer': () => {
|
||||
const b = new Buffer();
|
||||
assertInstanceOf(b, Buffer);
|
||||
@ -76,8 +71,11 @@ testSuite({
|
||||
|
||||
assertEquals(b.strlen(), 0);
|
||||
},
|
||||
},
|
||||
Document: {
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
const DocumentTest = {
|
||||
'.default': () => {
|
||||
const doc = Document.default();
|
||||
assertEquals(doc.numRows, 0);
|
||||
@ -120,14 +118,20 @@ testSuite({
|
||||
doc.delete(Position.at(3, 0));
|
||||
assertEquals(doc.row(0)?.toString(), 'fooar');
|
||||
},
|
||||
},
|
||||
Editor: {
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
const EditorTest = {
|
||||
'new Editor': () => {
|
||||
const e = new Editor(defaultTerminalSize);
|
||||
assertInstanceOf(e, Editor);
|
||||
},
|
||||
},
|
||||
Position: {
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
const PositionTest = {
|
||||
'.default': () => {
|
||||
const p = Position.default();
|
||||
assertEquals(p.x, 0);
|
||||
@ -151,8 +155,11 @@ testSuite({
|
||||
assertEquals(p2.x, 1);
|
||||
assertEquals(p2.y, 2);
|
||||
},
|
||||
},
|
||||
Row: {
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
const RowTest = {
|
||||
'.default': () => {
|
||||
const row = Row.default();
|
||||
assertEquals(row.toString(), '');
|
||||
@ -233,8 +240,28 @@ testSuite({
|
||||
assertEquals(aCx, cx);
|
||||
assertEquals(aRx, rx);
|
||||
},
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
const fnTest = {
|
||||
'defined()': () => {
|
||||
const { defined } = Fn;
|
||||
assertFalse(defined(null));
|
||||
assertFalse(defined(void 0));
|
||||
assertFalse(defined(undefined));
|
||||
assertTrue(defined(0));
|
||||
assertTrue(defined(false));
|
||||
},
|
||||
'nullish()': () => {
|
||||
const { nullish } = Fn;
|
||||
|
||||
assertTrue(nullish(null));
|
||||
assertTrue(nullish(void 0));
|
||||
assertTrue(nullish(undefined));
|
||||
assertFalse(nullish(0));
|
||||
assertFalse(nullish(false));
|
||||
},
|
||||
'fns': {
|
||||
'arrayInsert() strings': () => {
|
||||
const { arrayInsert } = Fn;
|
||||
|
||||
@ -347,8 +374,19 @@ testSuite({
|
||||
assertEquals(truncate('😺😸😹', 5), '😺😸😹');
|
||||
assertEquals(truncate('👨👩👧👦', 5), '👨👩👧');
|
||||
},
|
||||
},
|
||||
'readKey()': {
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
const encoder = new TextEncoder();
|
||||
|
||||
const testKeyMap = (codes: string[], expected: string) => {
|
||||
codes.forEach((code) => {
|
||||
assertEquals(Fn.readKey(encoder.encode(code)), expected);
|
||||
});
|
||||
};
|
||||
|
||||
const readKeyTest = {
|
||||
'empty input': () => {
|
||||
assertEquals(Fn.readKey(new Uint8Array(0)), '');
|
||||
},
|
||||
@ -385,5 +423,19 @@ testSuite({
|
||||
'End': () =>
|
||||
testKeyMap(['\x1b[4~', '\x1b[8~', '\x1b[F', '\x1bOF'], KeyCommand.End),
|
||||
'Enter': () => testKeyMap(['\n', '\r', '\v'], KeyCommand.Enter),
|
||||
},
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Test Suite Setup
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
testSuite({
|
||||
'ANSI utils': ANSITest,
|
||||
Buffer: BufferTest,
|
||||
Document: DocumentTest,
|
||||
Editor: EditorTest,
|
||||
Position: PositionTest,
|
||||
Row: RowTest,
|
||||
fns: fnTest,
|
||||
'readKey()': readKeyTest,
|
||||
});
|
||||
|
@ -81,7 +81,7 @@ export class Document {
|
||||
const row = this.#rows[potential.y];
|
||||
|
||||
// Okay, we have to take the Javascript string index (potential.x), convert
|
||||
// it to the Row character index, and then convert that to the Row render index
|
||||
// it to the Row 'character' index, and then convert that to the Row render index
|
||||
// so that the highlighted color starts in the right place.
|
||||
const start = row.cxToRx(row.byteIndexToCharIndex(potential.x));
|
||||
|
||||
|
@ -11,6 +11,20 @@ const decoder = new TextDecoder();
|
||||
*/
|
||||
export const noop = () => {};
|
||||
|
||||
/**
|
||||
* Does a value exist? (not null or undefined)
|
||||
*/
|
||||
export function defined(v: unknown): boolean {
|
||||
return v !== null && typeof v !== 'undefined';
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the value null or undefined?
|
||||
*/
|
||||
export function nullish(v: unknown): boolean {
|
||||
return v === null || typeof v === 'undefined';
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert input from ANSI escape sequences into a form
|
||||
* that can be more easily mapped to editor commands
|
||||
|
@ -107,6 +107,9 @@ export class Row {
|
||||
return this.byteIndexToCharIndex(byteCount);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the raw row offset to the equivalent offset for screen rendering
|
||||
*/
|
||||
public cxToRx(cx: number): number {
|
||||
let rx = 0;
|
||||
let j;
|
||||
@ -120,6 +123,9 @@ export class Row {
|
||||
return rx;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the screen rendering row offset to the file row offset
|
||||
*/
|
||||
public rxToCx(rx: number): number {
|
||||
let curRx = 0;
|
||||
let cx = 0;
|
||||
@ -137,6 +143,10 @@ export class Row {
|
||||
return cx;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the index of a JS string into the equivalent
|
||||
* 'unicode character' index
|
||||
*/
|
||||
public byteIndexToCharIndex(byteIndex: number): number {
|
||||
if (this.toString().length === this.chars.length) {
|
||||
return byteIndex;
|
||||
@ -154,6 +164,10 @@ export class Row {
|
||||
return this.chars.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the 'unicode character' index into the equivalent
|
||||
* JS string index
|
||||
*/
|
||||
public charIndexToByteIndex(charIndex: number): number {
|
||||
if (charIndex === 0 || this.toString().length === this.chars.length) {
|
||||
return charIndex;
|
||||
|
Loading…
Reference in New Issue
Block a user