@iamsergio/qttest-utils 0.4.5 → 0.4.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +11 -1
- package/a +8 -0
- package/foo +15 -0
- package/out/example.js +30 -3
- package/out/qttest.d.ts +13 -1
- package/out/qttest.js +90 -11
- package/package.json +1 -1
- package/src/example.ts +36 -3
- package/src/qttest.ts +113 -10
- package/test/qt_test/CMakeLists.txt +22 -0
- package/test/qt_test/CMakePresets.json +15 -0
- package/test/qt_test/test1.cpp +18 -0
- package/test/qt_test/test2.cpp +18 -0
- package/test/qt_test/test3.cpp +18 -0
- package/test1.log +31 -0
- package/test1.log1 +17 -0
package/README.md
CHANGED
|
@@ -4,4 +4,14 @@ A nodejs module for listing Qt Test executables and their individual test slots
|
|
|
4
4
|
|
|
5
5
|
To be used by vscode extensions that implement the `Testing API`, but can also be used standalone for whatever reason ;).
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
|
|
8
|
+
## Example
|
|
9
|
+
|
|
10
|
+
```
|
|
11
|
+
$ cd test/qt_test
|
|
12
|
+
$ cmake --preset=dev
|
|
13
|
+
$ cmake --build build-dev/
|
|
14
|
+
$ cd ../..
|
|
15
|
+
$ tsc
|
|
16
|
+
$ node out/example.js test/qt_test/build-dev
|
|
17
|
+
```
|
package/a
ADDED
package/foo
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
TAP version 13
|
|
2
|
+
# MyTest
|
|
3
|
+
ok 1 - initTestCase()
|
|
4
|
+
not ok 2 - testF()
|
|
5
|
+
---
|
|
6
|
+
# failed
|
|
7
|
+
at: MyTest::testF() (/data/sources/vscode-test-extension/qttest-utils/test/qt_test/test2.cpp:13)
|
|
8
|
+
file: /data/sources/vscode-test-extension/qttest-utils/test/qt_test/test2.cpp
|
|
9
|
+
line: 13
|
|
10
|
+
...
|
|
11
|
+
ok 3 - cleanupTestCase()
|
|
12
|
+
1..3
|
|
13
|
+
# tests 3
|
|
14
|
+
# pass 2
|
|
15
|
+
# fail 1
|
package/out/example.js
CHANGED
|
@@ -36,10 +36,37 @@ function example() {
|
|
|
36
36
|
yield qt.removeNonLinking();
|
|
37
37
|
// Example of filtering out by regexp:
|
|
38
38
|
qt.removeMatching(/(tst_view|tst_window)/);
|
|
39
|
-
//
|
|
40
|
-
qt.maintainMatching(/(tst_docks|tst_qtwidgets|tst_multisplitter)/);
|
|
39
|
+
// Uncomment to see example of filtering out by regexp (inverted):
|
|
40
|
+
// qt.maintainMatching(/(tst_docks|tst_qtwidgets|tst_multisplitter)/);
|
|
41
41
|
qt.dumpExecutablePaths();
|
|
42
|
-
qt.dumpTestSlots();
|
|
42
|
+
yield qt.dumpTestSlots();
|
|
43
|
+
console.log("\nRunning tests...");
|
|
44
|
+
for (var executable of qt.qtTestExecutables) {
|
|
45
|
+
yield executable.runTest();
|
|
46
|
+
if (executable.lastExitCode === 0)
|
|
47
|
+
console.log(" PASS: " + executable.filename);
|
|
48
|
+
else
|
|
49
|
+
console.log(" FAIL: " + executable.filename + "; code=" + executable.lastExitCode);
|
|
50
|
+
for (let slot of executable.slots) {
|
|
51
|
+
if (slot.lastTestFailure) {
|
|
52
|
+
console.log(" failed slot=" + slot.name + "; path=" + slot.lastTestFailure.filePath + "; line=" + slot.lastTestFailure.lineNumber);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
// Also run individual slots, just for example purposes:
|
|
57
|
+
console.log("\nRunning single tests...");
|
|
58
|
+
let slot = qt.qtTestExecutables[1].slots[0];
|
|
59
|
+
yield slot.runTest();
|
|
60
|
+
if (slot.lastTestFailure)
|
|
61
|
+
console.log(" FAIL:" + JSON.stringify(slot.lastTestFailure));
|
|
62
|
+
else
|
|
63
|
+
console.log(" PASS:");
|
|
64
|
+
let slot2 = qt.qtTestExecutables[1].slots[2];
|
|
65
|
+
yield slot2.runTest();
|
|
66
|
+
if (slot2.lastTestFailure)
|
|
67
|
+
console.log(" FAIL:" + JSON.stringify(slot2.lastTestFailure));
|
|
68
|
+
else
|
|
69
|
+
console.log(" PASS");
|
|
43
70
|
});
|
|
44
71
|
}
|
|
45
72
|
example();
|
package/out/qttest.d.ts
CHANGED
|
@@ -7,6 +7,7 @@ export declare class QtTest {
|
|
|
7
7
|
readonly buildDirPath: string;
|
|
8
8
|
vscodeTestItem: any | undefined;
|
|
9
9
|
slots: QtTestSlot[] | null;
|
|
10
|
+
lastExitCode: number;
|
|
10
11
|
constructor(filename: string, buildDirPath: string);
|
|
11
12
|
get id(): string;
|
|
12
13
|
get label(): string;
|
|
@@ -23,12 +24,17 @@ export declare class QtTest {
|
|
|
23
24
|
*/
|
|
24
25
|
linksToQtTestLib(): Promise<boolean> | undefined;
|
|
25
26
|
isQtTestViaHelp(): Promise<boolean | undefined>;
|
|
26
|
-
|
|
27
|
+
slotByName(name: string): QtTestSlot | undefined;
|
|
28
|
+
runTest(slot?: QtTestSlot, cwd?: string): Promise<boolean>;
|
|
29
|
+
tapOutputFileName(slot?: QtTestSlot): string;
|
|
30
|
+
txtOutputFileName(slot?: QtTestSlot): string;
|
|
27
31
|
command(): {
|
|
28
32
|
label: string;
|
|
29
33
|
executablePath: string;
|
|
30
34
|
args: string[];
|
|
31
35
|
};
|
|
36
|
+
clearSubTestStates(): void;
|
|
37
|
+
updateSubTestStates(cwdDir: string, slot?: QtTestSlot): Promise<void>;
|
|
32
38
|
}
|
|
33
39
|
/**
|
|
34
40
|
* Represents a single Qt test slot
|
|
@@ -37,6 +43,7 @@ export declare class QtTestSlot {
|
|
|
37
43
|
name: string;
|
|
38
44
|
parentQTest: QtTest;
|
|
39
45
|
vscodeTestItem: any | undefined;
|
|
46
|
+
lastTestFailure: TestFailure | undefined;
|
|
40
47
|
constructor(name: string, parent: QtTest);
|
|
41
48
|
get id(): string;
|
|
42
49
|
get absoluteFilePath(): string;
|
|
@@ -60,3 +67,8 @@ export declare class QtTests {
|
|
|
60
67
|
dumpExecutablePaths(): void;
|
|
61
68
|
dumpTestSlots(): Promise<void>;
|
|
62
69
|
}
|
|
70
|
+
export interface TestFailure {
|
|
71
|
+
name: string;
|
|
72
|
+
filePath: string;
|
|
73
|
+
lineNumber: number;
|
|
74
|
+
}
|
package/out/qttest.js
CHANGED
|
@@ -49,7 +49,10 @@ const cmake_1 = require("./cmake");
|
|
|
49
49
|
*/
|
|
50
50
|
class QtTest {
|
|
51
51
|
constructor(filename, buildDirPath) {
|
|
52
|
+
/// The list of individual runnable test slots
|
|
52
53
|
this.slots = null;
|
|
54
|
+
/// Set after running
|
|
55
|
+
this.lastExitCode = 0;
|
|
53
56
|
this.filename = filename;
|
|
54
57
|
this.buildDirPath = buildDirPath;
|
|
55
58
|
}
|
|
@@ -159,34 +162,110 @@ class QtTest {
|
|
|
159
162
|
});
|
|
160
163
|
});
|
|
161
164
|
}
|
|
165
|
+
slotByName(name) {
|
|
166
|
+
if (!this.slots)
|
|
167
|
+
return undefined;
|
|
168
|
+
for (let slot of this.slots) {
|
|
169
|
+
if (slot.name == name)
|
|
170
|
+
return slot;
|
|
171
|
+
}
|
|
172
|
+
return undefined;
|
|
173
|
+
}
|
|
162
174
|
/// Runs this test
|
|
163
|
-
runTest(
|
|
175
|
+
runTest(slot, cwd = "") {
|
|
164
176
|
return __awaiter(this, void 0, void 0, function* () {
|
|
165
177
|
let args = [];
|
|
166
|
-
if (
|
|
178
|
+
if (slot) {
|
|
167
179
|
// Runs a single Qt test instead
|
|
168
|
-
args = args.concat(
|
|
180
|
+
args = args.concat(slot.name);
|
|
169
181
|
}
|
|
182
|
+
else {
|
|
183
|
+
this.clearSubTestStates();
|
|
184
|
+
}
|
|
185
|
+
// log to file
|
|
186
|
+
args = args.concat("-o").concat(this.tapOutputFileName(slot) + ",tap");
|
|
187
|
+
args = args.concat("-o").concat(this.txtOutputFileName(slot) + ",txt");
|
|
170
188
|
return yield new Promise((resolve, reject) => {
|
|
171
|
-
let
|
|
172
|
-
const child = (0, child_process_1.spawn)(this.filename, args,
|
|
173
|
-
child.
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
189
|
+
let cwdDir = cwd.length > 0 ? cwd : this.buildDirPath;
|
|
190
|
+
const child = (0, child_process_1.spawn)(this.filename, args, { cwd: cwdDir });
|
|
191
|
+
child.on("exit", (code) => __awaiter(this, void 0, void 0, function* () {
|
|
192
|
+
/// We can code even be null ?
|
|
193
|
+
if (code == undefined)
|
|
194
|
+
code = -1;
|
|
195
|
+
if (!slot) {
|
|
196
|
+
this.lastExitCode = code;
|
|
197
|
+
}
|
|
198
|
+
/// When running a QtTest executable, let's check which sub-tests failed
|
|
199
|
+
/// (So VSCode can show some error icon for each fail)
|
|
200
|
+
yield this.updateSubTestStates(cwdDir, slot);
|
|
177
201
|
if (code === 0) {
|
|
178
202
|
resolve(true);
|
|
179
203
|
}
|
|
180
204
|
else {
|
|
181
205
|
resolve(false);
|
|
182
206
|
}
|
|
183
|
-
});
|
|
207
|
+
}));
|
|
184
208
|
});
|
|
185
209
|
});
|
|
186
210
|
}
|
|
211
|
+
/// Using .tap so we don't have to use a separate XML library
|
|
212
|
+
/// .tap is plain text and a single regexp can catch the failing tests and line number
|
|
213
|
+
tapOutputFileName(slot) {
|
|
214
|
+
let slotName = slot ? ("_" + slot.name) : "";
|
|
215
|
+
return this.label + slotName + ".tap";
|
|
216
|
+
}
|
|
217
|
+
txtOutputFileName(slot) {
|
|
218
|
+
let slotName = slot ? ("_" + slot.name) : "";
|
|
219
|
+
return this.label + slotName + ".txt";
|
|
220
|
+
}
|
|
187
221
|
command() {
|
|
188
222
|
return { label: this.label, executablePath: this.filename, args: [] };
|
|
189
223
|
}
|
|
224
|
+
clearSubTestStates() {
|
|
225
|
+
if (this.slots) {
|
|
226
|
+
for (let slot of this.slots) {
|
|
227
|
+
slot.lastTestFailure = undefined;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
updateSubTestStates(cwdDir, slot) {
|
|
232
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
233
|
+
let tapFileName = cwdDir + "/" + this.tapOutputFileName(slot);
|
|
234
|
+
var failures = yield new Promise((resolve, reject) => {
|
|
235
|
+
fs.readFile(tapFileName, "utf8", (error, data) => {
|
|
236
|
+
if (error) {
|
|
237
|
+
console.log("Failed to read log file");
|
|
238
|
+
reject(error);
|
|
239
|
+
}
|
|
240
|
+
else {
|
|
241
|
+
// A fail line is something like:
|
|
242
|
+
// at: MyTest::testF() (/some/path/qttest-utils/test/qt_test/test2.cpp:13)
|
|
243
|
+
const pattern = /at:\s+(.+?)::(.+?)\(\)\s+\((.+?):(\d+)\)/gm;
|
|
244
|
+
const matches = Array.from(data.matchAll(pattern));
|
|
245
|
+
const failedResults = matches.map(match => ({
|
|
246
|
+
name: match[2],
|
|
247
|
+
filePath: match[3],
|
|
248
|
+
lineNumber: parseInt(match[4]),
|
|
249
|
+
}));
|
|
250
|
+
resolve(failedResults);
|
|
251
|
+
}
|
|
252
|
+
});
|
|
253
|
+
});
|
|
254
|
+
for (let failure of failures) {
|
|
255
|
+
if (slot && slot.name != failure.name) {
|
|
256
|
+
// We executed a single slot, ignore anything else
|
|
257
|
+
continue;
|
|
258
|
+
}
|
|
259
|
+
let failedSlot = this.slotByName(failure.name);
|
|
260
|
+
if (failedSlot) {
|
|
261
|
+
failedSlot.lastTestFailure = failure;
|
|
262
|
+
}
|
|
263
|
+
else {
|
|
264
|
+
console.log("Failed to find slot with name " + failure.name);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
});
|
|
268
|
+
}
|
|
190
269
|
}
|
|
191
270
|
exports.QtTest = QtTest;
|
|
192
271
|
/**
|
|
@@ -205,7 +284,7 @@ class QtTestSlot {
|
|
|
205
284
|
}
|
|
206
285
|
runTest() {
|
|
207
286
|
return __awaiter(this, void 0, void 0, function* () {
|
|
208
|
-
return this.parentQTest.runTest(this
|
|
287
|
+
return this.parentQTest.runTest(this);
|
|
209
288
|
});
|
|
210
289
|
}
|
|
211
290
|
command() {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@iamsergio/qttest-utils",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.6",
|
|
4
4
|
"description": "API for listing QtTest executables from a build directory and which individual test slots each executable contains. Useful for a Text Explorer VSCode extension.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
package/src/example.ts
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
import { CMakeTests, CMakeTest } from "./cmake";
|
|
6
6
|
import { QtTest, QtTests } from "./qttest";
|
|
7
7
|
import fs from 'fs';
|
|
8
|
+
import { exec } from "child_process";
|
|
8
9
|
|
|
9
10
|
async function example() {
|
|
10
11
|
const args = process.argv.slice(2)
|
|
@@ -31,11 +32,43 @@ async function example() {
|
|
|
31
32
|
// Example of filtering out by regexp:
|
|
32
33
|
qt.removeMatching(/(tst_view|tst_window)/);
|
|
33
34
|
|
|
34
|
-
//
|
|
35
|
-
qt.maintainMatching(/(tst_docks|tst_qtwidgets|tst_multisplitter)/);
|
|
35
|
+
// Uncomment to see example of filtering out by regexp (inverted):
|
|
36
|
+
// qt.maintainMatching(/(tst_docks|tst_qtwidgets|tst_multisplitter)/);
|
|
36
37
|
|
|
37
38
|
qt.dumpExecutablePaths();
|
|
38
|
-
qt.dumpTestSlots();
|
|
39
|
+
await qt.dumpTestSlots();
|
|
40
|
+
|
|
41
|
+
console.log("\nRunning tests...");
|
|
42
|
+
for (var executable of qt.qtTestExecutables) {
|
|
43
|
+
await executable.runTest();
|
|
44
|
+
if (executable.lastExitCode === 0)
|
|
45
|
+
console.log(" PASS: " + executable.filename);
|
|
46
|
+
else
|
|
47
|
+
console.log(" FAIL: " + executable.filename + "; code=" + executable.lastExitCode);
|
|
48
|
+
for (let slot of executable.slots!) {
|
|
49
|
+
if (slot.lastTestFailure) {
|
|
50
|
+
console.log(" failed slot=" + slot.name + "; path=" + slot.lastTestFailure.filePath + "; line=" + slot.lastTestFailure.lineNumber);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Also run individual slots, just for example purposes:
|
|
56
|
+
|
|
57
|
+
console.log("\nRunning single tests...");
|
|
58
|
+
let slot = qt.qtTestExecutables[1].slots![0];
|
|
59
|
+
await slot.runTest();
|
|
60
|
+
if (slot.lastTestFailure)
|
|
61
|
+
console.log(" FAIL:" + JSON.stringify(slot.lastTestFailure));
|
|
62
|
+
else
|
|
63
|
+
console.log(" PASS:");
|
|
64
|
+
|
|
65
|
+
let slot2 = qt.qtTestExecutables[1].slots![2];
|
|
66
|
+
await slot2.runTest();
|
|
67
|
+
if (slot2.lastTestFailure)
|
|
68
|
+
console.log(" FAIL:" + JSON.stringify(slot2.lastTestFailure));
|
|
69
|
+
else
|
|
70
|
+
console.log(" PASS");
|
|
71
|
+
|
|
39
72
|
}
|
|
40
73
|
|
|
41
74
|
example();
|
package/src/qttest.ts
CHANGED
|
@@ -18,8 +18,12 @@ export class QtTest {
|
|
|
18
18
|
/// Allows vscode extensions to associate with a test item
|
|
19
19
|
vscodeTestItem: any | undefined;
|
|
20
20
|
|
|
21
|
+
/// The list of individual runnable test slots
|
|
21
22
|
slots: QtTestSlot[] | null = null;
|
|
22
23
|
|
|
24
|
+
/// Set after running
|
|
25
|
+
lastExitCode: number = 0;
|
|
26
|
+
|
|
23
27
|
constructor(filename: string, buildDirPath: string) {
|
|
24
28
|
this.filename = filename;
|
|
25
29
|
this.buildDirPath = buildDirPath;
|
|
@@ -138,22 +142,49 @@ export class QtTest {
|
|
|
138
142
|
});
|
|
139
143
|
}
|
|
140
144
|
|
|
145
|
+
public slotByName(name: string): QtTestSlot | undefined {
|
|
146
|
+
if (!this.slots)
|
|
147
|
+
return undefined;
|
|
148
|
+
|
|
149
|
+
for (let slot of this.slots) {
|
|
150
|
+
if (slot.name == name)
|
|
151
|
+
return slot;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
return undefined;
|
|
155
|
+
}
|
|
156
|
+
|
|
141
157
|
/// Runs this test
|
|
142
|
-
public async runTest(
|
|
158
|
+
public async runTest(slot?: QtTestSlot, cwd: string = ""): Promise<boolean> {
|
|
143
159
|
let args: string[] = [];
|
|
144
|
-
if (
|
|
160
|
+
if (slot) {
|
|
145
161
|
// Runs a single Qt test instead
|
|
146
|
-
args = args.concat(
|
|
162
|
+
args = args.concat(slot.name);
|
|
163
|
+
} else {
|
|
164
|
+
this.clearSubTestStates();
|
|
147
165
|
}
|
|
148
166
|
|
|
167
|
+
// log to file
|
|
168
|
+
args = args.concat("-o").concat(this.tapOutputFileName(slot) + ",tap");
|
|
169
|
+
args = args.concat("-o").concat(this.txtOutputFileName(slot) + ",txt");
|
|
170
|
+
|
|
149
171
|
return await new Promise((resolve, reject) => {
|
|
150
|
-
let
|
|
151
|
-
const child = spawn(this.filename, args,
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
172
|
+
let cwdDir = cwd.length > 0 ? cwd : this.buildDirPath;
|
|
173
|
+
const child = spawn(this.filename, args, { cwd: cwdDir });
|
|
174
|
+
|
|
175
|
+
child.on("exit", async (code) => {
|
|
176
|
+
|
|
177
|
+
/// We can code even be null ?
|
|
178
|
+
if (code == undefined) code = -1;
|
|
179
|
+
|
|
180
|
+
if (!slot) {
|
|
181
|
+
this.lastExitCode = code;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/// When running a QtTest executable, let's check which sub-tests failed
|
|
185
|
+
/// (So VSCode can show some error icon for each fail)
|
|
186
|
+
await this.updateSubTestStates(cwdDir, slot);
|
|
155
187
|
|
|
156
|
-
child.on("exit", (code) => {
|
|
157
188
|
if (code === 0) {
|
|
158
189
|
resolve(true);
|
|
159
190
|
} else {
|
|
@@ -163,9 +194,71 @@ export class QtTest {
|
|
|
163
194
|
});
|
|
164
195
|
}
|
|
165
196
|
|
|
197
|
+
/// Using .tap so we don't have to use a separate XML library
|
|
198
|
+
/// .tap is plain text and a single regexp can catch the failing tests and line number
|
|
199
|
+
public tapOutputFileName(slot?: QtTestSlot): string {
|
|
200
|
+
let slotName = slot ? ("_" + slot.name) : "";
|
|
201
|
+
return this.label + slotName + ".tap";
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
public txtOutputFileName(slot?: QtTestSlot): string {
|
|
205
|
+
let slotName = slot ? ("_" + slot.name) : "";
|
|
206
|
+
return this.label + slotName + ".txt";
|
|
207
|
+
}
|
|
208
|
+
|
|
166
209
|
public command(): { label: string, executablePath: string, args: string[] } {
|
|
167
210
|
return { label: this.label, executablePath: this.filename, args: [] };
|
|
168
211
|
}
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
public clearSubTestStates() {
|
|
215
|
+
if (this.slots) {
|
|
216
|
+
for (let slot of this.slots) {
|
|
217
|
+
slot.lastTestFailure = undefined;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
public async updateSubTestStates(cwdDir: string, slot?: QtTestSlot) {
|
|
223
|
+
|
|
224
|
+
let tapFileName: string = cwdDir + "/" + this.tapOutputFileName(slot);
|
|
225
|
+
|
|
226
|
+
var failures = await new Promise<TestFailure[]>((resolve, reject) => {
|
|
227
|
+
fs.readFile(tapFileName, "utf8", (error, data) => {
|
|
228
|
+
if (error) {
|
|
229
|
+
console.log("Failed to read log file");
|
|
230
|
+
reject(error);
|
|
231
|
+
} else {
|
|
232
|
+
// A fail line is something like:
|
|
233
|
+
// at: MyTest::testF() (/some/path/qttest-utils/test/qt_test/test2.cpp:13)
|
|
234
|
+
|
|
235
|
+
const pattern = /at:\s+(.+?)::(.+?)\(\)\s+\((.+?):(\d+)\)/gm;
|
|
236
|
+
const matches = Array.from(data.matchAll(pattern));
|
|
237
|
+
const failedResults = matches.map(match => ({
|
|
238
|
+
name: match[2],
|
|
239
|
+
filePath: match[3],
|
|
240
|
+
lineNumber: parseInt(match[4]),
|
|
241
|
+
}));
|
|
242
|
+
|
|
243
|
+
resolve(failedResults);
|
|
244
|
+
}
|
|
245
|
+
});
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
for (let failure of failures) {
|
|
249
|
+
if (slot && slot.name != failure.name) {
|
|
250
|
+
// We executed a single slot, ignore anything else
|
|
251
|
+
continue;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
let failedSlot = this.slotByName(failure.name);
|
|
255
|
+
if (failedSlot) {
|
|
256
|
+
failedSlot.lastTestFailure = failure;
|
|
257
|
+
} else {
|
|
258
|
+
console.log("Failed to find slot with name " + failure.name);
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
}
|
|
169
262
|
}
|
|
170
263
|
|
|
171
264
|
/**
|
|
@@ -180,6 +273,9 @@ export class QtTestSlot {
|
|
|
180
273
|
/// Allows vscode extensions to associate with a test item
|
|
181
274
|
vscodeTestItem: any | undefined;
|
|
182
275
|
|
|
276
|
+
/// Set after running
|
|
277
|
+
lastTestFailure: TestFailure | undefined;
|
|
278
|
+
|
|
183
279
|
constructor(name: string, parent: QtTest) {
|
|
184
280
|
this.name = name;
|
|
185
281
|
this.parentQTest = parent;
|
|
@@ -194,7 +290,7 @@ export class QtTestSlot {
|
|
|
194
290
|
}
|
|
195
291
|
|
|
196
292
|
public async runTest(): Promise<boolean> {
|
|
197
|
-
return this.parentQTest.runTest(this
|
|
293
|
+
return this.parentQTest.runTest(this);
|
|
198
294
|
}
|
|
199
295
|
|
|
200
296
|
public command(): { label: string, executablePath: string, args: string[] } {
|
|
@@ -273,3 +369,10 @@ export class QtTests {
|
|
|
273
369
|
}
|
|
274
370
|
}
|
|
275
371
|
}
|
|
372
|
+
|
|
373
|
+
/// Represents a failure location
|
|
374
|
+
export interface TestFailure {
|
|
375
|
+
name: string;
|
|
376
|
+
filePath: string;
|
|
377
|
+
lineNumber: number;
|
|
378
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: 2023 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
|
|
2
|
+
# Author: Sergio Martins <sergio.martins@kdab.com>
|
|
3
|
+
# SPDX-License-Identifier: MIT
|
|
4
|
+
|
|
5
|
+
cmake_minimum_required(VERSION 3.12)
|
|
6
|
+
project(qttest)
|
|
7
|
+
|
|
8
|
+
find_package(Qt5Test 5.15 REQUIRED)
|
|
9
|
+
set(CMAKE_AUTOMOC ON)
|
|
10
|
+
|
|
11
|
+
add_executable(test1 test1.cpp)
|
|
12
|
+
add_executable(test2 test2.cpp)
|
|
13
|
+
add_executable(test3 test3.cpp)
|
|
14
|
+
|
|
15
|
+
target_link_libraries(test1 Qt5::Test)
|
|
16
|
+
target_link_libraries(test2 Qt5::Test)
|
|
17
|
+
target_link_libraries(test3 Qt5::Test)
|
|
18
|
+
|
|
19
|
+
enable_testing()
|
|
20
|
+
add_test(NAME test1 COMMAND test1)
|
|
21
|
+
add_test(NAME test2 COMMAND test2)
|
|
22
|
+
add_test(NAME test3 COMMAND test3)
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 2,
|
|
3
|
+
"configurePresets": [
|
|
4
|
+
{
|
|
5
|
+
"name": "dev",
|
|
6
|
+
"displayName": "dev",
|
|
7
|
+
"generator": "Ninja",
|
|
8
|
+
"binaryDir": "${sourceDir}/build-dev",
|
|
9
|
+
"cacheVariables": {
|
|
10
|
+
"CMAKE_BUILD_TYPE": "Debug",
|
|
11
|
+
"CMAKE_EXPORT_COMPILE_COMMANDS": "ON"
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
]
|
|
15
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// SPDX-FileCopyrightText: 2023 Klarälvdalens Datakonsult AB, a KDAB Group
|
|
2
|
+
// company <info@kdab.com> Author: Sergio Martins <sergio.martins@kdab.com>
|
|
3
|
+
// SPDX-License-Identifier: MIT
|
|
4
|
+
|
|
5
|
+
#include <QObject>
|
|
6
|
+
#include <QtTest>
|
|
7
|
+
|
|
8
|
+
class MyTest : public QObject {
|
|
9
|
+
Q_OBJECT
|
|
10
|
+
private Q_SLOTS:
|
|
11
|
+
void testA() {}
|
|
12
|
+
void testB() {}
|
|
13
|
+
void testC() {}
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
QTEST_MAIN(MyTest);
|
|
17
|
+
|
|
18
|
+
#include <test1.moc>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// SPDX-FileCopyrightText: 2023 Klarälvdalens Datakonsult AB, a KDAB Group
|
|
2
|
+
// company <info@kdab.com> Author: Sergio Martins <sergio.martins@kdab.com>
|
|
3
|
+
// SPDX-License-Identifier: MIT
|
|
4
|
+
|
|
5
|
+
#include <QObject>
|
|
6
|
+
#include <QtTest>
|
|
7
|
+
|
|
8
|
+
class MyTest : public QObject {
|
|
9
|
+
Q_OBJECT
|
|
10
|
+
private Q_SLOTS:
|
|
11
|
+
void testD() {}
|
|
12
|
+
void testE() {}
|
|
13
|
+
void testF() { QFAIL("failed"); }
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
QTEST_MAIN(MyTest);
|
|
17
|
+
|
|
18
|
+
#include <test2.moc>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// SPDX-FileCopyrightText: 2023 Klarälvdalens Datakonsult AB, a KDAB Group
|
|
2
|
+
// company <info@kdab.com> Author: Sergio Martins <sergio.martins@kdab.com>
|
|
3
|
+
// SPDX-License-Identifier: MIT
|
|
4
|
+
|
|
5
|
+
#include <QObject>
|
|
6
|
+
#include <QtTest>
|
|
7
|
+
|
|
8
|
+
class MyTest : public QObject {
|
|
9
|
+
Q_OBJECT
|
|
10
|
+
private Q_SLOTS:
|
|
11
|
+
void testG() {}
|
|
12
|
+
void testH() {}
|
|
13
|
+
void testI() {}
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
QTEST_MAIN(MyTest);
|
|
17
|
+
|
|
18
|
+
#include <test3.moc>
|
package/test1.log
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<TestCase name="MyTest">
|
|
3
|
+
<Environment>
|
|
4
|
+
<QtVersion>5.15.2</QtVersion>
|
|
5
|
+
<QtBuild>Qt 5.15.2 (x86_64-little_endian-lp64 shared (dynamic) release build; by GCC 5.3.1 20160406 (Red Hat 5.3.1-6))</QtBuild>
|
|
6
|
+
<QTestVersion>5.15.2</QTestVersion>
|
|
7
|
+
</Environment>
|
|
8
|
+
<TestFunction name="initTestCase">
|
|
9
|
+
<Incident type="pass" file="" line="0" />
|
|
10
|
+
<Duration msecs="0.312962"/>
|
|
11
|
+
</TestFunction>
|
|
12
|
+
<TestFunction name="testD">
|
|
13
|
+
<Incident type="pass" file="" line="0" />
|
|
14
|
+
<Duration msecs="0.010127"/>
|
|
15
|
+
</TestFunction>
|
|
16
|
+
<TestFunction name="testE">
|
|
17
|
+
<Incident type="pass" file="" line="0" />
|
|
18
|
+
<Duration msecs="0.005239"/>
|
|
19
|
+
</TestFunction>
|
|
20
|
+
<TestFunction name="testF">
|
|
21
|
+
<Incident type="fail" file="/data/sources/vscode-test-extension/qttest-utils/test/qt_test/test2.cpp" line="13">
|
|
22
|
+
<Description><![CDATA[failed]]></Description>
|
|
23
|
+
</Incident>
|
|
24
|
+
<Duration msecs="0.018438"/>
|
|
25
|
+
</TestFunction>
|
|
26
|
+
<TestFunction name="cleanupTestCase">
|
|
27
|
+
<Incident type="pass" file="" line="0" />
|
|
28
|
+
<Duration msecs="0.00426"/>
|
|
29
|
+
</TestFunction>
|
|
30
|
+
<Duration msecs="0.432951"/>
|
|
31
|
+
</TestCase>
|
package/test1.log1
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
TAP version 13
|
|
2
|
+
# MyTest
|
|
3
|
+
ok 1 - initTestCase()
|
|
4
|
+
ok 2 - testD()
|
|
5
|
+
ok 3 - testE()
|
|
6
|
+
not ok 4 - testF()
|
|
7
|
+
---
|
|
8
|
+
# failed
|
|
9
|
+
at: MyTest::testF() (/data/sources/vscode-test-extension/qttest-utils/test/qt_test/test2.cpp:13)
|
|
10
|
+
file: /data/sources/vscode-test-extension/qttest-utils/test/qt_test/test2.cpp
|
|
11
|
+
line: 13
|
|
12
|
+
...
|
|
13
|
+
ok 5 - cleanupTestCase()
|
|
14
|
+
1..5
|
|
15
|
+
# tests 5
|
|
16
|
+
# pass 4
|
|
17
|
+
# fail 1
|