@iamsergio/qttest-utils 0.4.7 → 0.4.8
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/package.json +1 -1
- package/a +0 -8
- package/code.code-workspace +0 -11
- package/foo +0 -15
- package/src/cmake.ts +0 -87
- package/src/example.ts +0 -78
- package/src/index.ts +0 -12
- package/src/qttest.ts +0 -393
- package/src/utils.ts +0 -59
- package/test/qt_test/CMakeLists.txt +0 -22
- package/test/qt_test/CMakePresets.json +0 -15
- package/test/qt_test/test1.cpp +0 -18
- package/test/qt_test/test2.cpp +0 -18
- package/test/qt_test/test3.cpp +0 -18
- package/test1.log +0 -31
- package/test1.log1 +0 -17
- package/tsconfig.json +0 -18
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@iamsergio/qttest-utils",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.8",
|
|
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/a
DELETED
package/code.code-workspace
DELETED
package/foo
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
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/src/cmake.ts
DELETED
|
@@ -1,87 +0,0 @@
|
|
|
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
|
-
import { spawn } from "child_process";
|
|
6
|
-
import path from "path";
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Represents tests added in cmake (Via add_test())
|
|
10
|
-
*
|
|
11
|
-
* Contains methods to discover Qt Tests via CMake
|
|
12
|
-
*/
|
|
13
|
-
export class CMakeTests {
|
|
14
|
-
// The build dir where we'll run
|
|
15
|
-
readonly buildDirPath: string;
|
|
16
|
-
|
|
17
|
-
constructor(buildDirPath: string) {
|
|
18
|
-
this.buildDirPath = buildDirPath;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* Invokes ctest.exe --show-only=json-v1
|
|
23
|
-
*
|
|
24
|
-
* @returns a promise with the list of tests
|
|
25
|
-
*/
|
|
26
|
-
public async tests(): Promise<CMakeTest[] | undefined> {
|
|
27
|
-
|
|
28
|
-
// TODO: Check if folder exists
|
|
29
|
-
if (this.buildDirPath.length == 0) {
|
|
30
|
-
console.error("Could not find out cmake build dir");
|
|
31
|
-
return undefined;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
return new Promise((resolve, reject) => {
|
|
35
|
-
const child = spawn("ctest", ["--show-only=json-v1"], { "cwd": this.buildDirPath });
|
|
36
|
-
let output = "";
|
|
37
|
-
child.stdout.on("data", (chunk) => {
|
|
38
|
-
output += chunk.toString();
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
child.on("exit", (code) => {
|
|
42
|
-
if (code === 0) {
|
|
43
|
-
resolve(this.ctestJsonToList(output));
|
|
44
|
-
} else {
|
|
45
|
-
reject(new Error("Failed to run ctest"));
|
|
46
|
-
}
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
return undefined;
|
|
50
|
-
});
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
private ctestJsonToList(json: string): CMakeTest[] {
|
|
54
|
-
|
|
55
|
-
let allJSON = JSON.parse(json);
|
|
56
|
-
|
|
57
|
-
if (!("tests" in allJSON)) { return []; }
|
|
58
|
-
|
|
59
|
-
let tests: CMakeTest[] = allJSON.tests.map((testJSON: any) => {
|
|
60
|
-
let test = new CMakeTest();
|
|
61
|
-
test.command = testJSON.command;
|
|
62
|
-
test.cwd = testJSON.cwd;
|
|
63
|
-
return test;
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
return tests;
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
/// Represents an inividual CTest test
|
|
72
|
-
export class CMakeTest {
|
|
73
|
-
public command: string[] = [];
|
|
74
|
-
public cwd: string = "";
|
|
75
|
-
|
|
76
|
-
public id(): string {
|
|
77
|
-
return this.command.join(",");
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
public label(): string {
|
|
81
|
-
return path.basename(this.executablePath());
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
public executablePath(): string {
|
|
85
|
-
return this.command[0];
|
|
86
|
-
}
|
|
87
|
-
}
|
package/src/example.ts
DELETED
|
@@ -1,78 +0,0 @@
|
|
|
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
|
-
import { CMakeTests, CMakeTest } from "./cmake";
|
|
6
|
-
import { QtTest, QtTests } from "./qttest";
|
|
7
|
-
import fs from 'fs';
|
|
8
|
-
import { exec } from "child_process";
|
|
9
|
-
|
|
10
|
-
async function example() {
|
|
11
|
-
const args = process.argv.slice(2)
|
|
12
|
-
if (args.length != 1) {
|
|
13
|
-
console.error("ERROR: Expected a single argument with the build-dir with cmake tests!");
|
|
14
|
-
process.exit(2);
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
let buildDirPath = args[0];
|
|
18
|
-
|
|
19
|
-
if (!fs.existsSync(buildDirPath)) {
|
|
20
|
-
console.error('Directory does not exist!');
|
|
21
|
-
process.exit(1);
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
let qt = new QtTests();
|
|
25
|
-
|
|
26
|
-
qt.setLogFunction((message: string) => {
|
|
27
|
-
console.log(message);
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
// Gather all tests that would be executed by CTest:
|
|
31
|
-
await qt.discoverViaCMake(buildDirPath);
|
|
32
|
-
|
|
33
|
-
// Filter-out the ones that don't link to QtTest (doctests and such)
|
|
34
|
-
await qt.removeNonLinking();
|
|
35
|
-
|
|
36
|
-
// Example of filtering out by regexp:
|
|
37
|
-
qt.removeMatching(/(tst_view|tst_window)/);
|
|
38
|
-
|
|
39
|
-
// Uncomment to see example of filtering out by regexp (inverted):
|
|
40
|
-
// qt.maintainMatching(/(tst_docks|tst_qtwidgets|tst_multisplitter)/);
|
|
41
|
-
|
|
42
|
-
qt.dumpExecutablePaths();
|
|
43
|
-
await qt.dumpTestSlots();
|
|
44
|
-
|
|
45
|
-
console.log("\nRunning tests...");
|
|
46
|
-
for (var executable of qt.qtTestExecutables) {
|
|
47
|
-
await executable.runTest();
|
|
48
|
-
if (executable.lastExitCode === 0)
|
|
49
|
-
console.log(" PASS: " + executable.filename);
|
|
50
|
-
else
|
|
51
|
-
console.log(" FAIL: " + executable.filename + "; code=" + executable.lastExitCode);
|
|
52
|
-
for (let slot of executable.slots!) {
|
|
53
|
-
if (slot.lastTestFailure) {
|
|
54
|
-
console.log(" failed slot=" + slot.name + "; path=" + slot.lastTestFailure.filePath + "; line=" + slot.lastTestFailure.lineNumber);
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
// Also run individual slots, just for example purposes:
|
|
60
|
-
|
|
61
|
-
console.log("\nRunning single tests...");
|
|
62
|
-
let slot = qt.qtTestExecutables[1].slots![0];
|
|
63
|
-
await slot.runTest();
|
|
64
|
-
if (slot.lastTestFailure)
|
|
65
|
-
console.log(" FAIL:" + JSON.stringify(slot.lastTestFailure));
|
|
66
|
-
else
|
|
67
|
-
console.log(" PASS:");
|
|
68
|
-
|
|
69
|
-
let slot2 = qt.qtTestExecutables[1].slots![2];
|
|
70
|
-
await slot2.runTest();
|
|
71
|
-
if (slot2.lastTestFailure)
|
|
72
|
-
console.log(" FAIL:" + JSON.stringify(slot2.lastTestFailure));
|
|
73
|
-
else
|
|
74
|
-
console.log(" PASS");
|
|
75
|
-
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
example();
|
package/src/index.ts
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
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
|
-
import { CMakeTests, CMakeTest } from "./cmake";
|
|
6
|
-
import { QtTests, QtTest, QtTestSlot } from "./qttest";
|
|
7
|
-
|
|
8
|
-
const qttest = {
|
|
9
|
-
QtTests, QtTest, QtTestSlot, CMakeTests, CMakeTest
|
|
10
|
-
};
|
|
11
|
-
|
|
12
|
-
export default qttest;
|
package/src/qttest.ts
DELETED
|
@@ -1,393 +0,0 @@
|
|
|
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
|
-
import { spawn } from "child_process";
|
|
6
|
-
import path from "path";
|
|
7
|
-
import * as fs from 'fs';
|
|
8
|
-
import { CMakeTests } from "./cmake";
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
type LoggerFunction = (arg: string) => void;
|
|
12
|
-
var gLogFunction: LoggerFunction | undefined;
|
|
13
|
-
|
|
14
|
-
function logMessage(message: string) {
|
|
15
|
-
if (gLogFunction) {
|
|
16
|
-
gLogFunction(message);
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Represents a single QtTest executable.
|
|
22
|
-
* Supports listing the individual test slots
|
|
23
|
-
*/
|
|
24
|
-
export class QtTest {
|
|
25
|
-
readonly filename: string;
|
|
26
|
-
readonly buildDirPath: string;
|
|
27
|
-
|
|
28
|
-
/// Allows vscode extensions to associate with a test item
|
|
29
|
-
vscodeTestItem: any | undefined;
|
|
30
|
-
|
|
31
|
-
/// The list of individual runnable test slots
|
|
32
|
-
slots: QtTestSlot[] | null = null;
|
|
33
|
-
|
|
34
|
-
/// Set after running
|
|
35
|
-
lastExitCode: number = 0;
|
|
36
|
-
|
|
37
|
-
constructor(filename: string, buildDirPath: string) {
|
|
38
|
-
this.filename = filename;
|
|
39
|
-
this.buildDirPath = buildDirPath;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
public get id() {
|
|
43
|
-
return this.filename;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
public get label() {
|
|
47
|
-
return path.basename(this.filename);
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* Calls "./yourqttest -functions" and stores the results in the slots property.
|
|
52
|
-
*/
|
|
53
|
-
public async parseAvailableSlots(): Promise<void> {
|
|
54
|
-
let slotNames: string[] = [];
|
|
55
|
-
let output = "";
|
|
56
|
-
let err = "";
|
|
57
|
-
|
|
58
|
-
await new Promise((resolve, reject) => {
|
|
59
|
-
if (!fs.existsSync(this.filename)) {
|
|
60
|
-
reject(new Error("File doesn't exit: " + this.filename));
|
|
61
|
-
return;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
const child = spawn(this.filename, ["-functions"], { cwd: this.buildDirPath });
|
|
65
|
-
|
|
66
|
-
child.stdout.on("data", (chunk) => {
|
|
67
|
-
output += chunk.toString();
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
child.stderr.on("data", (chunk) => {
|
|
71
|
-
err += chunk.toString();
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
child.on("exit", (code) => {
|
|
75
|
-
if (code === 0) {
|
|
76
|
-
slotNames = slotNames.concat(output.split("\n"));
|
|
77
|
-
slotNames = slotNames.map(entry => entry.trim().replace("()", ""));
|
|
78
|
-
slotNames = slotNames.filter(entry => entry.length > 0);
|
|
79
|
-
|
|
80
|
-
if (slotNames.length > 0) {
|
|
81
|
-
this.slots = [];
|
|
82
|
-
for (var slotName of slotNames) {
|
|
83
|
-
var slot = new QtTestSlot(slotName, this);
|
|
84
|
-
this.slots.push(slot);
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
resolve(slotNames);
|
|
89
|
-
} else {
|
|
90
|
-
reject(new Error("Failed to run -functions, stdout=" + output + "; stderr=" + err + "; code=" + code));
|
|
91
|
-
}
|
|
92
|
-
});
|
|
93
|
-
});
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
/**
|
|
97
|
-
* Returns whether this executable links to libQtTest.so.
|
|
98
|
-
*
|
|
99
|
-
* Useful for Qt autodetection, as some tests are doctest or so.
|
|
100
|
-
*
|
|
101
|
-
* Only implemented for Linux. Returns undefined on other platforms.
|
|
102
|
-
*/
|
|
103
|
-
public linksToQtTestLib(): Promise<boolean> | undefined {
|
|
104
|
-
|
|
105
|
-
let isLinux = process.platform === "linux";
|
|
106
|
-
if (!isLinux) { return undefined; }
|
|
107
|
-
|
|
108
|
-
return new Promise((resolve, reject) => {
|
|
109
|
-
const child = spawn("ldd", [this.filename]);
|
|
110
|
-
let output = "";
|
|
111
|
-
let result = false;
|
|
112
|
-
child.stdout.on("data", (chunk) => {
|
|
113
|
-
if (!result) {
|
|
114
|
-
if (chunk.toString().includes("libQt5Test.so") || chunk.toString().includes("libQt6Test.so")) {
|
|
115
|
-
result = true;
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
});
|
|
119
|
-
|
|
120
|
-
child.on("exit", (code) => {
|
|
121
|
-
if (code === 0) {
|
|
122
|
-
resolve(result);
|
|
123
|
-
} else {
|
|
124
|
-
reject(new Error("Failed to run ldd"));
|
|
125
|
-
}
|
|
126
|
-
});
|
|
127
|
-
});
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
/// Returns whether this test is a QtTest by running it with -help and checking if the help text looks familiar
|
|
131
|
-
/// Note that if this is not a QtTest it might not run help and instead execute the test itself
|
|
132
|
-
public async isQtTestViaHelp(): Promise<boolean | undefined> {
|
|
133
|
-
return await new Promise((resolve, reject) => {
|
|
134
|
-
const child = spawn(this.filename, ["-help"]);
|
|
135
|
-
let output = "";
|
|
136
|
-
let result = false;
|
|
137
|
-
child.stdout.on("data", (chunk) => {
|
|
138
|
-
if (!result) {
|
|
139
|
-
if (chunk.toString().includes("[testfunction[:testdata]]")) {
|
|
140
|
-
result = true;
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
});
|
|
144
|
-
|
|
145
|
-
child.on("exit", (code) => {
|
|
146
|
-
if (code === 0) {
|
|
147
|
-
resolve(result);
|
|
148
|
-
} else {
|
|
149
|
-
resolve(false);
|
|
150
|
-
}
|
|
151
|
-
});
|
|
152
|
-
});
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
public slotByName(name: string): QtTestSlot | undefined {
|
|
156
|
-
if (!this.slots)
|
|
157
|
-
return undefined;
|
|
158
|
-
|
|
159
|
-
for (let slot of this.slots) {
|
|
160
|
-
if (slot.name == name)
|
|
161
|
-
return slot;
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
return undefined;
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
/// Runs this test
|
|
168
|
-
public async runTest(slot?: QtTestSlot, cwd: string = ""): Promise<boolean> {
|
|
169
|
-
let args: string[] = [];
|
|
170
|
-
if (slot) {
|
|
171
|
-
// Runs a single Qt test instead
|
|
172
|
-
args = args.concat(slot.name);
|
|
173
|
-
} else {
|
|
174
|
-
this.clearSubTestStates();
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
// log to file
|
|
178
|
-
args = args.concat("-o").concat(this.tapOutputFileName(slot) + ",tap");
|
|
179
|
-
args = args.concat("-o").concat(this.txtOutputFileName(slot) + ",txt");
|
|
180
|
-
|
|
181
|
-
return await new Promise((resolve, reject) => {
|
|
182
|
-
let cwdDir = cwd.length > 0 ? cwd : this.buildDirPath;
|
|
183
|
-
logMessage("Running " + this.filename + " " + args.join(" ") + " with cwd=" + cwdDir);
|
|
184
|
-
const child = spawn(this.filename, args, { cwd: cwdDir });
|
|
185
|
-
|
|
186
|
-
child.on("exit", async (code) => {
|
|
187
|
-
|
|
188
|
-
/// We can code even be null ?
|
|
189
|
-
if (code == undefined) code = -1;
|
|
190
|
-
|
|
191
|
-
if (!slot) {
|
|
192
|
-
this.lastExitCode = code;
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
/// When running a QtTest executable, let's check which sub-tests failed
|
|
196
|
-
/// (So VSCode can show some error icon for each fail)
|
|
197
|
-
await this.updateSubTestStates(cwdDir, slot);
|
|
198
|
-
|
|
199
|
-
if (code === 0) {
|
|
200
|
-
resolve(true);
|
|
201
|
-
} else {
|
|
202
|
-
resolve(false);
|
|
203
|
-
}
|
|
204
|
-
});
|
|
205
|
-
});
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
/// Using .tap so we don't have to use a separate XML library
|
|
209
|
-
/// .tap is plain text and a single regexp can catch the failing tests and line number
|
|
210
|
-
public tapOutputFileName(slot?: QtTestSlot): string {
|
|
211
|
-
let slotName = slot ? ("_" + slot.name) : "";
|
|
212
|
-
return this.label + slotName + ".tap";
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
public txtOutputFileName(slot?: QtTestSlot): string {
|
|
216
|
-
let slotName = slot ? ("_" + slot.name) : "";
|
|
217
|
-
return this.label + slotName + ".txt";
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
public command(): { label: string, executablePath: string, args: string[] } {
|
|
221
|
-
return { label: this.label, executablePath: this.filename, args: [] };
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
public clearSubTestStates() {
|
|
226
|
-
if (this.slots) {
|
|
227
|
-
for (let slot of this.slots) {
|
|
228
|
-
slot.lastTestFailure = undefined;
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
public async updateSubTestStates(cwdDir: string, slot?: QtTestSlot) {
|
|
234
|
-
|
|
235
|
-
let tapFileName: string = cwdDir + "/" + this.tapOutputFileName(slot);
|
|
236
|
-
|
|
237
|
-
var failures = await new Promise<TestFailure[]>((resolve, reject) => {
|
|
238
|
-
fs.readFile(tapFileName, "utf8", (error, data) => {
|
|
239
|
-
if (error) {
|
|
240
|
-
logMessage("ERROR: Failed to read log file");
|
|
241
|
-
reject(error);
|
|
242
|
-
} else {
|
|
243
|
-
// A fail line is something like:
|
|
244
|
-
// at: MyTest::testF() (/some/path/qttest-utils/test/qt_test/test2.cpp:13)
|
|
245
|
-
|
|
246
|
-
const pattern = /at:\s+(.+?)::(.+?)\(\)\s+\((.+?):(\d+)\)/gm;
|
|
247
|
-
const matches = Array.from(data.matchAll(pattern));
|
|
248
|
-
const failedResults = matches.map(match => ({
|
|
249
|
-
name: match[2],
|
|
250
|
-
filePath: match[3],
|
|
251
|
-
lineNumber: parseInt(match[4]),
|
|
252
|
-
}));
|
|
253
|
-
|
|
254
|
-
resolve(failedResults);
|
|
255
|
-
}
|
|
256
|
-
});
|
|
257
|
-
});
|
|
258
|
-
|
|
259
|
-
for (let failure of failures) {
|
|
260
|
-
if (slot && slot.name != failure.name) {
|
|
261
|
-
// We executed a single slot, ignore anything else
|
|
262
|
-
continue;
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
let failedSlot = this.slotByName(failure.name);
|
|
266
|
-
if (failedSlot) {
|
|
267
|
-
failedSlot.lastTestFailure = failure;
|
|
268
|
-
} else {
|
|
269
|
-
logMessage("ERROR: Failed to find slot with name " + failure.name);
|
|
270
|
-
}
|
|
271
|
-
}
|
|
272
|
-
}
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
/**
|
|
276
|
-
* Represents a single Qt test slot
|
|
277
|
-
*/
|
|
278
|
-
export class QtTestSlot {
|
|
279
|
-
name: string;
|
|
280
|
-
|
|
281
|
-
// The QTest executable this slot belongs to
|
|
282
|
-
parentQTest: QtTest;
|
|
283
|
-
|
|
284
|
-
/// Allows vscode extensions to associate with a test item
|
|
285
|
-
vscodeTestItem: any | undefined;
|
|
286
|
-
|
|
287
|
-
/// Set after running
|
|
288
|
-
lastTestFailure: TestFailure | undefined;
|
|
289
|
-
|
|
290
|
-
constructor(name: string, parent: QtTest) {
|
|
291
|
-
this.name = name;
|
|
292
|
-
this.parentQTest = parent;
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
public get id() {
|
|
296
|
-
return this.parentQTest.filename + this.name;
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
public get absoluteFilePath() {
|
|
300
|
-
return this.parentQTest.filename;
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
public async runTest(): Promise<boolean> {
|
|
304
|
-
return this.parentQTest.runTest(this);
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
public command(): { label: string, executablePath: string, args: string[] } {
|
|
308
|
-
return { label: this.name, executablePath: this.absoluteFilePath, args: [this.name] };
|
|
309
|
-
}
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
/**
|
|
313
|
-
* Represents the list of all QtTest executables in your project
|
|
314
|
-
*/
|
|
315
|
-
export class QtTests {
|
|
316
|
-
qtTestExecutables: QtTest[] = [];
|
|
317
|
-
|
|
318
|
-
async discoverViaCMake(buildDirPath: string) {
|
|
319
|
-
var cmake = new CMakeTests(buildDirPath);
|
|
320
|
-
let ctests = await cmake.tests();
|
|
321
|
-
if (ctests) {
|
|
322
|
-
for (let ctest of ctests) {
|
|
323
|
-
let qtest = new QtTest(ctest.executablePath(), buildDirPath);
|
|
324
|
-
this.qtTestExecutables.push(qtest);
|
|
325
|
-
}
|
|
326
|
-
} else {
|
|
327
|
-
logMessage("ERROR: Failed to retrieve ctests!");
|
|
328
|
-
}
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
/// Removes any executable (from the list) that doesn't link to libQtTest.so
|
|
332
|
-
/// This heuristic tries to filter-out doctest and other non-Qt tests
|
|
333
|
-
/// Only implemented for linux for now
|
|
334
|
-
public async removeNonLinking() {
|
|
335
|
-
let isLinux = process.platform === "linux";
|
|
336
|
-
if (!isLinux) { return; }
|
|
337
|
-
|
|
338
|
-
let acceptedExecutables: QtTest[] = [];
|
|
339
|
-
for (let ex of this.qtTestExecutables) {
|
|
340
|
-
let linksToQt = await ex.linksToQtTestLib();
|
|
341
|
-
// undefined or true is accepted
|
|
342
|
-
if (linksToQt !== false) {
|
|
343
|
-
acceptedExecutables.push(ex);
|
|
344
|
-
}
|
|
345
|
-
this.qtTestExecutables = acceptedExecutables;
|
|
346
|
-
}
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
public setLogFunction(func: LoggerFunction) {
|
|
350
|
-
gLogFunction = func;
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
public async removeByRunningHelp() {
|
|
354
|
-
this.qtTestExecutables = this.qtTestExecutables.filter(async (ex) => await ex.isQtTestViaHelp());
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
/// Removes any executable (from the list) that matches the specified regex
|
|
358
|
-
public removeMatching(regex: RegExp) {
|
|
359
|
-
this.qtTestExecutables = this.qtTestExecutables.filter((ex) => !regex.test(ex.filename));
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
/// Removes any executable (from the list) that doesn't match the specified regex
|
|
363
|
-
public maintainMatching(regex: RegExp) {
|
|
364
|
-
this.qtTestExecutables = this.qtTestExecutables.filter((ex) => regex.test(ex.filename));
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
public dumpExecutablePaths() {
|
|
368
|
-
for (var ex of this.qtTestExecutables) {
|
|
369
|
-
console.log(ex.filename);
|
|
370
|
-
}
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
public async dumpTestSlots() {
|
|
374
|
-
for (var ex of this.qtTestExecutables) {
|
|
375
|
-
if (!ex.slots)
|
|
376
|
-
await ex.parseAvailableSlots();
|
|
377
|
-
|
|
378
|
-
console.log(ex.filename);
|
|
379
|
-
if (ex.slots) {
|
|
380
|
-
for (let slot of ex.slots) {
|
|
381
|
-
console.log(" - " + slot.name);
|
|
382
|
-
}
|
|
383
|
-
}
|
|
384
|
-
}
|
|
385
|
-
}
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
/// Represents a failure location
|
|
389
|
-
export interface TestFailure {
|
|
390
|
-
name: string;
|
|
391
|
-
filePath: string;
|
|
392
|
-
lineNumber: number;
|
|
393
|
-
}
|
package/src/utils.ts
DELETED
|
@@ -1,59 +0,0 @@
|
|
|
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
|
-
import path from "path";
|
|
6
|
-
import * as fs from 'fs';
|
|
7
|
-
|
|
8
|
-
/// Returns whether the specified file is an executable
|
|
9
|
-
function isExecutable(filePath: string): boolean {
|
|
10
|
-
if (process.platform === "win32") {
|
|
11
|
-
return path.extname(filePath).toLocaleLowerCase() === ".exe";
|
|
12
|
-
} else {
|
|
13
|
-
try {
|
|
14
|
-
fs.accessSync(filePath, fs.constants.X_OK);
|
|
15
|
-
return true;
|
|
16
|
-
} catch (err) {
|
|
17
|
-
return false;
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
/// Returns whether the specified file is a library
|
|
23
|
-
function isLibrary(filename: string): boolean {
|
|
24
|
-
const split = filename.split(".");
|
|
25
|
-
|
|
26
|
-
if (split.length <= 1) { return false; }
|
|
27
|
-
|
|
28
|
-
// Find the first non-numeric extension, so we ignore all the trailing numbers in libFoo.so.2.0.9
|
|
29
|
-
for (var i = split.length - 1; i >= 0; --i) {
|
|
30
|
-
const extension = split[i];
|
|
31
|
-
const isNumber = !isNaN(Number(extension));
|
|
32
|
-
if (isNumber) { continue; }
|
|
33
|
-
|
|
34
|
-
return ["so", "dll", "dylib"].includes(extension);
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
return false;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/// Recursively looks for executable files in folderPath
|
|
41
|
-
function executableFiles(folderPath: string): string[] {
|
|
42
|
-
const files = fs.readdirSync(folderPath);
|
|
43
|
-
var executables: string[] = [];
|
|
44
|
-
for (var file of files) {
|
|
45
|
-
|
|
46
|
-
// Ignore CMakeFiles directory, it has some of binaries
|
|
47
|
-
if (path.basename(file) === "CMakeFiles") { continue; }
|
|
48
|
-
|
|
49
|
-
const childPath = path.join(folderPath, file);
|
|
50
|
-
const info = fs.statSync(childPath);
|
|
51
|
-
if (info.isDirectory()) {
|
|
52
|
-
executables = executables.concat(executableFiles(childPath));
|
|
53
|
-
} else if (info.isFile() && !isLibrary(path.basename(childPath)) && isExecutable(childPath)) {
|
|
54
|
-
executables.push(childPath);
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
return executables;
|
|
59
|
-
}
|
|
@@ -1,22 +0,0 @@
|
|
|
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)
|
|
@@ -1,15 +0,0 @@
|
|
|
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
|
-
}
|
package/test/qt_test/test1.cpp
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
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>
|
package/test/qt_test/test2.cpp
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
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>
|
package/test/qt_test/test3.cpp
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
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
DELETED
|
@@ -1,31 +0,0 @@
|
|
|
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
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
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
|
package/tsconfig.json
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"module": "CommonJS",
|
|
4
|
-
"esModuleInterop": true,
|
|
5
|
-
"target": "ES6",
|
|
6
|
-
"outDir": "out",
|
|
7
|
-
"sourceMap": false,
|
|
8
|
-
"strict": true,
|
|
9
|
-
"declaration": true
|
|
10
|
-
},
|
|
11
|
-
"include": [
|
|
12
|
-
"src/*.ts"
|
|
13
|
-
],
|
|
14
|
-
"exclude": [
|
|
15
|
-
"node_modules",
|
|
16
|
-
"out"
|
|
17
|
-
]
|
|
18
|
-
}
|