From c82c9161e31730c6b068c9e671c9fe00ea9d83fb Mon Sep 17 00:00:00 2001 From: Jairus Date: Tue, 16 Jul 2024 19:31:35 -0700 Subject: [PATCH] plugins, reporters, invisible message passing, refactor code --- as-test.config.json | 1 + assembly/index.ts | 134 +++++++++------ assembly/reporters/tap.ts | 30 ---- assembly/src/expectation.ts | 46 ++--- assembly/src/log.ts | 15 ++ assembly/src/suite.ts | 64 ++++--- assembly/src/tests.ts | 13 +- assembly/util/helpers.ts | 2 +- assembly/util/term.ts | 42 ++--- assets/img/{screenshot.png => download.png} | Bin bin/run.js | 175 ++++++++++++++++--- bin/types.js | 1 + cli/run.ts | 178 +++++++++++++++++--- cli/types.ts | 1 + package.json | 3 +- plugins/coverage/config.json | 7 - plugins/coverage/reporter.ts | 6 - plugins/coverage/transform.ts | 0 plugins/index.ts | 23 --- plugins/tsconfig.json | 97 ----------- reporters/json/index.ts | 3 - reporters/report.ts | 108 ------------ reporters/tsconfig.json | 97 ----------- 23 files changed, 504 insertions(+), 542 deletions(-) delete mode 100644 assembly/reporters/tap.ts create mode 100644 assembly/src/log.ts rename assets/img/{screenshot.png => download.png} (100%) delete mode 100644 plugins/coverage/config.json delete mode 100644 plugins/coverage/reporter.ts delete mode 100644 plugins/coverage/transform.ts delete mode 100644 plugins/index.ts delete mode 100644 plugins/tsconfig.json delete mode 100644 reporters/json/index.ts delete mode 100644 reporters/report.ts delete mode 100644 reporters/tsconfig.json diff --git a/as-test.config.json b/as-test.config.json index cf12e9f..e6f4bed 100644 --- a/as-test.config.json +++ b/as-test.config.json @@ -1,6 +1,7 @@ { "input": ["./assembly/__tests__/*.spec.ts"], "outDir": "./build", + "logs": "./logs", "config": "none", "plugins": { "coverage": true diff --git a/assembly/index.ts b/assembly/index.ts index 5ab7c1c..c254294 100644 --- a/assembly/index.ts +++ b/assembly/index.ts @@ -1,34 +1,26 @@ import { rainbow } from "as-rainbow"; -import { Suite, SuiteKind } from "./src/suite"; +import { Suite } from "./src/suite"; import { Expectation } from "./src/expectation"; import { stringify } from "as-console/stringify"; import { __COVER, __HASHES, __POINTS } from "as-test/assembly/coverage"; import { JSON } from "json-as"; -import { Report, SuiteReport, TestReport, Time } from "../reporters/report"; -import { term } from "./util/term"; - -/** - * Enumeration representing the verdict of a test case. - */ -export type Verdict = string; -export namespace Verdict { - export const None = "none"; - export const Ok = "ok"; - export const Fail = "fail"; -} +import { term, TermLine } from "./util/term"; +import { Log } from "./src/log"; let entrySuites: Suite[] = []; // @ts-ignore const FILE = isDefined(ENTRY_FILE) ? ENTRY_FILE : "unknown"; // Globals +// @ts-ignore @global let suites: Suite[] = []; - +// @ts-ignore @global let depth: i32 = -1; - +// @ts-ignore @global let current_suite: Suite | null = null; - +// @ts-ignore let before_all_callback: (() => void) | null = null; +// @ts-ignore let after_all_callback: (() => void) | null = null; export let before_each_callback: (() => void) | null = null; @@ -50,7 +42,7 @@ let __test_options!: RunOptions; * ``` */ export function describe(description: string, callback: () => void): void { - const suite = new Suite(description, callback, SuiteKind.Describe); + const suite = new Suite(description, callback, "describe"); if (depth >= 0) { const _suite = suites[depth]; @@ -61,6 +53,7 @@ export function describe(description: string, callback: () => void): void { suites.push(suite); } } else { + suite.file = FILE; entrySuites.push(suite); suites.push(suite); } @@ -81,7 +74,7 @@ export function describe(description: string, callback: () => void): void { * ``` */ export function test(description: string, callback: () => void): void { - const suite = new Suite(description, callback, SuiteKind.Test); + const suite = new Suite(description, callback, "test"); if (depth >= 0) { const _suite = suites[depth]; @@ -92,6 +85,7 @@ export function test(description: string, callback: () => void): void { suites.push(suite); } } else { + suite.file = FILE; entrySuites.push(suite); suites.push(suite); } @@ -112,7 +106,7 @@ export function test(description: string, callback: () => void): void { * ``` */ export function it(description: string, callback: () => void): void { - const suite = new Suite(description, callback, SuiteKind.It); + const suite = new Suite(description, callback, "it"); if (depth >= 0) { const _suite = suites[depth]; @@ -123,6 +117,7 @@ export function it(description: string, callback: () => void): void { suites.push(suite); } } else { + suite.file = FILE; entrySuites.push(suite); suites.push(suite); } @@ -175,9 +170,11 @@ export function log(data: T): void { const lines = formatted.split("\n"); for (let i = 0; i < lines.length; i++) { const line = unchecked(lines[i]); - console.log(" " + rainbow.bgYellow(" LOG ") + " " + line); + if (current_suite) { + current_suite!.addLog(new Log(line)); + } } - console.log(""); + term.write("\n"); } } @@ -272,8 +269,10 @@ class RunOptions { * ``` */ export function run(options: RunOptions = new RunOptions()): void { + // const buf = new ArrayBuffer(20); + // const bytes = process.stdin.read(buf); + // const stdinLn = term.write(String.UTF8.decodeUnsafe(changetype(buf), bytes) + "\n"); __test_options = options; - term.write("\n"); const time = new Time(); const fileLn = term.write(`${rainbow.bgCyanBright(" FILE ")} ${rainbow.dimMk(FILE)}\n`); term.write("\n"); @@ -287,45 +286,80 @@ export function run(options: RunOptions = new RunOptions()): void { depth = -1; current_suite = null; - const suiteLn = term.write(` ${rainbow.bgBlackBright(" ... ")} ${rainbow.dimMk(suite.description)}\n`); - term.write("\n"); suite.run(); suites = []; depth = -1; current_suite = null; + } + time.end = performance.now(); + fileLn.edit(`${rainbow.bgCyanBright(" FILE ")} ${rainbow.dimMk(FILE)} ${rainbow.dimMk(time.format())}`); + const reportText = "\x1B[8mSTART_READ" + JSON.stringify(entrySuites) + "END_READ\x1B[0m\n"; + term.write(reportText).clear(); +} - let suiteNone = true; - for (let ii = 0; ii < suite.suites.length; ii++) { - const _suite = unchecked(suite.suites[ii]); - if (_suite.verdict == Verdict.Fail) { - suite.verdict = Verdict.Fail; - suiteNone = false; - } else if (_suite.verdict == Verdict.Ok) { - suiteNone = false; - } +export class Result { + public name: string; + public arg1: i32; + public arg2: i32; + constructor(name: string, arg1: i32, arg2: i32) { + this.name = name; + this.arg1 = arg1; + this.arg2 = arg2; + } + display(): string { + let out = ""; + out += `${rainbow.boldMk(this.name)} `; + if (this.arg1) { + out += `${rainbow.boldMk(rainbow.red(this.arg1.toString() + " " + "failed"))}`; + } else { + out += `${rainbow.boldMk(rainbow.green("0 failed"))}`; } + out += ` ${this.arg1 + this.arg2} total\n`; + return out; + } + serialize(): string { + return JSON.stringify(this); + } +} - for (let iii = 0; iii < suite.tests.length; iii++) { - const _test = unchecked(suite.tests[iii]); - if (_test.verdict == Verdict.Fail) { - suite.verdict = Verdict.Fail; - } - } +@json +export class Time { + start: f64 = 0; + end: f64 = 0; + format(): string { + return formatTime(this.end - this.start); + } +} - if (!suiteNone && suite.tests.length) { - suite.verdict = Verdict.Ok; - } +class Unit { + name: string; + divisor: number; +} - if (suite.verdict == Verdict.Ok) { - suiteLn.edit(` ${rainbow.bgGreenBright(" PASS ")} ${rainbow.dimMk(suite.description)} ${rainbow.dimMk(suite.time.format())}\n`); +function formatTime(time: f64): string { + if (time < 0) return "0.00μs"; + + const us = time * 1000; + + const units: Unit[] = [ + { name: "μs", divisor: 1 }, + { name: "ms", divisor: 1000 }, + { name: "s", divisor: 1000 * 1000 }, + { name: "m", divisor: 60 * 1000 * 1000 }, + { name: "h", divisor: 60 * 60 * 1000 * 1000 }, + { name: "d", divisor: 24 * 60 * 60 * 1000 * 1000 }, + ]; + + for (let i = units.length - 1; i >= 0; i--) { + const unit = units[i]; + if (us >= unit.divisor) { + const value = (Math.round((us / unit.divisor) * 100) / 100).toString(); + return `${value}${unit.name}`; } } - time.end = performance.now(); - fileLn.edit(`${rainbow.bgCyanBright(" FILE ")} ${rainbow.dimMk(FILE)} ${rainbow.dimMk(time.format())}`); -} -export function getDepth(): string { - if (depth < 0) return ""; - return " ".repeat(depth); + const _us = (Math.round(us * 100) / 100).toString(); + + return `${_us}μs`; } \ No newline at end of file diff --git a/assembly/reporters/tap.ts b/assembly/reporters/tap.ts deleted file mode 100644 index 435fc9a..0000000 --- a/assembly/reporters/tap.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { Verdict } from ".."; -import { Suite } from "../src/suite"; - -export class TapReporter { - public groups: Suite[]; - constructor(groups: Suite[]) { - this.groups = groups; - } - report(): string { - let out = "TAP version 14\n"; - let totalTests: i32 = this.groups.length; - - out += "1.." + totalTests.toString(); - for (let i = 0; i < this.groups.length; i++) { - const group = unchecked(this.groups[i]); - if (group.verdict === Verdict.Ok) { - out += `\nok ${i} - ${group.description}`; - } else if (group.verdict === Verdict.Fail) { - out += `\nnot ok ${i} - ${group.description}`; - out += " ---"; - out += ` message: '${group.description}'`; - out += ` severity: fail`; - for (let ii = 0; ii < group.tests.length; ii++) { - const res = unchecked(group.tests[ii]); - if (res.verdict === Verdict.Ok) continue; - } - } - } - } -} diff --git a/assembly/src/expectation.ts b/assembly/src/expectation.ts index 1fba49b..0240a3e 100644 --- a/assembly/src/expectation.ts +++ b/assembly/src/expectation.ts @@ -1,12 +1,14 @@ import { visualize } from "../util/helpers"; import { Tests } from "./tests"; -import { Verdict, after_each_callback, before_each_callback } from ".."; +import { after_each_callback, before_each_callback } from ".."; +@json export class Expectation extends Tests { - public verdict: Verdict = Verdict.None; + public verdict: string = "none"; private _left: T; // @ts-ignore private _right: u64 = 0; + // @ts-ignore private _not: boolean = false; constructor(left: T) { super(); @@ -24,8 +26,8 @@ export class Expectation extends Tests { toBeNull(): void { this.verdict = isNullable() && changetype(this._left) - ? Verdict.Ok - : Verdict.Fail; + ? "ok" + : "fail"; // @ts-ignore store(changetype(this), null, offsetof>("_right")); @@ -52,7 +54,7 @@ export class Expectation extends Tests { if (!isInteger() && !isFloat()) ERROR("toBeGreaterThan() can only be used on number types!"); - this.verdict = this._left > value ? Verdict.Ok : Verdict.Fail; + this.verdict = this._left > value ? "ok" : "fail"; store( changetype(this), value, @@ -81,7 +83,7 @@ export class Expectation extends Tests { if (!isInteger() && !isFloat()) ERROR("toBeGreaterOrEqualTo() can only be used on number types!"); - this.verdict = this._left >= value ? Verdict.Ok : Verdict.Fail; + this.verdict = this._left >= value ? "ok" : "fail"; store( changetype(this), value, @@ -110,7 +112,7 @@ export class Expectation extends Tests { if (!isInteger() && !isFloat()) ERROR("toBeLessThan() can only be used on number types!"); - this.verdict = this._left < value ? Verdict.Ok : Verdict.Fail; + this.verdict = this._left < value ? "ok" : "fail"; store( changetype(this), value, @@ -139,7 +141,7 @@ export class Expectation extends Tests { if (!isInteger() && !isFloat()) ERROR("toBeLessThanOrEqualTo() can only be used on number types!"); - this.verdict = this._left <= value ? Verdict.Ok : Verdict.Fail; + this.verdict = this._left <= value ? "ok" : "fail"; store( changetype(this), value, @@ -164,7 +166,7 @@ export class Expectation extends Tests { * @returns - void */ toBeString(): void { - this.verdict = isString() ? Verdict.Ok : Verdict.Fail; + this.verdict = isString() ? "ok" : "fail"; this.left = nameof(); this.right = "string"; @@ -182,7 +184,7 @@ export class Expectation extends Tests { * @returns - void */ toBeBoolean(): void { - this.verdict = isBoolean() ? Verdict.Ok : Verdict.Fail; + this.verdict = isBoolean() ? "ok" : "fail"; this.left = nameof(); this.right = "boolean"; @@ -200,7 +202,7 @@ export class Expectation extends Tests { * @returns - void */ toBeArray(): void { - this.verdict = isArray() ? Verdict.Ok : Verdict.Fail; + this.verdict = isArray() ? "ok" : "fail"; this.left = nameof(); this.right = "Array"; @@ -218,7 +220,7 @@ export class Expectation extends Tests { * @returns - void */ toBeNumber(): void { - this.verdict = isFloat() || isInteger() ? Verdict.Ok : Verdict.Fail; + this.verdict = isFloat() || isInteger() ? "ok" : "fail"; this.left = nameof(); this.right = "number"; @@ -236,7 +238,7 @@ export class Expectation extends Tests { * @returns - void */ toBeInteger(): void { - this.verdict = isInteger() ? Verdict.Ok : Verdict.Fail; + this.verdict = isInteger() ? "ok" : "fail"; this.left = nameof(); this.right = "float"; @@ -254,7 +256,7 @@ export class Expectation extends Tests { * @returns - void */ toBeFloat(): void { - this.verdict = isFloat() ? Verdict.Ok : Verdict.Fail; + this.verdict = isFloat() ? "ok" : "fail"; this.left = nameof(); this.right = "integer"; @@ -275,8 +277,8 @@ export class Expectation extends Tests { this.verdict = // @ts-ignore (isFloat() || isInteger()) && isFinite(this._left) - ? Verdict.Ok - : Verdict.Fail; + ? "ok" + : "fail"; this.left = "Infinity"; this.right = "Finite"; @@ -298,7 +300,7 @@ export class Expectation extends Tests { toHaveLength(value: i32): void { this.verdict = // @ts-ignore - isArray() && this._left.length == value ? Verdict.Ok : Verdict.Fail; + isArray() && this._left.length == value ? "ok" : "fail"; // @ts-ignore this.left = this._left.length.toString(); @@ -322,7 +324,7 @@ export class Expectation extends Tests { toContain(value: valueof): void { this.verdict = // @ts-ignore - isArray() && this._left.includes(value) ? Verdict.Ok : Verdict.Fail; + isArray() && this._left.includes(value) ? "ok" : "fail"; // @ts-ignore this.left = "includes value"; @@ -347,15 +349,15 @@ export class Expectation extends Tests { offsetof>("_right"), ); if (isBoolean()) { - this.verdict = this._left === equals ? Verdict.Ok : Verdict.Fail; + this.verdict = this._left === equals ? "ok" : "fail"; } else if (isString()) { - this.verdict = this._left === equals ? Verdict.Ok : Verdict.Fail; + this.verdict = this._left === equals ? "ok" : "fail"; } else if (isInteger() || isFloat()) { - this.verdict = this._left === equals ? Verdict.Ok : Verdict.Fail; + this.verdict = this._left === equals ? "ok" : "fail"; } else if (isArray()) { // getArrayDepth(); } else { - this.verdict = Verdict.None; + this.verdict = "none"; } this.instr = "toBe"; diff --git a/assembly/src/log.ts b/assembly/src/log.ts new file mode 100644 index 0000000..bdb9a11 --- /dev/null +++ b/assembly/src/log.ts @@ -0,0 +1,15 @@ +import { rainbow } from "as-rainbow"; +import { term } from "../util/term"; + +@json +export class Log { + public order: i32 = 0; + public depth: i32 = 0; + public text: string; + constructor(text: string) { + this.text = text; + } + display(): void { + term.write(" ".repeat(this.depth + 1) + `${rainbow.bgMagentaBright(" LOG ")}${rainbow.dimMk(":")} ${this.text}\n`); + } +} \ No newline at end of file diff --git a/assembly/src/suite.ts b/assembly/src/suite.ts index 3a11fb9..5ef4e81 100644 --- a/assembly/src/suite.ts +++ b/assembly/src/suite.ts @@ -1,40 +1,46 @@ import { rainbow } from "as-rainbow"; -import { getDepth, Verdict } from ".."; -import { Time } from "../../reporters/report"; +import { Time } from ".."; import { Expectation } from "./expectation"; import { Tests } from "./tests"; import { term } from "../util/term"; +import { Log } from "./log"; -export type SuiteKind = string; -export namespace SuiteKind { - export const It = "it"; - export const Describe = "describe"; - export const Test = "test"; -} - +@json export class Suite { + public file: string = "unknown"; + public order: i32 = 0; public time: Time = new Time(); public description: string; public depth: i32 = 0; public suites: Suite[] = []; public tests: Tests[] = []; - public logs: string[] = []; - public kind: SuiteKind; + public logs: Log[] = []; + public kind: string; - public verdict: Verdict = Verdict.None; + public verdict: string = "none"; public callback: () => void; - constructor(description: string, callback: () => void, kind: SuiteKind) { + constructor(description: string, callback: () => void, kind: string) { this.description = description; this.callback = callback; this.kind = kind; } addExpectation>(test: T): void { + test.order = this.order++; this.tests.push(test); } addSuite(suite: Suite): void { + suite.order = this.order++; this.suites.push(suite); + suite.depth = this.depth + 1; + suite.file = this.file; + } + addLog(log: Log): void { + log.order = this.order++; + this.logs.push(log); + log.depth = this.depth + 1; + log.display(); } run(): void { @@ -43,32 +49,42 @@ export class Suite { // @ts-ignore depth++; this.time.start = performance.now(); - const suiteDepth = getDepth(); + const suiteDepth = " ".repeat(this.depth + 1); const suiteLn = term.write(`${suiteDepth}${rainbow.bgBlackBright(" ... ")} ${rainbow.dimMk(this.description)}\n`); term.write("\n"); this.callback(); this.time.end = performance.now(); // @ts-ignore depth--; + + let suiteNone = true; for (let i = 0; i < this.suites.length; i++) { const suite = unchecked(this.suites[i]); suite.run(); - if (suite.verdict === Verdict.Fail) { - this.verdict = Verdict.Fail; - break; + if (suite.verdict == "fail") { + this.verdict = "fail"; + suiteNone = false; + } else if (suite.verdict == "ok") { + suiteNone = false; } } for (let i = 0; i < this.tests.length; i++) { const test = unchecked(this.tests[i]); - if (test.verdict === Verdict.Fail) { - this.verdict = Verdict.Fail; - break; + if (test.verdict == "fail") { + this.verdict = "fail"; + suiteNone = false; + } else if (test.verdict == "ok") { + suiteNone = false; } } - if (this.verdict === Verdict.None) { - if (this.tests.length) this.verdict = Verdict.Ok; - if (this.suites.length) this.verdict = Verdict.Ok; + + if (!suiteNone || this.tests.length) { + this.verdict = "ok"; + suiteLn.edit(`${suiteDepth}${rainbow.bgGreenBright(" PASS ")} ${rainbow.dimMk(this.description)}\n`); + } else if (this.verdict == "fail") { + suiteLn.edit(`${suiteDepth}${rainbow.bgRed(" FAIL ")} ${rainbow.dimMk(this.description)}\n`); + } else { + suiteLn.edit(`${suiteDepth}${rainbow.bgBlackBright(" EMPTY ")} ${rainbow.dimMk(this.description)}\n`); } - suiteLn.edit(`${suiteDepth}${rainbow.bgGreenBright(" PASS ")} ${rainbow.dimMk(this.description)} ${rainbow.dimMk(this.time.format())}\n`); } } diff --git a/assembly/src/tests.ts b/assembly/src/tests.ts index 39bc322..cbd3f06 100644 --- a/assembly/src/tests.ts +++ b/assembly/src/tests.ts @@ -1,14 +1,9 @@ -import { Verdict } from ".."; - +@json export class Tests { + public order: i32 = 0; public type!: string; - public verdict: Verdict = Verdict.None; + public verdict: string = "none"; public left: string = ""; public right: string = ""; public instr: string = ""; -} - -export class ReportLogs { - passed: string | null; - failed: string | null; -} +} \ No newline at end of file diff --git a/assembly/util/helpers.ts b/assembly/util/helpers.ts index 17e4424..e928d7d 100644 --- a/assembly/util/helpers.ts +++ b/assembly/util/helpers.ts @@ -83,4 +83,4 @@ export function diff(left: string, right: string, not: boolean = false): Diff { @inline export function colorText(format: i32[], text: string): string { return `\u001b[${format[0].toString()}m${text}\u001b[${format[1].toString()}m`; -} +} \ No newline at end of file diff --git a/assembly/util/term.ts b/assembly/util/term.ts index d2befe0..8f1a44d 100644 --- a/assembly/util/term.ts +++ b/assembly/util/term.ts @@ -1,40 +1,42 @@ -export class Log { - private line: i32 = 0; - constructor(line: i32 = 0) { - this.line = line; +export class TermLine { + public start: i32 = 0; + public end: i32 = 0; + constructor(start: i32 = 0, end: i32 = 0) { + this.start = start; + this.end = end; } - edit(data: string): Log { - term.clearLn(this.line); + edit(data: string): TermLine { + let end = this.end; + while (--end >= this.start) { + term.clearLn(end); + } process.stdout.write(data); - process.stdout.write("\x1B[999B"); - process.stdout.write("\x1B[0G"); - return new Log(this.line); + term.resetCursor(); + return new TermLine(this.end); + } + clear(): void { + term.clearLn(this.start); } } export namespace term { export let lines: i32 = 0; - export function write(data: string): Log { - process.stdout.write(data); - return new Log(term.lines++); - } - export function writeLn(data: string): void { + export function write(data: string): TermLine { + const start = term.lines; for (let i = 0; i < data.length; i++) { const code = data.charCodeAt(i); if (code === 10) term.lines++; } - term.lines++; - process.stdout.write(data + "\n"); + process.stdout.write(data); + return new TermLine(start, term.lines); } export function clearLn(line: i32): void { process.stdout.write(`\u001B[${term.lines - line}A`); process.stdout.write("\x1B[2K"); process.stdout.write("\x1B[0G"); } - export function editLn(data: string, ln: i32): void { - process.stdout.write(`\u001B[${ln}A`); - process.stdout.write("\x1B[2K"); + export function resetCursor(): void { + process.stdout.write("\x1B[999B"); process.stdout.write("\x1B[0G"); - term.writeLn(data); } } \ No newline at end of file diff --git a/assets/img/screenshot.png b/assets/img/download.png similarity index 100% rename from assets/img/screenshot.png rename to assets/img/download.png diff --git a/bin/run.js b/bin/run.js index a50ab6b..d879b2c 100644 --- a/bin/run.js +++ b/bin/run.js @@ -1,44 +1,175 @@ import chalk from "chalk"; -import { execSync } from "child_process"; +import { exec } from "child_process"; import { glob } from "glob"; -import { getExec, loadConfig } from "./util.js"; +import { formatTime, getExec, loadConfig } from "./util.js"; import * as path from "path"; +import { existsSync, mkdirSync, writeFileSync } from "fs"; const CONFIG_PATH = path.join(process.cwd(), "./as-test.config.json"); +const ansi = new RegExp("[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]+)*|[a-zA-Z\\d]+(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)|(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-nq-uy=><~]))", "g"); export async function run() { const reports = []; const config = loadConfig(CONFIG_PATH); const inputFiles = await glob(config.input); console.log(chalk.dim("Running tests using " + config.runOptions.runtime.name + "")); - const exec = config.runOptions.runtime.run.split(" ")[0]; - let execPath = getExec(exec); + const command = config.runOptions.runtime.run.split(" ")[0]; + let execPath = getExec(command); if (!execPath) { - console.log(`${chalk.bgRed(" ERROR ")}${chalk.dim(":")} could not locate ${exec} in PATH variable!`); + console.log(`${chalk.bgRed(" ERROR ")}${chalk.dim(":")} could not locate ${command} in PATH variable!`); process.exit(0); } - for (const file of inputFiles) { + if (inputFiles.length) { + console.log(chalk.bold.blueBright(` _____ _____ _____ _____ _____ _____ `)); + console.log(chalk.bold.blueBright(`| _ || __| ___|_ _|| __|| __||_ _|`)); + console.log(chalk.bold.blueBright(`| ||__ ||___| | | | __||__ | | | `)); + console.log(chalk.bold.blueBright(`|__|__||_____| |_| |_____||_____| |_| `)); + console.log(chalk.dim("\n------------------- v0.2.1 -------------------\n")); + } + for (const plugin of Object.keys(config.plugins)) { + if (!config.plugins[plugin]) + continue; + console.log(chalk.bgBlueBright(" PLUGIN ") + " " + chalk.dim("Using " + plugin.slice(0, 1).toUpperCase() + plugin.slice(1)) + "\n"); + } + for (let i = 0; i < inputFiles.length; i++) { + const file = inputFiles[i]; const outFile = path.join(config.outDir, file.slice(file.lastIndexOf("/") + 1).replace(".ts", ".wasm")); let cmd = config.runOptions.runtime.run - .replace(exec, execPath) + .replace(command, execPath) .replace("", outFile); if (config.buildOptions.target == "bindings") { cmd = config.runOptions.runtime.run - .replace(exec, execPath) + .replace(command, execPath) .replace("", outFile.replace(".wasm", ".js")); } - execSync(cmd, { stdio: "inherit" }); /* - process.stdout.write(stdout.toString().slice(0, stdout.indexOf("--REPORT-START--"))); - const report = stdout - .toString() - .slice( - stdout.indexOf("--REPORT-START--") + 16, - stdout.indexOf("--REPORT-END--"), - ); - reports.push(JSON.parse(report));*/ - } - //report(JSON.stringify(reports)); - for (const report of reports) { - if (report.verdict == "fail") - process.exit(1); + const report = JSON.parse(await (() => { + return new Promise((res, _) => { + let stdout = ""; + const io = exec(cmd); + io.stdout.pipe(process.stdout); + io.stderr.pipe(process.stderr); + io.stdout.on("data", (data) => { + stdout += data; + }); + io.stdout.on("close", () => { + res(stdout.slice(stdout.indexOf("START_READ") + 10, stdout.indexOf("END_READ"))); + }); + }); + })()); + reports.push(report); + } + if (config.logs && config.logs != "none") { + if (!existsSync(path.join(process.cwd(), config.logs))) { + mkdirSync(path.join(process.cwd(), config.logs)); + } + writeFileSync(path.join(process.cwd(), config.logs, "test.log.json"), JSON.stringify(reports, null, 2)); + } + const reporter = new Reporter(reports); + if (reporter.failed.length) { + console.log(chalk.dim("----------------- [FAILED] -------------------\n")); + for (const failed of reporter.failed) { + console.log(`${chalk.bgRed(" FAIL ")} ${chalk.dim(failed.description)}\n`); + for (const test of failed.tests) { + if (test.verdict == "fail") { + console.log(`${chalk.dim("(expected) ->")} ${chalk.bold(test._left.toString())}`); + console.log(`${chalk.dim("(received) ->")} ${chalk.bold(test._right.toString())}\n`); + } + } + } + } + console.log("----------------- [RESULTS] ------------------\n"); + process.stdout.write(chalk.bold("Files: ")); + if (reporter.failedFiles) { + process.stdout.write(chalk.bold.red(reporter.failedFiles + " failed")); } + else { + process.stdout.write(chalk.bold.greenBright("0 failed")); + } + process.stdout.write(", " + (reporter.failedFiles + reporter.passedFiles) + " total\n"); + process.stdout.write(chalk.bold("Suites: ")); + if (reporter.failedSuites) { + process.stdout.write(chalk.bold.red(reporter.failedSuites + " failed")); + } + else { + process.stdout.write(chalk.bold.greenBright("0 failed")); + } + process.stdout.write(", " + (reporter.failedSuites + reporter.passedSuites) + " total\n"); + process.stdout.write(chalk.bold("Tests: ")); + if (reporter.failedTests) { + process.stdout.write(chalk.bold.red(reporter.failedTests + " failed")); + } + else { + process.stdout.write(chalk.bold.greenBright("0 failed")); + } + process.stdout.write(", " + (reporter.failedTests + reporter.passedTests) + " total\n"); + process.stdout.write(chalk.bold("Time: ") + formatTime(reporter.time) + "\n"); + if (reporter.failedFiles) + process.exit(1); process.exit(0); } +class Reporter { + constructor(reports) { + this.passedFiles = 0; + this.failedFiles = 0; + this.passedSuites = 0; + this.failedSuites = 0; + this.passedTests = 0; + this.failedTests = 0; + this.failed = []; + this.time = 0.0; + this.readReports(reports); + } + readReports(reports) { + for (const file of reports) { + this.readFile(file); + } + } + readFile(file) { + let failed = false; + for (const suite of file) { + if (suite.verdict == "fail") { + failed = true; + this.failedSuites++; + } + else { + this.passedSuites++; + } + this.time += suite.time.end - suite.time.start; + for (const subSuite of suite.suites) { + this.readSuite(subSuite); + } + for (const test of suite.tests) { + if (test.verdict == "fail") + this.failed.push(suite); + this.readTest(test); + } + } + if (failed) + this.failedFiles++; + else + this.passedFiles++; + } + readSuite(suite) { + if (suite.verdict == "fail") { + this.failedSuites++; + } + else { + this.passedSuites++; + } + this.time += suite.time.end - suite.time.start; + for (const subSuite of suite.suites) { + this.readSuite(subSuite); + } + for (const test of suite.tests) { + if (test.verdict == "fail") + this.failed.push(suite); + this.readTest(test); + } + } + readTest(test) { + if (test.verdict == "fail") { + this.failedTests++; + } + else { + this.passedTests++; + } + } +} diff --git a/bin/types.js b/bin/types.js index 3e7314f..739ab9e 100644 --- a/bin/types.js +++ b/bin/types.js @@ -2,6 +2,7 @@ export class Config { constructor() { this.input = ["./assembly/__tests__/*.spec.ts"]; this.outDir = "./build"; + this.logs = "./logs"; this.config = "none"; this.buildOptions = new BuildOptions(); this.runOptions = new RunOptions(); diff --git a/cli/run.ts b/cli/run.ts index 7c9b80d..028b39d 100644 --- a/cli/run.ts +++ b/cli/run.ts @@ -1,12 +1,14 @@ import chalk from "chalk"; -import { execSync } from "child_process"; +import { exec, execSync } from "child_process"; import { glob } from "glob"; -import { report } from "../build/log.reporter.js"; -import { getExec, loadConfig } from "./util.js"; +import { formatTime, getExec, loadConfig } from "./util.js"; import * as path from "path"; +import { appendFileSync, existsSync, mkdirSync, writeFileSync } from "fs"; const CONFIG_PATH = path.join(process.cwd(), "./as-test.config.json"); + +const ansi = new RegExp("[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]+)*|[a-zA-Z\\d]+(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)|(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-nq-uy=><~]))", "g"); export async function run() { const reports: any[] = []; const config = loadConfig(CONFIG_PATH); @@ -16,40 +18,174 @@ export async function run() { chalk.dim("Running tests using " + config.runOptions.runtime.name + ""), ); - const exec = config.runOptions.runtime.run.split(" ")[0]; - let execPath = getExec(exec); + const command = config.runOptions.runtime.run.split(" ")[0]; + let execPath = getExec(command); if (!execPath) { - console.log(`${chalk.bgRed(" ERROR ")}${chalk.dim(":")} could not locate ${exec} in PATH variable!`); + console.log(`${chalk.bgRed(" ERROR ")}${chalk.dim(":")} could not locate ${command} in PATH variable!`); process.exit(0); } - for (const file of inputFiles) { + if (inputFiles.length) { + console.log(chalk.bold.blueBright(` _____ _____ _____ _____ _____ _____ `)); + console.log(chalk.bold.blueBright(`| _ || __| ___|_ _|| __|| __||_ _|`)); + console.log(chalk.bold.blueBright(`| ||__ ||___| | | | __||__ | | | `)); + console.log(chalk.bold.blueBright(`|__|__||_____| |_| |_____||_____| |_| `)); + console.log(chalk.dim("\n------------------- v0.2.1 -------------------\n")); + } + + for (const plugin of Object.keys(config.plugins)) { + if (!config.plugins[plugin]) continue; + console.log(chalk.bgBlueBright(" PLUGIN ") + " " + chalk.dim("Using " + plugin.slice(0, 1).toUpperCase() + plugin.slice(1)) + "\n") + } + + for (let i = 0; i < inputFiles.length; i++) { + const file = inputFiles[i]; const outFile = path.join(config.outDir, file.slice(file.lastIndexOf("/") + 1).replace(".ts", ".wasm")); let cmd = config.runOptions.runtime.run - .replace(exec, execPath) + .replace(command, execPath) .replace("", outFile); if (config.buildOptions.target == "bindings") { cmd = config.runOptions.runtime.run - .replace(exec, execPath) + .replace(command, execPath) .replace("", outFile.replace(".wasm", ".js")); } - execSync(cmd, { stdio: "inherit"});/* - process.stdout.write(stdout.toString().slice(0, stdout.indexOf("--REPORT-START--"))); - const report = stdout - .toString() - .slice( - stdout.indexOf("--REPORT-START--") + 16, - stdout.indexOf("--REPORT-END--"), - ); - reports.push(JSON.parse(report));*/ + + const report = JSON.parse(await (() => { + return new Promise((res, _) => { + let stdout = ""; + const io = exec(cmd); + io.stdout.pipe(process.stdout); + io.stderr.pipe(process.stderr); + + io.stdout.on("data", (data: string) => { + stdout += data; + }); + + io.stdout.on("close", () => { + res(stdout.slice(stdout.indexOf("START_READ") + 10, stdout.indexOf("END_READ"))); + }); + }); + })()); + reports.push(report); + } + + if (config.logs && config.logs != "none") { + if (!existsSync(path.join(process.cwd(), config.logs))) { + mkdirSync(path.join(process.cwd(), config.logs)); + } + writeFileSync(path.join(process.cwd(), config.logs, "test.log.json"), JSON.stringify(reports, null, 2)); + } + const reporter = new Reporter(reports); + + if (reporter.failed.length) { + console.log(chalk.dim("----------------- [FAILED] -------------------\n")); + for (const failed of reporter.failed) { + console.log(`${chalk.bgRed(" FAIL ")} ${chalk.dim(failed.description)}\n`); + for (const test of failed.tests) { + if (test.verdict == "fail") { + console.log(`${chalk.dim("(expected) ->")} ${chalk.bold(test._left.toString())}`); + console.log(`${chalk.dim("(received) ->")} ${chalk.bold(test._right.toString())}\n`); + } + } + } } - //report(JSON.stringify(reports)); + console.log("----------------- [RESULTS] ------------------\n"); + + process.stdout.write(chalk.bold("Files: ")); + if (reporter.failedFiles) { + process.stdout.write(chalk.bold.red(reporter.failedFiles + " failed")); + } else { + process.stdout.write(chalk.bold.greenBright("0 failed")); + } + process.stdout.write(", " + (reporter.failedFiles + reporter.passedFiles) + " total\n"); + + process.stdout.write(chalk.bold("Suites: ")); + if (reporter.failedSuites) { + process.stdout.write(chalk.bold.red(reporter.failedSuites + " failed")); + } else { + process.stdout.write(chalk.bold.greenBright("0 failed")); + } + process.stdout.write(", " + (reporter.failedSuites + reporter.passedSuites) + " total\n"); - for (const report of reports) { - if (report.verdict == "fail") process.exit(1); + process.stdout.write(chalk.bold("Tests: ")); + if (reporter.failedTests) { + process.stdout.write(chalk.bold.red(reporter.failedTests + " failed")); + } else { + process.stdout.write(chalk.bold.greenBright("0 failed")); } + process.stdout.write(", " + (reporter.failedTests + reporter.passedTests) + " total\n"); + + process.stdout.write(chalk.bold("Time: ") + formatTime(reporter.time) + "\n"); + + if (reporter.failedFiles) process.exit(1); process.exit(0); } + +class Reporter { + public passedFiles = 0; + public failedFiles = 0; + + public passedSuites = 0; + public failedSuites = 0; + + public passedTests = 0; + public failedTests = 0; + + public failed: any[] = []; + + public time = 0.0; + constructor(reports: any[]) { + this.readReports(reports); + } + readReports(reports: any[]) { + for (const file of reports) { + this.readFile(file); + } + } + readFile(file: any) { + let failed = false; + for (const suite of file) { + if (suite.verdict == "fail") { + failed = true; + this.failedSuites++; + } else { + this.passedSuites++; + } + this.time += suite.time.end - suite.time.start; + for (const subSuite of suite.suites) { + this.readSuite(subSuite); + } + for (const test of suite.tests) { + if (test.verdict == "fail") this.failed.push(suite); + this.readTest(test); + } + } + if (failed) this.failedFiles++; + else this.passedFiles++; + } + readSuite(suite: any) { + if (suite.verdict == "fail") { + this.failedSuites++; + } else { + this.passedSuites++; + } + this.time += suite.time.end - suite.time.start; + for (const subSuite of suite.suites) { + this.readSuite(subSuite); + } + for (const test of suite.tests) { + if (test.verdict == "fail") this.failed.push(suite); + this.readTest(test); + } + } + readTest(test: any) { + if (test.verdict == "fail") { + this.failedTests++; + } else { + this.passedTests++; + } + } +} \ No newline at end of file diff --git a/cli/types.ts b/cli/types.ts index 46e8bf5..653f859 100644 --- a/cli/types.ts +++ b/cli/types.ts @@ -1,6 +1,7 @@ export class Config { input: string[] = ["./assembly/__tests__/*.spec.ts"]; outDir: string = "./build"; + logs: string = "./logs"; config: string = "none"; plugins: {}; buildOptions: BuildOptions = new BuildOptions(); diff --git a/package.json b/package.json index 99171cf..44a8a4d 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,6 @@ "pretest": "node ./bin/index.js build", "build:transform": "tsc -p ./transform", "build:cli": "tsc -p cli", - "build:log": "asc ./reporters/log/index.ts -o ./build/log.reporter.wasm --exportRuntime --bindings esm --transform json-as/transform", "prettier": "prettier -w .", "prepublish": "npm run build:cli && npm run build:transform && npm run test" }, @@ -32,7 +31,7 @@ "chalk": "^5.3.0", "glob": "^11.0.0", "jest": "^29.7.0", - "json-as": "^0.9.13" + "json-as": "^0.9.14" }, "overrides": { "assemblyscript": "$assemblyscript", diff --git a/plugins/coverage/config.json b/plugins/coverage/config.json deleted file mode 100644 index e1f963e..0000000 --- a/plugins/coverage/config.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "name": "coverage", - "options": { - "reporter": "./reporter.ts", - "transform": "./lib/index.js" - } -} diff --git a/plugins/coverage/reporter.ts b/plugins/coverage/reporter.ts deleted file mode 100644 index 768a0cd..0000000 --- a/plugins/coverage/reporter.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { __HASHES, __POINTS } from "../../assembly/coverage"; -import { Result } from ".."; -export function addToResults(): Result { - const result = new Result("Coverage", __HASHES().size, __POINTS()); - return result; -} diff --git a/plugins/coverage/transform.ts b/plugins/coverage/transform.ts deleted file mode 100644 index e69de29..0000000 diff --git a/plugins/index.ts b/plugins/index.ts deleted file mode 100644 index 3e55bf0..0000000 --- a/plugins/index.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { rainbow } from "as-rainbow"; - -export class Result { - public name: string; - public arg1: i32; - public arg2: i32; - constructor(name: string, arg1: i32, arg2: i32) { - this.name = name; - this.arg1 = arg1; - this.arg2 = arg2; - } - display(): string { - let out = ""; - out += `${rainbow.boldMk(this.name)} `; - if (this.arg1) { - out += `${rainbow.boldMk(rainbow.red(this.arg1.toString() + " " + "failed"))}`; - } else { - out += `${rainbow.boldMk(rainbow.green("0 failed"))}`; - } - out += ` ${this.arg1 + this.arg2} total\n`; - return out; - } -} diff --git a/plugins/tsconfig.json b/plugins/tsconfig.json deleted file mode 100644 index 86b8816..0000000 --- a/plugins/tsconfig.json +++ /dev/null @@ -1,97 +0,0 @@ -{ - "extends": "assemblyscript/std/assembly.json", - "include": ["./**/*.ts"], - "compilerOptions": { - /* Visit https://aka.ms/tsconfig to read more about this file */ - /* Projects */ - // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */ - // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ - // "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */ - // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */ - // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ - // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ - /* Language and Environment */ - "target": "es2016" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */, - // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ - // "jsx": "preserve", /* Specify what JSX code is generated. */ - "experimentalDecorators": true /* Enable experimental support for TC39 stage 2 draft decorators. */, - "emitDecoratorMetadata": true /* Emit design-type metadata for decorated declarations in source files. */, - // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */ - // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ - // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */ - // "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */ - // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ - // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ - // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ - /* Modules */ - "module": "commonjs" /* Specify what module code is generated. */, - // "rootDir": "./", /* Specify the root folder within your source files. */ - // "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */ - // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ - // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ - // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ - // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */ - // "types": [], /* Specify type package names to be included without being referenced in a source file. */ - // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ - // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ - // "resolveJsonModule": true, /* Enable importing .json files. */ - // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ - /* JavaScript Support */ - // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */ - // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ - // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ - /* Emit */ - // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ - // "declarationMap": true, /* Create sourcemaps for d.ts files. */ - // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ - // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ - // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */ - // "outDir": "./", /* Specify an output folder for all emitted files. */ - // "removeComments": true, /* Disable emitting comments. */ - // "noEmit": true, /* Disable emitting files from a compilation. */ - // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ - // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */ - // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ - // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ - // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ - // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ - // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ - // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ - // "newLine": "crlf", /* Set the newline character for emitting files. */ - // "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */ - // "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */ - // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ - // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */ - // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ - // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */ - /* Interop Constraints */ - // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ - // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ - "esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */, - // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ - "forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */, - /* Type Checking */ - "strict": false /* Enable all strict type-checking options. */, - // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */ - "strictNullChecks": true /* When type checking, take into account 'null' and 'undefined'. */, - // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ - // "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */ - // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ - // "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */ - // "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */ - // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ - "noUnusedLocals": true /* Enable error reporting when local variables aren't read. */, - "noUnusedParameters": true /* Raise an error when a function parameter isn't read. */, - // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ - // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ - // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ - // "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */ - // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ - // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */ - // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ - // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ - /* Completeness */ - // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ - "skipLibCheck": true /* Skip type checking all .d.ts files. */ - } -} diff --git a/reporters/json/index.ts b/reporters/json/index.ts deleted file mode 100644 index 035c06f..0000000 --- a/reporters/json/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export function report(_logs: string): string { - return _logs; -} diff --git a/reporters/report.ts b/reporters/report.ts deleted file mode 100644 index 5072817..0000000 --- a/reporters/report.ts +++ /dev/null @@ -1,108 +0,0 @@ -import { Verdict } from "../assembly"; -import { Suite } from "../assembly/src/suite"; -import { Tests } from "../assembly/src/tests"; - - -@json -export class Time { - start: f64 = 0; - end: f64 = 0; - format(): string { - return formatTime(this.end - this.start); - } -} - - -@json -export class Report { - time: Time = new Time(); - plugins: string[] = []; - file: string = "unknown"; - verdict: Verdict = Verdict.None; - groups: SuiteReport[] = []; -} - - -@json -export class SuiteReport { - time: Time = new Time(); - kind: string = ""; - verdict: Verdict = Verdict.None; - description: string = ""; - tests: TestReport[] = []; - suites: SuiteReport[] = []; - logs: string[] = []; - errors: string[] = []; - static wrap(suite: Suite): SuiteReport { - const report = new SuiteReport(); - - for (let i = 0; i < (suite).suites.length; i++) { - const _suite = unchecked((suite).suites[i]); - report.suites.push(SuiteReport.wrap(_suite)); - } - - for (let i = 0; i < (suite).tests.length; i++) { - const test = unchecked((suite).tests[i]); - report.tests.push(TestReport.wrap(test)); - } - - report.description = suite.description; - report.verdict = suite.verdict; - report.kind = suite.kind; - report.time = suite.time; - report.logs = suite.logs; - - return report; - } -} - - -@json -export class TestReport { - verdict: Verdict = Verdict.None; - left: string = ""; - instr: string = ""; - right: string = ""; - static wrap(test: Tests): TestReport { - const report = new TestReport(); - - report.verdict = test.verdict; - report.left = test.left; - report.instr = test.instr; - report.right = test.right; - - return report; - } -} - -class Unit { - name: string; - divisor: number; -} - -function formatTime(time: f64): string { - if (time < 0) return "0.00μs"; - - const us = time * 1000; - - const units: Unit[] = [ - { name: "μs", divisor: 1 }, - { name: "ms", divisor: 1000 }, - { name: "s", divisor: 1000 * 1000 }, - { name: "m", divisor: 60 * 1000 * 1000 }, - { name: "h", divisor: 60 * 60 * 1000 * 1000 }, - { name: "d", divisor: 24 * 60 * 60 * 1000 * 1000 }, - ]; - - for (let i = units.length - 1; i >= 0; i--) { - const unit = units[i]; - if (us >= unit.divisor) { - const value = (Math.round((us / unit.divisor) * 100) / 100).toString(); - return `${value}${unit.name}`; - } - } - - const _us = (Math.round(us * 100) / 100).toString(); - - return `${_us}μs`; -} diff --git a/reporters/tsconfig.json b/reporters/tsconfig.json deleted file mode 100644 index 86b8816..0000000 --- a/reporters/tsconfig.json +++ /dev/null @@ -1,97 +0,0 @@ -{ - "extends": "assemblyscript/std/assembly.json", - "include": ["./**/*.ts"], - "compilerOptions": { - /* Visit https://aka.ms/tsconfig to read more about this file */ - /* Projects */ - // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */ - // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ - // "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */ - // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */ - // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ - // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ - /* Language and Environment */ - "target": "es2016" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */, - // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ - // "jsx": "preserve", /* Specify what JSX code is generated. */ - "experimentalDecorators": true /* Enable experimental support for TC39 stage 2 draft decorators. */, - "emitDecoratorMetadata": true /* Emit design-type metadata for decorated declarations in source files. */, - // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */ - // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ - // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */ - // "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */ - // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ - // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ - // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ - /* Modules */ - "module": "commonjs" /* Specify what module code is generated. */, - // "rootDir": "./", /* Specify the root folder within your source files. */ - // "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */ - // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ - // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ - // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ - // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */ - // "types": [], /* Specify type package names to be included without being referenced in a source file. */ - // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ - // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ - // "resolveJsonModule": true, /* Enable importing .json files. */ - // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ - /* JavaScript Support */ - // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */ - // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ - // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ - /* Emit */ - // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ - // "declarationMap": true, /* Create sourcemaps for d.ts files. */ - // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ - // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ - // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */ - // "outDir": "./", /* Specify an output folder for all emitted files. */ - // "removeComments": true, /* Disable emitting comments. */ - // "noEmit": true, /* Disable emitting files from a compilation. */ - // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ - // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */ - // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ - // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ - // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ - // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ - // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ - // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ - // "newLine": "crlf", /* Set the newline character for emitting files. */ - // "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */ - // "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */ - // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ - // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */ - // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ - // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */ - /* Interop Constraints */ - // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ - // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ - "esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */, - // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ - "forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */, - /* Type Checking */ - "strict": false /* Enable all strict type-checking options. */, - // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */ - "strictNullChecks": true /* When type checking, take into account 'null' and 'undefined'. */, - // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ - // "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */ - // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ - // "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */ - // "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */ - // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ - "noUnusedLocals": true /* Enable error reporting when local variables aren't read. */, - "noUnusedParameters": true /* Raise an error when a function parameter isn't read. */, - // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ - // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ - // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ - // "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */ - // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ - // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */ - // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ - // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ - /* Completeness */ - // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ - "skipLibCheck": true /* Skip type checking all .d.ts files. */ - } -}