Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 2 additions & 7 deletions src/runners/baseRunner/RunnerResultAnalyzer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@
// Licensed under the MIT license.

import * as path from 'path';
import { Location, MarkdownString, Range, TestItem, TestMessage } from 'vscode';
import { Location, MarkdownString, Range, TestItem } from 'vscode';
import { IRunTestContext } from '../../types';
import { setTestState, TestResultState } from '../utils';

export abstract class RunnerResultAnalyzer {
constructor(protected testContext: IRunTestContext) { }
Expand All @@ -21,7 +20,7 @@ export abstract class RunnerResultAnalyzer {
return [];
}

protected processStackTrace(data: string, traces: MarkdownString, assertionFailure: TestMessage | undefined, currentItem: TestItem | undefined, projectName: string): void {
protected processStackTrace(data: string, traces: MarkdownString, currentItem: TestItem | undefined, projectName: string): void {
const traceRegExp: RegExp = /(\s?at\s+)([\w$\\.]+\/)?((?:[\w$]+\.)+[<\w$>]+)\((.*)\)/;
const traceResults: RegExpExecArray | null = traceRegExp.exec(data);
if (traceResults) {
Expand Down Expand Up @@ -55,10 +54,6 @@ export abstract class RunnerResultAnalyzer {
this.testMessageLocation = new Location(currentItem.uri, new Range(currentItem.range.start.line, 0, currentItem.range.start.line, 0));
}
}
if (assertionFailure) {
assertionFailure.location = this.testMessageLocation;
setTestState(this.testContext.testRun, currentItem, TestResultState.Failed, assertionFailure);
}
}
}
} else {
Expand Down
15 changes: 9 additions & 6 deletions src/runners/junitRunner/JUnitRunnerResultAnalyzer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,13 +107,17 @@ export class JUnitRunnerResultAnalyzer extends RunnerResultAnalyzer {
if (!this.tracingItem) {
return;
}
const testMessage: TestMessage = new TestMessage(this.traces);
const currentResultState: TestResultState = this.getCurrentState(this.tracingItem).resultState;
this.tryAppendMessage(this.tracingItem, testMessage, currentResultState);
this.recordingType = RecordingType.None;
if (this.assertionFailure) {
this.tryAppendMessage(this.tracingItem, this.assertionFailure, currentResultState);
}
if (this.traces?.value) {
this.tryAppendMessage(this.tracingItem, new TestMessage(this.traces), currentResultState);
}
if (currentResultState === TestResultState.Errored) {
setTestState(this.testContext.testRun, this.tracingItem, currentResultState);
}
this.recordingType = RecordingType.None;
} else if (data.startsWith(MessageId.ExpectStart)) {
this.recordingType = RecordingType.ExpectMessage;
} else if (data.startsWith(MessageId.ExpectEnd)) {
Expand All @@ -139,8 +143,7 @@ export class JUnitRunnerResultAnalyzer extends RunnerResultAnalyzer {
this.assertionFailure = TestMessage.diff(`Expected [${assertionResults[1]}] but was [${assertionResults[2]}]`, assertionResults[1], assertionResults[2]);
}
}

this.processStackTrace(data, this.traces, this.assertionFailure, this.tracingItem, this.projectName);
this.processStackTrace(data, this.traces, this.tracingItem, this.projectName);
}
}

Expand Down Expand Up @@ -218,6 +221,7 @@ export class JUnitRunnerResultAnalyzer extends RunnerResultAnalyzer {
this.expectString = '';
this.actualString = '';
this.recordingType = RecordingType.None;
this.testMessageLocation = undefined;
}

protected getStacktraceFilter(): string[] {
Expand Down Expand Up @@ -335,7 +339,6 @@ export class JUnitRunnerResultAnalyzer extends RunnerResultAnalyzer {
private async tryAppendMessage(item: TestItem, testMessage: TestMessage, testState: TestResultState): Promise<void> {
if (this.testMessageLocation) {
testMessage.location = this.testMessageLocation;
this.testMessageLocation = undefined;
} else if (item.uri && item.range) {
testMessage.location = new Location(item.uri, item.range);
} else {
Expand Down
4 changes: 2 additions & 2 deletions src/runners/testngRunner/TestNGRunnerResultAnalyzer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ export class TestNGRunnerResultAnalyzer extends RunnerResultAnalyzer {
// tslint:disable-next-line: no-conditional-assignment
while ((match = this.regex.exec(data)) !== null) {
try {
this.processData(match[1]);
this.processData(match[1]);
} catch (error) {
this.testContext.testRun.appendOutput(`[ERROR] Failed to parse output data: ${match[1]}\n`);
}
Expand Down Expand Up @@ -80,7 +80,7 @@ export class TestNGRunnerResultAnalyzer extends RunnerResultAnalyzer {
markdownTrace.supportHtml = true;

for (const line of outputData.attributes.trace.split(/\r?\n/)) {
this.processStackTrace(line, markdownTrace, undefined, this.currentItem, this.projectName);
this.processStackTrace(line, markdownTrace, this.currentItem, this.projectName);
}

const testMessage: TestMessage = new TestMessage(markdownTrace);
Expand Down
54 changes: 52 additions & 2 deletions test/suite/JUnitAnalyzer.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@

import * as assert from 'assert';
import * as sinon from 'sinon';
import { IRunTestContext, TestKind } from '../../src/types';
import { MarkdownString, Range, TestController, TestMessage, TestRunRequest, tests, workspace } from 'vscode';
import { JUnitRunnerResultAnalyzer } from '../../src/runners/junitRunner/JUnitRunnerResultAnalyzer';
import { IRunTestContext, TestKind } from '../../src/types';
import { generateTestItem } from './utils';

// tslint:disable: only-arrow-functions
Expand Down Expand Up @@ -146,7 +146,7 @@ java.lang.AssertionError: expected:<1> but was:<2>
analyzer.analyzeData(testRunnerOutput);

sinon.assert.calledWith(failedSpy, testItem, sinon.match.any, sinon.match.number);
const testMessage = failedSpy.getCall(0).args[1] as TestMessage;
const testMessage = failedSpy.getCall(1).args[1] as TestMessage;
const stringLiteral = (testMessage.message as MarkdownString).value;
assert.ok(stringLiteral.split('<br/>').length === 3);
});
Expand Down Expand Up @@ -336,4 +336,54 @@ org.junit.ComparisonFailure: expected:<hello

assert.strictEqual(testItem.description, '');
});

test("test diff is not duplicated when failing assertion is extracted", () => {
const range = new Range(9, 0, 11, 0);
const testItem = generateTestItem(testController, 'junit@junit5.TestWithExtractedEqualityAssertion#test', TestKind.JUnit5, range, undefined, 'TestWithExtractedEqualityAssertion.java');
const testRunRequest = new TestRunRequest([testItem], []);
const testRun = testController.createTestRun(testRunRequest);
const startedSpy = sinon.spy(testRun, 'started');
const failedSpy = sinon.spy(testRun, 'failed');
const testRunnerOutput = `%TESTC 1 v2
%TSTTREE2,junit5.TestWithExtractedEqualityAssertion,true,1,false,1,TestWithExtractedEqualityAssertion,,[engine:junit-jupiter]/[class:junit5.TestWithExtractedEqualityAssertion]
%TSTTREE3,test(junit5.TestWithExtractedEqualityAssertion),false,1,false,2,test(),,[engine:junit-jupiter]/[class:junit5.TestWithExtractedEqualityAssertion]/[method:test()]
%TESTS 3,test(junit5.TestWithExtractedEqualityAssertion)
%FAILED 3,test(junit5.TestWithExtractedEqualityAssertion)
%EXPECTS
1
%EXPECTE
%ACTUALS
2
%ACTUALE
%TRACES
org.opentest4j.AssertionFailedError: expected: <1> but was: <2>
at junit5.TestWithExtractedEqualityAssertion.extracted2(TestWithExtractedEqualityAssertion.java:18)
at junit5.TestWithExtractedEqualityAssertion.extracted1(TestWithExtractedEqualityAssertion.java:14)
at junit5.TestWithExtractedEqualityAssertion.test(TestWithExtractedEqualityAssertion.java:11)
%TRACEE
%TESTE 3,test(junit5.TestWithExtractedEqualityAssertion)
%RUNTIME55`;
const runnerContext: IRunTestContext = {
isDebug: false,
kind: TestKind.JUnit5,
projectName: 'junit',
testItems: [testItem],
testRun: testRun,
workspaceFolder: workspace.workspaceFolders?.[0]!,
};

const analyzer = new JUnitRunnerResultAnalyzer(runnerContext);
analyzer.analyzeData(testRunnerOutput);

sinon.assert.calledWith(startedSpy, testItem);
sinon.assert.calledWith(failedSpy, testItem, sinon.match.any);

const diffTestMessages = failedSpy.getCalls().map(call => call.args[1] as TestMessage).filter(v => v.actualOutput || v.expectedOutput);
assert.strictEqual(diffTestMessages.length, 1, "not more than one diff-message");
const testMessage = diffTestMessages[0];
assert.strictEqual(testMessage.expectedOutput, '1');
assert.strictEqual(testMessage.actualOutput, '2');
assert.strictEqual(testMessage.location?.range.start.line, 10); // =11 - 1, (most precise info we get from the stack trace)
});

});
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package junit5;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

class TestWithExtractedEqualityAssertion {

@Test
void test() {
}

@Test
void test1() {
extracted1();
}

@Test
void test2() {
extracted2();
}

private void extracted1() {
extracted2();
}

private void extracted2() {
Assertions.assertEquals(1, 2);
}

}