Skip to content

Commit

Permalink
feat(report): add line number reporter for assertion
Browse files Browse the repository at this point in the history
  • Loading branch information
TomokiMiyauci committed Nov 30, 2021
1 parent 2a5029c commit eb9f47b
Show file tree
Hide file tree
Showing 6 changed files with 193 additions and 1 deletion.
2 changes: 2 additions & 0 deletions deps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,13 @@ export {

export {
blue,
brightBlack,
gray,
green,
red,
yellow,
} from "https://deno.land/std@0.116.0/fmt/colors.ts";
export { fromFileUrl } from "https://deno.land/std@0.116.0/path/mod.ts";

// third party

Expand Down
3 changes: 3 additions & 0 deletions report/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# report

assert result reporter
35 changes: 35 additions & 0 deletions report/assertion.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// Copyright 2021-Present the Unitest authors. All rights reserved. MIT license.
import { brightBlack, red } from "../deps.ts";

type CodeInfo = {
code: string;
lineNumber: number;
column: number;
};

// /** insert something to beginning of line */
// function BOL(text: string, symbol: string): string {
// return `${symbol}${text.replaceAll("\n", `\n${symbol}`)}`;
// }

function prettyCode({ code, lineNumber }: CodeInfo): string {
const codes = code.split("\n");

const sliced = codes.slice(
lineNumber - 2,
lineNumber + 2,
);

const numberedCodes = sliced.map((fragment, i) => {
const number = i + lineNumber - 1;
const isWrongLine = number === lineNumber;

return `${isWrongLine ? red(">") : " "} ${brightBlack(String(number))} ${
brightBlack("|")
} ${isWrongLine ? fragment : brightBlack(fragment)}`;
});

return numberedCodes.join("\n");
}

export { prettyCode };
33 changes: 33 additions & 0 deletions report/stack_trace.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// Copyright 2021-Present the Unitest authors. All rights reserved. MIT license.
type StackTrace = {
file: string;
methodName: string;
lineNumber: number;
column: number;
};

function parseStackTraceLine(line: string): StackTrace | null {
const re =
/^\s*at (?<methodName>\S+) \(?(?<file>\S+):(?<lineNumber>\d+):(?<column>\d+)\)?.*$/i;

const result = re.exec(line);
if (!result || !result.groups) return null;
const { file, methodName, lineNumber, column } = result.groups;

return {
file,
methodName,
lineNumber: Number(lineNumber),
column: Number(column),
};
}

function parseStackTrace(stack: string): StackTrace[] {
const lines = stack.split("\n");

const traces = lines.map((line) => parseStackTraceLine(line));

return traces.filter(Boolean) as StackTrace[];
}

export { parseStackTrace, parseStackTraceLine };
86 changes: 86 additions & 0 deletions report/stack_trace_test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
// Copyright 2021-Present the Unitest authors. All rights reserved. MIT license.
import { assertEquals } from "../dev_deps.ts";
import { parseStackTrace, parseStackTraceLine } from "./stack_trace.ts";

Deno.test({
name: "parseStackTraceLine",
fn: () => {
const table: [
...Parameters<typeof parseStackTraceLine>,
ReturnType<typeof parseStackTraceLine>,
][] = [
[
` at main (file:///path/to/file.ts:23:11)`,
{
file: "file:///path/to/file.ts",
methodName: "main",
lineNumber: 23,
column: 11,
},
],
[
` at assertEquals (https://deno.land/std@0.115.1/testing/asserts.ts:266:9)`,
{
file: "https://deno.land/std@0.115.1/testing/asserts.ts",
methodName: "assertEquals",
lineNumber: 266,
column: 9,
},
],

[
` at assertEquals https://deno.land/std@0.115.1/testing/asserts.ts:266:9`,
{
file: "https://deno.land/std@0.115.1/testing/asserts.ts",
methodName: "assertEquals",
lineNumber: 266,
column: 9,
},
],

[
` at Array.forEach (<anonymous>)`,
null,
],
];

table.forEach(([value, result]) => {
assertEquals(parseStackTraceLine(value), result);
});
},
});

Deno.test({
name: "trace",
fn: () => {
const table: [
...Parameters<typeof parseStackTrace>,
ReturnType<typeof parseStackTrace>,
][] = [
[
`ReferenceError: FAIL is not defined
at Constraint.execute (deltablue.js:525:2)
at Constraint.execute anonymous
at Constraint.recalculate (deltablue.js:424:21)`,
[
{
file: "deltablue.js",
methodName: "Constraint.execute",
lineNumber: 525,
column: 2,
},
{
file: "deltablue.js",
methodName: "Constraint.recalculate",
lineNumber: 424,
column: 21,
},
],
],
];

table.forEach(([value, result]) => {
assertEquals(parseStackTrace(value), result);
});
},
});
35 changes: 34 additions & 1 deletion test/mod.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
// Copyright 2021-Present the Unitest authors. All rights reserved. MIT license.
import { AnyFn } from "../_types.ts";
import { isString } from "../deps.ts";
import { AssertionError, fromFileUrl, isString } from "../deps.ts";
import { each } from "./each.ts";
import { parseStackTrace } from "../report/stack_trace.ts";
import { prettyCode } from "../report/assertion.ts";

type Test<Context extends Record<PropertyKey, unknown>> = {
setup?: () => Context | void;
Expand Down Expand Up @@ -41,6 +43,37 @@ function _test<T extends Record<PropertyKey, unknown>>(

try {
await fn({ ...context, ...denoContext });
} catch (e) {
if (e instanceof Error) {
if (e.stack) {
const { state } = await Deno.permissions.query({
name: "read",
});

if (state !== "granted") {
throw e;
}

const stackTraces = parseStackTrace(e.stack);
const testFileStack = stackTraces.find(({ file }) => {
return /file:\/\/\S+_test\.[j|t]sx?$/.test(file);
});

if (!testFileStack) {
throw e;
}

const { lineNumber, column, file } = testFileStack;
const code = await Deno.readTextFile(
fromFileUrl(file),
);

const pretty = prettyCode({ code, lineNumber, column });
throw new AssertionError(`${e.message}\n${pretty}\n`);
}
} else {
throw Error("panic: unexpected error");
}
} finally {
teardown?.(context);
}
Expand Down

0 comments on commit eb9f47b

Please sign in to comment.