@iamsergio/qttest-utils 0.4.4 → 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 +15 -1
- package/out/qttest.js +90 -11
- package/package.json +1 -1
- package/src/example.ts +36 -3
- package/src/qttest.ts +120 -11
- 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
|
@@ -5,7 +5,9 @@
|
|
|
5
5
|
export declare class QtTest {
|
|
6
6
|
readonly filename: string;
|
|
7
7
|
readonly buildDirPath: string;
|
|
8
|
+
vscodeTestItem: any | undefined;
|
|
8
9
|
slots: QtTestSlot[] | null;
|
|
10
|
+
lastExitCode: number;
|
|
9
11
|
constructor(filename: string, buildDirPath: string);
|
|
10
12
|
get id(): string;
|
|
11
13
|
get label(): string;
|
|
@@ -22,12 +24,17 @@ export declare class QtTest {
|
|
|
22
24
|
*/
|
|
23
25
|
linksToQtTestLib(): Promise<boolean> | undefined;
|
|
24
26
|
isQtTestViaHelp(): Promise<boolean | undefined>;
|
|
25
|
-
|
|
27
|
+
slotByName(name: string): QtTestSlot | undefined;
|
|
28
|
+
runTest(slot?: QtTestSlot, cwd?: string): Promise<boolean>;
|
|
29
|
+
tapOutputFileName(slot?: QtTestSlot): string;
|
|
30
|
+
txtOutputFileName(slot?: QtTestSlot): string;
|
|
26
31
|
command(): {
|
|
27
32
|
label: string;
|
|
28
33
|
executablePath: string;
|
|
29
34
|
args: string[];
|
|
30
35
|
};
|
|
36
|
+
clearSubTestStates(): void;
|
|
37
|
+
updateSubTestStates(cwdDir: string, slot?: QtTestSlot): Promise<void>;
|
|
31
38
|
}
|
|
32
39
|
/**
|
|
33
40
|
* Represents a single Qt test slot
|
|
@@ -35,6 +42,8 @@ export declare class QtTest {
|
|
|
35
42
|
export declare class QtTestSlot {
|
|
36
43
|
name: string;
|
|
37
44
|
parentQTest: QtTest;
|
|
45
|
+
vscodeTestItem: any | undefined;
|
|
46
|
+
lastTestFailure: TestFailure | undefined;
|
|
38
47
|
constructor(name: string, parent: QtTest);
|
|
39
48
|
get id(): string;
|
|
40
49
|
get absoluteFilePath(): string;
|
|
@@ -58,3 +67,8 @@ export declare class QtTests {
|
|
|
58
67
|
dumpExecutablePaths(): void;
|
|
59
68
|
dumpTestSlots(): Promise<void>;
|
|
60
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
|
@@ -15,8 +15,15 @@ export class QtTest {
|
|
|
15
15
|
readonly filename: string;
|
|
16
16
|
readonly buildDirPath: string;
|
|
17
17
|
|
|
18
|
+
/// Allows vscode extensions to associate with a test item
|
|
19
|
+
vscodeTestItem: any | undefined;
|
|
20
|
+
|
|
21
|
+
/// The list of individual runnable test slots
|
|
18
22
|
slots: QtTestSlot[] | null = null;
|
|
19
23
|
|
|
24
|
+
/// Set after running
|
|
25
|
+
lastExitCode: number = 0;
|
|
26
|
+
|
|
20
27
|
constructor(filename: string, buildDirPath: string) {
|
|
21
28
|
this.filename = filename;
|
|
22
29
|
this.buildDirPath = buildDirPath;
|
|
@@ -44,7 +51,7 @@ export class QtTest {
|
|
|
44
51
|
return;
|
|
45
52
|
}
|
|
46
53
|
|
|
47
|
-
const child = spawn(this.filename, ["-functions"], {cwd: this.buildDirPath});
|
|
54
|
+
const child = spawn(this.filename, ["-functions"], { cwd: this.buildDirPath });
|
|
48
55
|
|
|
49
56
|
child.stdout.on("data", (chunk) => {
|
|
50
57
|
output += chunk.toString();
|
|
@@ -135,22 +142,49 @@ export class QtTest {
|
|
|
135
142
|
});
|
|
136
143
|
}
|
|
137
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
|
+
|
|
138
157
|
/// Runs this test
|
|
139
|
-
public async runTest(
|
|
158
|
+
public async runTest(slot?: QtTestSlot, cwd: string = ""): Promise<boolean> {
|
|
140
159
|
let args: string[] = [];
|
|
141
|
-
if (
|
|
160
|
+
if (slot) {
|
|
142
161
|
// Runs a single Qt test instead
|
|
143
|
-
args = args.concat(
|
|
162
|
+
args = args.concat(slot.name);
|
|
163
|
+
} else {
|
|
164
|
+
this.clearSubTestStates();
|
|
144
165
|
}
|
|
145
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
|
+
|
|
146
171
|
return await new Promise((resolve, reject) => {
|
|
147
|
-
let
|
|
148
|
-
const child = spawn(this.filename, args,
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
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);
|
|
152
187
|
|
|
153
|
-
child.on("exit", (code) => {
|
|
154
188
|
if (code === 0) {
|
|
155
189
|
resolve(true);
|
|
156
190
|
} else {
|
|
@@ -160,9 +194,71 @@ export class QtTest {
|
|
|
160
194
|
});
|
|
161
195
|
}
|
|
162
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
|
+
|
|
163
209
|
public command(): { label: string, executablePath: string, args: string[] } {
|
|
164
210
|
return { label: this.label, executablePath: this.filename, args: [] };
|
|
165
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
|
+
}
|
|
166
262
|
}
|
|
167
263
|
|
|
168
264
|
/**
|
|
@@ -174,6 +270,12 @@ export class QtTestSlot {
|
|
|
174
270
|
// The QTest executable this slot belongs to
|
|
175
271
|
parentQTest: QtTest;
|
|
176
272
|
|
|
273
|
+
/// Allows vscode extensions to associate with a test item
|
|
274
|
+
vscodeTestItem: any | undefined;
|
|
275
|
+
|
|
276
|
+
/// Set after running
|
|
277
|
+
lastTestFailure: TestFailure | undefined;
|
|
278
|
+
|
|
177
279
|
constructor(name: string, parent: QtTest) {
|
|
178
280
|
this.name = name;
|
|
179
281
|
this.parentQTest = parent;
|
|
@@ -188,7 +290,7 @@ export class QtTestSlot {
|
|
|
188
290
|
}
|
|
189
291
|
|
|
190
292
|
public async runTest(): Promise<boolean> {
|
|
191
|
-
return this.parentQTest.runTest(this
|
|
293
|
+
return this.parentQTest.runTest(this);
|
|
192
294
|
}
|
|
193
295
|
|
|
194
296
|
public command(): { label: string, executablePath: string, args: string[] } {
|
|
@@ -267,3 +369,10 @@ export class QtTests {
|
|
|
267
369
|
}
|
|
268
370
|
}
|
|
269
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
|