Skip to content

Commit

Permalink
Extract error message generation.
Browse files Browse the repository at this point in the history
This refactor makes it easier to use the Test Explorer. Here we
complete the separation between generating messages about why tests
failed from how we render them to the output window and diagnostic
system. This allows for easier testing.

Changes:

- extract whitespace cleaning function into cider namespace
- add tests for failure messages
- extract failure message generation into cider namespace
- extract diagnostic message generation into cider namespace
  • Loading branch information
marcomorain committed Dec 9, 2021
1 parent ba64d07 commit 40b7b1a
Show file tree
Hide file tree
Showing 3 changed files with 109 additions and 27 deletions.
53 changes: 53 additions & 0 deletions src/extension-test/unit/test-runner-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,57 @@ describe('test result processing', () => {

});

it('can produce detailed messages', () => {

expect(cider.detailedMessage({
type: 'pass',
ns: 'core',
context: 'ctx',
index: 0,
var: 'test',
message: ''
})).toBe('');

expect(cider.detailedMessage({
type: 'fail',
ns: 'core',
context: 'ctx',
index: 1,
expected: 'apple',
actual: 'orange',
var: 'test',
file: 'core.clj',
line: 7,
message: 'an extra message'
})).toBe(
`; FAIL in core/test (core.clj:7):
; ctx: an extra message
; expected:
apple
; actual:
orange`);


expect(cider.detailedMessage({
type: 'error',
ns: 'core',
context: 'ctx',
index: 1,
expected: 'apple',
actual: 'orange',
var: 'test',
error: 'shoes fell off',
file: 'impl.clj',
line: 9,
message: 'an extra message'
})).toBe(
`; ERROR in core/test (line 9):
; ctx: an extra message
; error: shoes fell off (impl.clj)
; expected:
apple`);


});

});
47 changes: 44 additions & 3 deletions src/nrepl/cider.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

// https://github.com/clojure-emacs/cider-nrepl/blob/a740583c3aa8b582f3097611787a276775131d32/src/cider/nrepl/middleware/test.clj#L45
export interface TestSummary {
ns: number;
Expand Down Expand Up @@ -38,16 +37,28 @@ export interface TestResults {
'gen-input': unknown
}

function stripTrailingNewlines(s: string): string {
return s.replace(/\r?\n$/, "");
}

export function resultMessage(resultItem: Readonly<TestResult>): string {
function resultMessage(resultItem: Readonly<TestResult>): string {
let msg = [];
if (resultItem.context && resultItem.context !== "false")
msg.push(resultItem.context);
if (resultItem.message)
msg.push(resultItem.message);
return `${msg.length > 0 ? msg.join(": ").replace(/\r?\n$/, "") : ''}`;
return `${msg.length > 0 ? stripTrailingNewlines(msg.join(": ")) : ''}`;
}


// Remove any trailing blank lines from any of the string in result.
export function cleanUpWhiteSpace(result: TestResult) {
for (const prop in result) {
if (typeof (result[prop]) === 'string') {
result[prop] = stripTrailingNewlines(result[prop]);
}
}
}
// Given a summary, return a message suitable for printing in the REPL to show
// the user a quick summary of the test run.
// Examples:
Expand Down Expand Up @@ -85,3 +96,33 @@ export function totalSummary(summaries: TestSummary[]): TestSummary {
}
return result;
}

// Return a detailed message about why a test failed.
// If the test passed, return the empty string.
// The message contains "comment" lines that are prepended with ;
// and "data" lines that should be printed verbatim into the REPL.
export function detailedMessage(result: TestResult): string {
const msg = [];
const message = resultMessage(result);
if (result.type === "error") {
msg.push(`; ERROR in ${result.ns}/${result.var} (line ${result.line}):`)
if (message) {
msg.push(`; ${message}`);
}
msg.push(`; error: ${result.error} (${result.file})`);
msg.push("; expected:");
msg.push(result.expected);
} else if (result.type === 'fail') {
msg.push(`; FAIL in ${result.ns}/${result.var} (${result.file}:${result.line}):`);
if (message) {
msg.push(`; ${message}`);
}
msg.push(`; expected:\n${result.expected}\n; actual:\n${result.actual}`);
}
return msg.join("\n");
}

// Return a short message that can be shown to user as a Diagnostic.
export function diagnosticMessage(result: TestResult): string {
return `failure in test: ${result.var} context: ${result.context}, expected ${result.expected}, got: ${result.actual}`
}
36 changes: 12 additions & 24 deletions src/testRunner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,42 +11,30 @@ import * as getText from './util/get-text';

let diagnosticCollection = vscode.languages.createDiagnosticCollection('calva');


function reportTests(results: cider.TestResults[]) {
let diagnostics: { [key: string]: vscode.Diagnostic[] } = {};
diagnosticCollection.clear();

const recordDiagnostic = (result: cider.TestResult) => {
const msg = cider.diagnosticMessage(result);
const err = new vscode.Diagnostic(new vscode.Range(result.line - 1, 0, result.line - 1, 1000), msg, vscode.DiagnosticSeverity.Error);
if (!diagnostics[result.file])
diagnostics[result.file] = [];
diagnostics[result.file].push(err);
}

for (let result of results) {
for (const ns in result.results) {
let resultSet = result.results[ns];
for (const test in resultSet) {
for (const a of resultSet[test]) {
for (const prop in a) {
if (typeof (a[prop]) === 'string') {
a[prop] = a[prop].replace(/\r?\n$/, "");
}
}

const message = cider.resultMessage(a);
cider.cleanUpWhiteSpace(a);

outputWindow.append(cider.detailedMessage(a));

if (a.type === "error") {
outputWindow.append(`; ERROR in ${ns}/${test} (line ${a.line}):`);
if (message !== '') {
outputWindow.append(`; ${message}`);
}
outputWindow.append(`; error: ${a.error} (${a.file})\n; expected:\n${a.expected}`);
}
if (a.type === "fail") {
let msg = `failure in test: ${test} context: ${a.context}, expected ${a.expected}, got: ${a.actual}`,
err = new vscode.Diagnostic(new vscode.Range(a.line - 1, 0, a.line - 1, 1000), msg, vscode.DiagnosticSeverity.Error);
if (!diagnostics[a.file])
diagnostics[a.file] = [];
diagnostics[a.file].push(err);
outputWindow.append(`; FAIL in ${ns}/${test} (${a.file}:${a.line}):`);
if (message !== '') {
outputWindow.append(`; ${message}`);
}
outputWindow.append(`; expected:\n${a.expected}\n; actual:\n${a.actual}`);
recordDiagnostic(a);
}
}
}
Expand Down

0 comments on commit 40b7b1a

Please sign in to comment.