Skip to content

Commit 4d24f85

Browse files
committed
Add more structured output for tests
The diff and the errors were always available, but they were not being sent to the output. Additionally, make sure to send output to both the test explorer log and the codeql test log.
1 parent 245496c commit 4d24f85

5 files changed

Lines changed: 133 additions & 5 deletions

File tree

extensions/ql-vscode/CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
## [UNRELEASED]
44

55
- Editors opened by navigating from the results view are no longer opened in _preview mode_. Now they are opened as a persistent editor. [#630](https://github.com/github/vscode-codeql/pull/630)
6+
- Alter structure of the _Test Explorer_ tree. It now follows the structure of the filesystem instead of the QL Packs. [#624](https://github.com/github/vscode-codeql/pull/624)
7+
- Add more structured output for tests. [#626](https://github.com/github/vscode-codeql/pull/626)
68

79
## 1.3.6 - 4 November 2020
810

@@ -31,6 +33,7 @@
3133
- Remove feature flag for the AST Viewer. For more information on how to use the AST Viewer, [see the documentation](https://help.semmle.com/codeql/codeql-for-vscode/procedures/exploring-the-structure-of-your-source-code.html).
3234
- The `codeQL.runningTests.numberOfThreads` setting is now used correctly when running tests.
3335
- Alter structure of the _Test Explorer_ tree. It now follows the structure of the filesystem instead of the qlpacks.
36+
- Ensure output of CodeQL test runs includes compilation error messages and test failure messages.
3437

3538
## 1.3.3 - 16 September 2020
3639

extensions/ql-vscode/src/cli.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import { DistributionProvider, FindDistributionResultKind } from './distribution
1717
import { assertNever } from './pure/helpers-pure';
1818
import { QueryMetadata, SortDirection } from './pure/interface-types';
1919
import { Logger, ProgressReporter } from './logging';
20+
import { CompilationMessage } from './pure/messages';
2021

2122
/**
2223
* The version of the SARIF format that we are using.
@@ -90,10 +91,11 @@ export interface TestRunOptions {
9091
export interface TestCompleted {
9192
test: string;
9293
pass: boolean;
93-
messages: string[];
94+
messages: CompilationMessage[];
9495
compilationMs: number;
9596
evaluationMs: number;
9697
expected: string;
98+
diff: string[] | undefined;
9799
}
98100

99101
/**

extensions/ql-vscode/src/test-adapter.ts

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -217,10 +217,26 @@ export class QLTestAdapter extends DisposableObject implements TestAdapter {
217217
cancellationToken: cancellationToken,
218218
logger: testLogger
219219
})) {
220+
const state = event.pass
221+
? 'passed'
222+
: event.messages?.length
223+
? 'errored'
224+
: 'failed';
225+
let message: string | undefined;
226+
if (event.diff?.length) {
227+
message = ['', `${state}: ${event.test}`, ...event.diff, ''].join('\n');
228+
testLogger.log(message);
229+
}
230+
(event.diff || []).join('\n');
220231
this._testStates.fire({
221232
type: 'test',
222-
state: event.pass ? 'passed' : 'failed',
223-
test: event.test
233+
state,
234+
test: event.test,
235+
message,
236+
decorations: event.messages?.map(msg => ({
237+
line: msg.position.line,
238+
message: msg.message
239+
}))
224240
});
225241
}
226242
}

extensions/ql-vscode/src/vscode-tests/no-workspace/databases.test.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,9 @@ describe('databases', () => {
2424
databaseManager = new DatabaseManager(
2525
{
2626
workspaceState: {
27-
update: updateSpy
28-
}
27+
update: updateSpy,
28+
get: sinon.stub()
29+
},
2930
} as unknown as ExtensionContext,
3031
{} as QueryServerConfig,
3132
{} as Logger,
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
import 'vscode-test';
2+
import 'mocha';
3+
import * as sinon from 'sinon';
4+
import { Uri, WorkspaceFolder } from 'vscode';
5+
import { expect } from 'chai';
6+
7+
import { QLTestAdapter } from '../../test-adapter';
8+
import { CodeQLCliServer } from '../../cli';
9+
10+
describe('test-adapter', () => {
11+
let adapter: QLTestAdapter;
12+
let runTestsSpy: sinon.SinonStub;
13+
let resolveTestsSpy: sinon.SinonStub;
14+
let resolveQlpacksSpy: sinon.SinonStub;
15+
let sandox: sinon.SinonSandbox;
16+
17+
beforeEach(() => {
18+
sandox = sinon.createSandbox();
19+
mockRunTests();
20+
resolveQlpacksSpy = sandox.stub().resolves({});
21+
resolveTestsSpy = sandox.stub().resolves([]);
22+
adapter = new QLTestAdapter({
23+
name: 'ABC',
24+
uri: Uri.parse('file:/ab/c')
25+
} as WorkspaceFolder, {
26+
runTests: runTestsSpy,
27+
resolveQlpacks: resolveQlpacksSpy,
28+
resolveTests: resolveTestsSpy
29+
} as unknown as CodeQLCliServer);
30+
});
31+
32+
afterEach(() => {
33+
sandox.restore();
34+
});
35+
36+
it('should run some tests', async () => {
37+
38+
const listenerSpy = sandox.spy();
39+
adapter.testStates(listenerSpy);
40+
const testsPath = Uri.parse('file:/ab/c').fsPath;
41+
const dPath = Uri.parse('file:/ab/c/d.ql').fsPath;
42+
const gPath = Uri.parse('file:/ab/c/e/f/g.ql').fsPath;
43+
const hPath = Uri.parse('file:/ab/c/e/f/h.ql').fsPath;
44+
45+
await adapter.run([testsPath]);
46+
47+
expect(listenerSpy.getCall(0).args).to.deep.eq([
48+
{ type: 'started', tests: [testsPath] }
49+
]);
50+
expect(listenerSpy.getCall(1).args).to.deep.eq([{
51+
type: 'test',
52+
state: 'passed',
53+
test: dPath,
54+
message: undefined,
55+
decorations: []
56+
}]);
57+
expect(listenerSpy.getCall(2).args).to.deep.eq([{
58+
type: 'test',
59+
state: 'errored',
60+
test: gPath,
61+
message: `\nerrored: ${gPath}\npqr\nxyz\n`,
62+
decorations: [
63+
{ line: 1, message: 'abc' }
64+
]
65+
}]);
66+
expect(listenerSpy.getCall(3).args).to.deep.eq([{
67+
type: 'test',
68+
state: 'failed',
69+
test: hPath,
70+
message: `\nfailed: ${hPath}\njkh\ntuv\n`,
71+
decorations: []
72+
}]);
73+
expect(listenerSpy.getCall(4).args).to.deep.eq([{ type: 'finished' }]);
74+
expect(listenerSpy).to.have.callCount(5);
75+
});
76+
77+
function mockRunTests() {
78+
// runTests is an async generator function. This is not directly supported in sinon
79+
// However, we can pretend the same thing by just returning an async array.
80+
runTestsSpy = sandox.stub();
81+
runTestsSpy.returns(
82+
(async function*() {
83+
yield Promise.resolve({
84+
test: Uri.parse('file:/ab/c/d.ql').fsPath,
85+
pass: true,
86+
messages: []
87+
});
88+
yield Promise.resolve({
89+
test: Uri.parse('file:/ab/c/e/f/g.ql').fsPath,
90+
pass: false,
91+
diff: ['pqr', 'xyz'],
92+
// a compile error
93+
messages: [
94+
{ position: { line: 1 }, message: 'abc' }
95+
]
96+
});
97+
yield Promise.resolve({
98+
test: Uri.parse('file:/ab/c/e/f/h.ql').fsPath,
99+
pass: false,
100+
diff: ['jkh', 'tuv'],
101+
messages: []
102+
});
103+
})()
104+
);
105+
}
106+
});

0 commit comments

Comments
 (0)