Use node apis for test setup, refactor a bunch of runtime stuff
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
b2169cf54b
commit
2c21bf0c9b
@ -3,10 +3,9 @@
|
||||
*/
|
||||
|
||||
import { IRuntime, RunTimeType } from '../common/runtime.ts';
|
||||
import TerminalIO from '../tsx/terminal_io.ts';
|
||||
import FileIO from '../tsx/file_io.ts';
|
||||
|
||||
import process from 'node:process';
|
||||
import { process } from '../common/runtime/node.ts';
|
||||
import TerminalIO from '../common/runtime/terminal_io.ts';
|
||||
import FileIO from '../common/runtime/file_io.ts';
|
||||
|
||||
/**
|
||||
* The Bun Runtime implementation
|
||||
|
@ -1,34 +1,19 @@
|
||||
/**
|
||||
* Adapt the bun test interface to the shared testing interface
|
||||
*/
|
||||
import { deepStrictEqual, notStrictEqual, strictEqual } from 'node:assert';
|
||||
import { describe, test } from 'bun:test';
|
||||
import { ITestBase } from '../common/types.ts';
|
||||
|
||||
export function testSuite(testObj: any) {
|
||||
Object.keys(testObj).forEach((group) => {
|
||||
describe(group, () => {
|
||||
const groupObj = testObj[group];
|
||||
Object.keys(groupObj).forEach((testName) => {
|
||||
test(testName, groupObj[testName]);
|
||||
import AbstractTestBase from '../common/runtime/test_base.ts';
|
||||
class BunTestBase extends AbstractTestBase {
|
||||
public static testSuite(testObj: any): void {
|
||||
Object.keys(testObj).forEach((group) => {
|
||||
describe(group, () => {
|
||||
const groupObj = testObj[group];
|
||||
Object.keys(groupObj).forEach((testName) => {
|
||||
test(testName, groupObj[testName]);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const BunTestBase: ITestBase = {
|
||||
assertEquivalent: (actual: unknown, expected: unknown) =>
|
||||
deepStrictEqual(actual, expected),
|
||||
assertExists: (actual: unknown) => notStrictEqual(actual, undefined),
|
||||
assertFalse: (actual: boolean) => strictEqual(actual, false),
|
||||
assertInstanceOf: (actual: unknown, expectedType: any) =>
|
||||
strictEqual(actual instanceof expectedType, true),
|
||||
assertNotEquals: (actual: unknown, expected: unknown) =>
|
||||
notStrictEqual(actual, expected),
|
||||
assertEquals: (actual: unknown, expected: unknown) =>
|
||||
strictEqual(actual, expected),
|
||||
assertTrue: (actual: boolean) => strictEqual(actual, true),
|
||||
testSuite,
|
||||
};
|
||||
|
||||
export default BunTestBase;
|
||||
|
@ -1,7 +1,7 @@
|
||||
import Row from './row.ts';
|
||||
import { arrayInsert, maxAdd, minSub } from './fns.ts';
|
||||
import Option, { None, Some } from './option.ts';
|
||||
import { getRuntime, logDebug } from './runtime.ts';
|
||||
import { getRuntime, logDebug, logWarning } from './runtime.ts';
|
||||
import { Position, SearchDirection } from './types.ts';
|
||||
|
||||
export class Document {
|
||||
@ -17,7 +17,7 @@ export class Document {
|
||||
this.dirty = false;
|
||||
}
|
||||
|
||||
get numRows(): number {
|
||||
public get numRows(): number {
|
||||
return this.#rows.length;
|
||||
}
|
||||
|
||||
@ -66,6 +66,10 @@ export class Document {
|
||||
direction: SearchDirection = SearchDirection.Forward,
|
||||
): Option<Position> {
|
||||
if (at.y >= this.numRows) {
|
||||
logWarning('Trying to search beyond the end of the current file', {
|
||||
at,
|
||||
document: this,
|
||||
});
|
||||
return None;
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
import process from 'node:process';
|
||||
import { process } from './runtime/node.ts';
|
||||
import { readKey } from './fns.ts';
|
||||
import { getRuntime, logError } from './runtime.ts';
|
||||
import { getRuntime, logError, logWarning } from './runtime.ts';
|
||||
import Editor from './editor.ts';
|
||||
|
||||
export async function main() {
|
||||
@ -43,7 +43,9 @@ export async function main() {
|
||||
for await (const char of term.inputLoop()) {
|
||||
const parsed = readKey(char);
|
||||
if (char.length === 0 || parsed.length === 0) {
|
||||
continue;
|
||||
logWarning('Empty input returned from runtime input loop');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Process input
|
||||
|
@ -1,7 +1,7 @@
|
||||
/**
|
||||
* Functions/Methods that depend on the current runtime to function
|
||||
*/
|
||||
import process from 'node:process';
|
||||
import { process } from './runtime/node.ts';
|
||||
import Ansi from './ansi.ts';
|
||||
import { IRuntime, ITerminalSize, ITestBase } from './types.ts';
|
||||
import { noop } from './fns.ts';
|
||||
|
@ -1,9 +1,9 @@
|
||||
import { appendFile, readFile, writeFile } from 'node:fs/promises';
|
||||
import { resolve } from 'node:path';
|
||||
|
||||
import { IFileIO } from '../common/runtime.ts';
|
||||
import { IFileIO } from '../runtime.ts';
|
||||
|
||||
const TsxFileIO: IFileIO = {
|
||||
const CommonFileIO: IFileIO = {
|
||||
openFile: async function (path: string): Promise<string> {
|
||||
const filePath = resolve(path);
|
||||
const contents = await readFile(filePath, { encoding: 'utf8' });
|
||||
@ -22,4 +22,4 @@ const TsxFileIO: IFileIO = {
|
||||
},
|
||||
};
|
||||
|
||||
export default TsxFileIO;
|
||||
export default CommonFileIO;
|
3
src/common/runtime/node.ts
Normal file
3
src/common/runtime/node.ts
Normal file
@ -0,0 +1,3 @@
|
||||
import * as process from 'node:process';
|
||||
|
||||
export { process };
|
@ -1,12 +1,11 @@
|
||||
import process from 'node:process';
|
||||
import { process } from './node.ts';
|
||||
import { readKey } from '../fns.ts';
|
||||
import { ITerminal, ITerminalSize } from '../types.ts';
|
||||
|
||||
import { readKey } from '../common/fns.ts';
|
||||
import { ITerminal, ITerminalSize } from '../common/types.ts';
|
||||
|
||||
const TsxTerminalIO: ITerminal = {
|
||||
const CommonTerminalIO: ITerminal = {
|
||||
argv: (process.argv.length > 2) ? process.argv.slice(2) : [],
|
||||
inputLoop: async function* (): AsyncGenerator<Uint8Array, null> {
|
||||
yield (await TsxTerminalIO.readStdinRaw()) ?? new Uint8Array(0);
|
||||
yield (await CommonTerminalIO.readStdinRaw()) ?? new Uint8Array(0);
|
||||
|
||||
return null;
|
||||
},
|
||||
@ -19,7 +18,7 @@ const TsxTerminalIO: ITerminal = {
|
||||
});
|
||||
},
|
||||
readStdin: async function (): Promise<string | null> {
|
||||
const raw = await TsxTerminalIO.readStdinRaw();
|
||||
const raw = await CommonTerminalIO.readStdinRaw();
|
||||
return readKey(raw ?? new Uint8Array(0));
|
||||
},
|
||||
readStdinRaw: function (): Promise<Uint8Array | null> {
|
||||
@ -38,4 +37,4 @@ const TsxTerminalIO: ITerminal = {
|
||||
},
|
||||
};
|
||||
|
||||
export default TsxTerminalIO;
|
||||
export default CommonTerminalIO;
|
88
src/common/runtime/test_base.ts
Normal file
88
src/common/runtime/test_base.ts
Normal file
@ -0,0 +1,88 @@
|
||||
/**
|
||||
* Adapt the node test interface to the shared testing interface
|
||||
*/
|
||||
import { deepStrictEqual, notStrictEqual, strictEqual } from 'node:assert';
|
||||
import Option from '../option.ts';
|
||||
|
||||
export interface ITestBase {
|
||||
assertEquivalent(actual: unknown, expected: unknown): void;
|
||||
assertExists(actual: unknown): void;
|
||||
assertInstanceOf(actual: unknown, expectedType: any): void;
|
||||
assertNotEquals(actual: unknown, expected: unknown): void;
|
||||
assertEquals(actual: unknown, expected: unknown): void;
|
||||
assertTrue(actual: boolean): void;
|
||||
assertFalse(actual: boolean): void;
|
||||
assertSome<T>(actual: Option<T>): void;
|
||||
assertNone<T>(actual: Option<T>): void;
|
||||
/**
|
||||
* Convert the nested test object into a test suite for the current runtime
|
||||
*/
|
||||
testSuite(testObj: any): void;
|
||||
}
|
||||
|
||||
abstract class AbstractTestBase implements Partial<ITestBase> {
|
||||
/**
|
||||
* The values (often objects) have all the same property values
|
||||
*/
|
||||
public static assertEquivalent(actual: unknown, expected: unknown): void {
|
||||
return deepStrictEqual(actual, expected);
|
||||
}
|
||||
|
||||
/**
|
||||
* The value is not null or undefined
|
||||
*/
|
||||
public static assertExists(actual: unknown): void {
|
||||
return notStrictEqual(actual, undefined);
|
||||
}
|
||||
|
||||
/**
|
||||
* `actual` is an object implementing `expectedType`
|
||||
*/
|
||||
public static assertInstanceOf(actual: unknown, expectedType: any): void {
|
||||
return strictEqual(actual instanceof expectedType, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* The values are not exactly equal (Different instance, type, value, etc)
|
||||
*/
|
||||
public static assertNotEquals(actual: unknown, expected: unknown): void {
|
||||
return notStrictEqual(actual, expected);
|
||||
}
|
||||
|
||||
/**
|
||||
* The values are exactly the same
|
||||
*/
|
||||
public static assertEquals(actual: unknown, expected: unknown): void {
|
||||
return strictEqual(actual, expected);
|
||||
}
|
||||
|
||||
/**
|
||||
* The value is true
|
||||
*/
|
||||
public static assertTrue(actual: boolean): void {
|
||||
return strictEqual(actual, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* The value is false
|
||||
*/
|
||||
public static assertFalse(actual: boolean): void {
|
||||
return strictEqual(actual, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* The value is a `Some` type `Option`
|
||||
*/
|
||||
public static assertSome<T>(actual: Option<T>): void {
|
||||
return AbstractTestBase.assertTrue(actual.isSome());
|
||||
}
|
||||
|
||||
/**
|
||||
* The value is a `None` type `Option`
|
||||
*/
|
||||
public static assertNone<T>(actual: Option<T>): void {
|
||||
return AbstractTestBase.assertTrue(actual.isNone());
|
||||
}
|
||||
}
|
||||
|
||||
export default AbstractTestBase;
|
@ -1,6 +1,7 @@
|
||||
import { RunTimeType } from './runtime.ts';
|
||||
|
||||
export { Position } from './position.ts';
|
||||
export type { ITestBase } from './runtime/test_base.ts';
|
||||
|
||||
/**
|
||||
* The size of terminal in rows and columns
|
||||
@ -128,66 +129,3 @@ export interface IRuntime {
|
||||
*/
|
||||
exit(code?: number): void;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Testing
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* The shared test interface, so tests can be run by both runtimes
|
||||
*/
|
||||
export interface ITestBase {
|
||||
/**
|
||||
* The values (often objects) have all the same property values
|
||||
*
|
||||
* @param actual
|
||||
* @param expected
|
||||
*/
|
||||
assertEquivalent(actual: unknown, expected: unknown): void;
|
||||
|
||||
/**
|
||||
* The value is not null or undefined
|
||||
*
|
||||
* @param actual
|
||||
*/
|
||||
assertExists(actual: unknown): void;
|
||||
|
||||
/**
|
||||
* The value is false
|
||||
*
|
||||
* @param actual
|
||||
*/
|
||||
assertFalse(actual: boolean): void;
|
||||
|
||||
/**
|
||||
* `actual` is an object implementing `expectedType`
|
||||
*
|
||||
* @param actual
|
||||
* @param expectedType
|
||||
*/
|
||||
assertInstanceOf(actual: unknown, expectedType: any): void;
|
||||
|
||||
/**
|
||||
* The values are not exactly equal (Different instance, type, value, etc)
|
||||
*
|
||||
* @param actual
|
||||
* @param expected
|
||||
*/
|
||||
assertNotEquals(actual: unknown, expected: unknown): void;
|
||||
|
||||
/**
|
||||
* The values are exactly the same
|
||||
*
|
||||
* @param actual
|
||||
* @param expected
|
||||
*/
|
||||
assertEquals(actual: unknown, expected: unknown): void;
|
||||
|
||||
/**
|
||||
* The value is true
|
||||
*
|
||||
* @param actual
|
||||
*/
|
||||
assertTrue(actual: boolean): void;
|
||||
testSuite(testObj: any): void;
|
||||
}
|
||||
|
@ -1,31 +1,15 @@
|
||||
import { ITestBase } from '../common/types.ts';
|
||||
import { stdAssert } from './deps.ts';
|
||||
const {
|
||||
assertEquals,
|
||||
assertExists,
|
||||
assertInstanceOf,
|
||||
assertNotEquals,
|
||||
assertStrictEquals,
|
||||
} = stdAssert;
|
||||
|
||||
export function testSuite(testObj: any) {
|
||||
Object.keys(testObj).forEach((group) => {
|
||||
const groupObj = testObj[group];
|
||||
Object.keys(groupObj).forEach((testName) => {
|
||||
Deno.test(testName, groupObj[testName]);
|
||||
// @ts-ignore The import exists, but tsc complains
|
||||
import { test } from 'node:test';
|
||||
import AbstractTestBase from '../common/runtime/test_base.ts';
|
||||
class DenoTestBase extends AbstractTestBase {
|
||||
public static testSuite(testObj: any) {
|
||||
Object.keys(testObj).forEach((group) => {
|
||||
const groupObj = testObj[group];
|
||||
Object.keys(groupObj).forEach((testName) => {
|
||||
test(testName, groupObj[testName]);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const DenoTestBase: ITestBase = {
|
||||
assertEquivalent: assertEquals,
|
||||
assertExists,
|
||||
assertInstanceOf,
|
||||
assertNotEquals,
|
||||
assertEquals: assertStrictEquals,
|
||||
assertTrue: (actual: boolean) => assertStrictEquals(actual, true),
|
||||
assertFalse: (actual: boolean) => assertStrictEquals(actual, false),
|
||||
testSuite,
|
||||
};
|
||||
|
||||
export default DenoTestBase;
|
||||
|
@ -2,17 +2,16 @@
|
||||
* The main entrypoint when using Tsx as the runtime
|
||||
*/
|
||||
import { IRuntime, RunTimeType } from '../common/runtime.ts';
|
||||
import TsxTerminalIO from './terminal_io.ts';
|
||||
import TsxFileIO from './file_io.ts';
|
||||
|
||||
import process from 'node:process';
|
||||
import { process } from '../common/runtime/node.ts';
|
||||
import TsxTerminalIO from '../common/runtime/terminal_io.ts';
|
||||
import FileIO from '../common/runtime/file_io.ts';
|
||||
|
||||
/**
|
||||
* The Tsx Runtime implementation
|
||||
*/
|
||||
const TsxRuntime: IRuntime = {
|
||||
name: RunTimeType.Tsx,
|
||||
file: TsxFileIO,
|
||||
file: FileIO,
|
||||
term: TsxTerminalIO,
|
||||
onEvent: (eventName: string, handler) => process.on(eventName, handler),
|
||||
onExit: (cb: () => void): void => {
|
||||
|
@ -1,39 +1,21 @@
|
||||
// @ts-nocheck: Bun is used for typescript checks, bun does not have 'node:assert' or 'node:test'
|
||||
/**
|
||||
* Adapt the node test interface to the shared testing interface
|
||||
*/
|
||||
import {
|
||||
deepStrictEqual,
|
||||
notStrictEqual,
|
||||
strictEqual,
|
||||
} from 'node:assert/strict';
|
||||
// @ts-ignore The import exists, but tsc complains
|
||||
import { describe, it } from 'node:test';
|
||||
import { ITestBase } from '../common/types.ts';
|
||||
import AbstractTestBase from '../common/runtime/test_base.ts';
|
||||
|
||||
export function testSuite(testObj: any) {
|
||||
Object.keys(testObj).forEach((group) => {
|
||||
describe(group, () => {
|
||||
const groupObj = testObj[group];
|
||||
Object.keys(groupObj).forEach((testName) => {
|
||||
it(testName, groupObj[testName]);
|
||||
class TsxTestBase extends AbstractTestBase {
|
||||
public static testSuite(testObj: any): void {
|
||||
Object.keys(testObj).forEach((group) => {
|
||||
describe(group, () => {
|
||||
const groupObj = testObj[group];
|
||||
Object.keys(groupObj).forEach((testName) => {
|
||||
it(testName, groupObj[testName]);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const TsxTestBase: ITestBase = {
|
||||
assertEquivalent: (actual: unknown, expected: unknown) =>
|
||||
deepStrictEqual(actual, expected),
|
||||
assertExists: (actual: unknown) => notStrictEqual(actual, undefined),
|
||||
assertFalse: (actual: boolean) => strictEqual(actual, false),
|
||||
assertInstanceOf: (actual: unknown, expectedType: any) =>
|
||||
strictEqual(actual instanceof expectedType, true),
|
||||
assertNotEquals: (actual: unknown, expected: unknown) =>
|
||||
notStrictEqual(actual, expected),
|
||||
assertEquals: (actual: unknown, expected: unknown) =>
|
||||
strictEqual(actual, expected),
|
||||
assertTrue: (actual: boolean) => strictEqual(actual, true),
|
||||
testSuite,
|
||||
};
|
||||
|
||||
export default TsxTestBase;
|
||||
|
@ -13,7 +13,8 @@
|
||||
"skipLibCheck": true,
|
||||
"composite": true,
|
||||
"downlevelIteration": true,
|
||||
"allowSyntheticDefaultImports": true
|
||||
"esModuleInterop": false,
|
||||
"allowSyntheticDefaultImports": false
|
||||
},
|
||||
"exclude": ["src/deno"]
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user